DCE won't turn off? Can't instantiate class reflectively

I’m working on a game where I specify a class name in a text file (eg. TheEndScreen) and the code reflectively instantiates it.

To achieve this, I use this reflection code (c/o Stack Overflow):

// Create the specified type. Must have a constructor with no args.
return Type.createInstance(Type.resolveClass(className), []);

When I run this on Neko, I get a stack dump:

Called from /usr/lib/haxe/std/neko/_std/Type.hx line 102
Called from deengames/abook/core/Screen.hx line 299
Called from deengames/abook/core/Screen.hx line 283
Called from deengames/abook/core/Screen.hx line 273
Called from deengames/io/GestureManager.hx line 45
Called from deengames/abook/core/Screen.hx line 107
Called from flixel/FlxState.hx line 155
Called from flixel/FlxGame.hx line 700
Called from flixel/FlxGame.hx line 648
Called from flixel/FlxGame.hx line 493
Called from openfl/_legacy/events/EventDispatcher.hx line 98
Called from a C function
Called from openfl/_legacy/display/DisplayObject.hx line 161
Called from a C function
Called from openfl/_legacy/display/DisplayObjectContainer.hx line 286
Called from openfl/_legacy/display/Stage.hx line 1103
Called from openfl/_legacy/display/Stage.hx line 351
Called from openfl/_legacy/display/Stage.hx line 1084
Called from openfl/_legacy/display/Stage.hx line 430

As a work-around, I currently just create the class by hand (eg. new TheEndScreen()) in some other place that the user won’t notice (eg. right before I destroy the splash screen).

This works, which makes me suspect that DCE is the reason behind this exception.

To work around this, I tried the following:

  • Adding @:keep on top of my class
  • Adding <haxeflag name="-dce no" /> in project.xml (as per other forum posts)
  • Adding <haxeflag name="-dce" value="no" /> in project.xml (as per the lime Project XML docs)

None of this seems to resolve the crash.

I also don’t have (and can’t easily install) the debug version of Flash to see what that generates.

Any ideas?

Try this:

<haxedef name="dump" value="pretty" />

After compiling, check through the “dump” folder.

We’re currently using this entry in our project.xml to preserve entire packages:

<haxeflag name="--macro" value="include('com.yourpackage.package')" />

Before this, we also did a dummy instantiation like you mentioned. Note: if you do that dummy instantiation, you can actually do it in a static method that never gets executed, so you don’t pay the cost at runtime. We still use this technique for certain Std methods that don’t get compiled in but are used by remotely downloaded swfs. For our own code, we use the above haxeflag.

@player_03 as expected, my class is missing from the dump folder unless I instantiate it somewhere. I wish I could definitively say whether this is a lime bug (dce isn’t disabled when it should be) or a Haxe bug (class gets eaten despite @:keep annotation) or something else.

@sjian That’s an excellent solution that works for me. Thanks!

Sounds like it wasn’t a DCE bug at all. The problem was that the class wasn’t included in the first place.

Haxe doesn’t include every class in your source folder. It only includes classes required by your main class. That means: your main class, all classes imported by your main class, all classes imported by those imported classes, etc.

Since this class was never referenced (either in an import statement or in the form of “new TheEndScreen()”), Haxe skipped it entirely. Haxe didn’t even open TheEndScreen.hx to see the @:keep annotation.

I guess that makes sense. Although, coming from a C# background, I kind of expected that project.xml made it a “project” (and not just a bunch of .hx files in a folder) that are a “project.” There’s even a classpath attribute, but I’m not sure I trust that it means what I expect.

I’m glad I have a solution / work-around though. Thanks for the clarification.