COMMUNITY

Macro: modify a type based on existing types

macro

(NoRabbit) #1

Hi there

what I need is simple but I’m not sure it’s even possible:

I have a couple of classes that extend a common class:

CommonClass {

}

ClassExtendingCommonClass extends CommonClass {
// some public fields here
public var id:Int;
public var name:String;
// ...
}

And I need to loop through all those classes that extends my “common class” in order to create a custom method for each one of them inside a “factory class” like so:

CommonClassFactory {

public function classExtendingCommonClass(id:Int, name:String):ClassExtendingCommonClass 
{
var c:ClassExtendingCommonClass = new ClassExtendingCommonClass ();
c.id = id;
c.name = name;
return c;
}

}

Is this even possible ? How would you go about that ?

Basically I want a factory class that will auto populate itself based on all the classes that extend my CommonClass that exist.

As for as I know, the only way is to parse the files by myself as the callbacks at macro time that I can use to get a list of all the types won’t allow me to modify another type after the callback has been called.

Maybe the only way is to create a new type instead of modifying an existing one after the onAfterTyping callback ?

Thanks a lot for your time.


(Jeff Ward) #2

You want an interface that applies a build macro on the base class. The build macro will get run on the base class AND the extending classes. This will allow you to add a field to the extending classes:

http://try-haxe.mrcdk.com/#1fB46

That should get you started.

Cheers,
-Jeff


(NoRabbit) #3

Hi Jeff

thanks for your answer. I already have that part figured out.
I realize I wasn’t very clear. My main question actually is:

Inside a macro, how do I access all the types that extend a certain type (or that contain certain metadata, or anything that allows me to identify the types I want to target) and modify the current type/class the macro is running on with the information of the targeted types ?

Let’s say for example, I want to fill an array in a specific class/type with all the types I’m targeting using a macro. How would I go about that ?

The onAfterTyping callback seems to be the only thing I can use to get a list of all the types but it doesn’t allow me to modify a class. At the moment I feel the only solution is to create a new class/type in the onAfterTyping callback… just like back2dos is explaining here: https://groups.google.com/forum/#!topic/haxelang/6Kf3V1e5rEM

I just hope there is a less hackish way of doing this.

Thanks again for your answer.

Thomas.


(Jeff Ward) #4

Hi Thomas,

Maybe you’ll find some useful pattern in @jasononeil’s CompileTime or @back2dos’s ctl – both are using Context.onGenerate to look over type information.

Another approach that will collect the classes at static init runtime: use your build macro to define a static var, who’s init function will push the class into the list, like so:

class MyClassName implements IBuildMacro
{
  /* generate this field with the macro */
  private static var __inserted:Bool = function() {
    SomeHelperClass.my_class_list.push(MyClassName);
    return true;
  }();
}

class SomeHelperClass {
  public static var my_class_list:Array<Class<IBuildMacro>> = [];
}

class Main {
  public static function main() {
    // my_class_list should be populated by the time I execute...
  }
}

This example here: https://try.haxe.org/#E6ac0

Best,
-Jeff


(NoRabbit) #5

Hi jeff

I think I understand better how it all works. It seems to me that the only way I can have a list of all the types is on the onAfterTyping callback. This is what CompileTime and ctl are doing. I understand why we can’t modify a type after that callback as it would mean to redo the entire typing thing.

Well, they could have allowed it, from another callback for example, but it seems a bit too much for just a small change.

I’ll have to go with the back2dos answer here: https://groups.google.com/forum/#!topic/haxelang/6Kf3V1e5rEM

But when I think about it, replacing an existing type would also mean to recheck all its dependencies, etc…
Anyways, I don’t like it but I’ll go with it.

Thanks again.