Static members of classes are not initialized during compiletime unless referenced directly
This would appear not to be a problem, but the important thing to remember is that initialization of static members can use a function which can do anything. If you look at this code:
package ItemTypes
import Inventory
import ItemTypeArmor
import ItemTypeWeapon
public abstract class ItemTypes
static constant LightArmor = new ItemTypeLightArmor()
static constant MediumArmor = new ItemTypeMediumArmor()
static constant HeavyArmor = new ItemTypeHeavyArmor()
static constant PulseRifle = new ItemTypePulseRifle()
@compiletime static function initialize()
for typ in ItemType
typ.generateObjData()
init
ItemTypes.initialize()
...you'd expect every ItemType instance to be processed in the loop in the initialize function, however, static members are not initialized, so those ItemType instances are not even created, so no object data will be created, either.
For anyone who wants a funky workaround for this, you have to do this:
package ItemTypes
import Inventory
import ItemTypeArmor
import ItemTypeWeapon
public abstract class ItemTypes
static constant LightArmor = new ItemTypeLightArmor()
static constant MediumArmor = new ItemTypeMediumArmor()
static constant HeavyArmor = new ItemTypeHeavyArmor()
static constant PulseRifle = new ItemTypePulseRifle()
@compiletime static function initialize()
if LightArmor == null
or MediumArmor == null
or HeavyArmor == null
if PulseRifle == null
for typ in ItemType
typ.generateObjData()
init
ItemTypes.initialize()
As bizarre as this looks, it works. Because those static members are referenced in the compiletime function (even if seemingly for no reason), ItemType objects are initialized, so the loop generates object data as intended.
This is the intended behavior. Running all initialization code at compiletime would cause problems, since you certainly use native which are not available at compiletime.
since you certainly use native which are
not available at compiletime.
Such as... what? I never do, actually. Not even timers or triggers, I just make those in init/construct blocks that are not run in compiletime at all if I need to. I have separated my compiletime vs non compiletime code enough that such things wouldn't happen. I want to have a container abstract class like this that will only run code that's possible to initialize in compiletime, and I make sure that those constructors don't use any code that compiletime can't deal with, and every approach other than this feels backwards. So my solutions are:
- Do what I did here, make dummy references to force the compiler to initialize variables
- Make those fields variables instead of constants so that I can set them from the classes where they are initialized in (a really bad solution because it makes them variables instead of constants and if I don't import those packages in ItemTypes package I could get a weird init order that would could fuck object ids)
What wold you suggest as an alternative to this, though? All solutions look ugly, even though I did find one that works really well in general, both can become hard to maintain.
Here's another workaround:
static constant LightArmor = compiletime(new ItemTypeLightArmor() castTo int) castTo ItemTypeLightArmor
This should also work, although it will create a bunch of unnecessary arrays in background, gotta test this.
package ItemTypes
import Inventory
import ItemTypeArmor
import ItemTypeWeapon
public constant ItemTypes = new ItemTypesClass()
class ItemTypesClass
constant LightArmor = new ItemTypeLightArmor()
constant MediumArmor = new ItemTypeMediumArmor()
constant HeavyArmor = new ItemTypeHeavyArmor()
constant PulseRifle = new ItemTypePulseRifle()
@compiletime function initialize()
for typ in ItemType
typ.generateObjData()
init
initialize()
Such as... what? I never do, actually. Not even timers or triggers, I just make those in init/construct blocks that are not run in compiletime at all if I need to.
So you are creating triggers at initialization time ... There really is no difference between initializing a global variable and running code in an init block. Neither of them are automatically run at compiletime.
We could change it so that @compiletime annotations can be put on init blocks and on variables to make them execute at compiletime.
Yeah, that sounds good. It'd also be cool if you can put it on a class to force init of all static data.