ooc-lang / rock

:ocean: self-hosted ooc compiler that generates c99
http://ooc-lang.org/
MIT License
401 stars 40 forks source link

Static variables are not maintained correctly #992

Closed thomasfanell closed 8 years ago

thomasfanell commented 8 years ago

Consider this example, where everything works as expected:

Base.ooc

Base: abstract class {
    instanceCount := static 0
    instances ::= static This instanceCount
    init: func {
        This instanceCount += 1
    }
}

Derived1.ooc

import Base
Derived1: class extends Base {
    init: func { super() }
}
//derived1 := Derived1 new()

Derived2.ooc

import Base
Derived2: class extends Base {
    init: func { super() }
 }
 //derived2 := Derived2 new()

main.ooc

import [Base, Derived1, Derived2]

d1 := Derived1 new()
d2 := Derived2 new()

main: func {
    "Instance count: %d" printfln (Base instances) // Instance count: 2
}

Now, if we instead comment out d1 and d2 in main.ooc and uncomment the creation of Derived1 and Derived2 in their respective files, we get Instance count = 1. That is, the static variable is re-initialized for every instance.

alexnask commented 8 years ago

Looking into this now.

alexnask commented 8 years ago

What happens is that the Module load functions call their respective class' load function and both Derived1 and Derived2 (obviously) call their parent's (Base) load function, which resets instanceCount to zero, since multiple executions are allowed.

Basically this means that any side effect on static member initialization will be evaluated multiple times (as many times as you have sublclasses).

Proposed fix is auto generating a static __done__ variable and using it to only evaluate a class' load function once, like we already do with modules.

alexnask commented 8 years ago

On a sidenote, string literals are constructed after class loads which leads to crashes if you try to use one in your static member initialization.

However, I don't think reversing global variable initialization and class load order is wise, since you may initialize a variable that depends on the class' static members.

I will see if there is some way to only reverse the order between (string) literals and class loads.

alexnask commented 8 years ago

@thomasfanell
Will be opening a PR for magic-lang in a bit.