COMMUNITY

Wildcards and resolving classes

Hi guys!
I am new here, even if I am in the Openfl forum since… well… maybe 2015.
Who cares, let’s go!

Maybe I know the answer, but I also know that I don’t know everything so I am asking you a probably-noob question: can I resolve a class with

Type.resolveClass

if the class has been “imported” with a wildcard?
An example, I need to resolve class

custom.gameName.symbols.SymbolA

and I imported the whole folder content by

import custom.gameName.symbols.*

because the folder contains tons of classes.

Type.resolveClass("custom.gameName.symbols.SymbolA")

doesn’t work, and this is why I am here, but maybe you can give me an advice to bypass/fix the problem.

Thanks!

The dead code elimination removes the class import if it doesn’t find the class use in the source code. It’s the case with ‘Type.resolveClass’ (the resolution is made at runtime and not during the compilation).

As you can see in the documentation, you can force keeping the class with: add ‘@keep’ in you class, or use ‘–macro keep()’ in the hxml, or completely disable the DCE with -dce no

Ok, now I understand what DCE is doing here.

I am adding more details about my case:
I am using conditional compilation

#if (gameName == "A")
import custom.gameName.symbols.SymbolA;
import custom.gameName.symbols.SymbolB;

#elseif (gameName == "B")

import custom.gameName.symbols.SymbolA;
import custom.gameName.symbols.SymbolB;
import custom.gameName.symbols.SymbolC;
import custom.gameName.symbols.SymbolD;
...
import custom.gameName.symbols.SymbolX;
import custom.gameName.symbols.SymbolZ;

#elseif (gameName == "C")
...

Replacing those lists with
import custom.gameName.symbols.*;
would be great.

Where should I put @:keep to keep the imports with the wildcard despite DCE?

That’s unrelated to DCE. See https://stackoverflow.com/questions/42021607/haxe-how-to-keep-unused-class-from-being-eliminated/.

@:keep should be added before your Symbol class definition. Like:

@:keep
class SymbolX {}

In case of all your symbole extends the same parent classes, you can use @:keepSub, and all the subclass will be protected against DCE.

Effectively, --macro include() it’s a good option, but import classes and @:keep it’s also an option.

I already tried to add the @:keep in all the game-related -SymbolX- classes and import them with the wildcarded import, but the game couldn’t resolve the Class at runtime.

It looks like I still have to list all the imports and that the wildcard is not an option, right?

The StackOverflow answer I linked explains this. @:keep doesn’t matter if the compiler never gets to see the type, which it doesn’t with wildcard imports because they’re lazy.

Ok, so if I put @:keep in the SymbolX classes I should be able to reach them even if the wildcarded import is removed by DCE, right? But it doesn’t work, even if I put both @:keep in the classes and @:keepSub in the super, and disable dce.
This because even if the compiler keeps the classes, without the explicit import it doesn’t know where the classes are located, as they are in a different folder, is this correct?

I would need an active (non-lazy) wildcard, but such an option would be very dangerous in the wrong hands.

I should be able to reach them even if the wildcarded import is removed by DCE

Again, this has nothing to do with DCE.

I would need an active (non-lazy) wildcard

--macro include() (again, as mentioned in my SO answer) is essentially an eager wildcard import.

Sorry, I should read more carefully.
So I have to include the package:
I can’t do it in the command line, how can I add (include) it in the block

#if (gameName == "A")
...
#end

with a macro?
I am pretty new to macros and in general this kind of operations :sweat_smile:

You can make an initialization macro of your own that calls include() (which is also an init macro).

--macro Macro.init()
class Macro {
	static function init() {
		#if (gameName == "A")
		haxe.macro.Compiler.include("package");
		#end
	}
}

I have added the function

public static function init() {
	#if (gameName == "A")
haxe.macro.Compiler.include("***.symbols");
	#end
}

in the class MyClass where all the imports are made, but I don’t know how to add

--macro MyClass.init()

because the panel Compiler Options -> Additional Options in HaxeDevelop does not allow to add anything, and if I add it directly in the .hxproj it ignores and removes it

EDIT: ok, maybe I have found the right way to add the option in the hxproj, but now I am probably setting the wrong relative path… :neutral_face:

You only have a .hxproj, no HXML file? Personally I would avoid that, makes you very IDE-dependent and you can’t even easily build from the command line. FD can work with HXML files too.

Well, in the bin/html5/haxe folder there are debug.hxml and release.hxml, I suppose they are imported by the template project, so the base versions must be somewh… here they are

HaxeToolkit\haxe\lib\openfl\8,9,2\assets\templates\html5\hxml\debug.hxml
HaxeToolkit\haxe\lib\openfl\8,9,2\assets\templates\html5\hxml\release.hxml

Do I have to inject the instruction to run .init() in here?

Oh, if it’s an OpenFL project, the .hxproj file is pretty irrelevant. In that case, all the build arguments are in your project.xml. Something like this should work:

<haxeflag name="--macro" value="Macro.init()" />

You should not be editing the hxml files generated by Lime, they will just be overwritten during the next build.

Oh, yes, I mean to inject in the template.
Well, if I can do it in the project.xml it is perfect, but I have the same problem:
how do I specify the path to MyClass.init()?
The source path

<source path="..\..\..\..\Library\Base" />

is the root, but I have to reach MyClass, that is in a subfolder
If I put Macro.hx in the root it works, but I need to add the includes in the specific class to centralize everything.
This really looks like a noob problem… I’m feeling sad :expressionless:

The path isn’t relevant here, the package is, just like when you import a type. If there’s package my.pack; in Macro.hx, it’d be my.pack.Macro.init().

I know, it is exactly what I did, but I get these errors

:sweat_smile:

The init function is identical, I just added the package path before MyClass.init() in project.xml

Hm, maybe something else comes across it for some reason… does it help to surround the module in #if macro?