The way I understand :genericBuild, it should be possible to implement something like C++/D templates (parametric polymorphism/duck typing specifically). I attempted it, but it’s not trivial so I was wondering if there is any existing library or code snippet that does this, because I don’t want to reinvent the wheel.
Illustration of what I want:
@:generic
@:genericBuild(Macro.build())
class X<T> {
public function foo(arg:T) {
return arg.bar();
}
}
and X would be instantiatable with any type parameter that has a bar member of type Void->?
I would love any discussion on this. Macros are great, but I feel like C++/D templates are much more intuitive, and having an option for at least a primitive version of them would be great.
EDIT: The build macro would just run through the type definition and replace all occurences of T with the actual instantiation parameter.
As I mentioned .bar() is supposed to be Void->?, not Void->Void. .bar() of T can return anything it wants, which then also becomes the return type of X.foo(). There is a wide variety of problems that generics using type erasure cannot accomplish. I’m not really here to discuss that.
EDIT: I realize X could be further parametrized with U and bar made into Void->U. But that approach is not really scalable. And I have another problem with it that I will post shortly.
class Modifier<T> {
var member:T;
public function new() {}
public function apply(to:T) {
this.member = to;
// Assume that T is also Modifiable<T>
// how do we add this to to.modifiers?
}
}
class AFooModifier extends Modifier<Foo> {
public function doSomethingWithFooMember() {
// Do something with Foo member
}
}
interface Modifiable<T> {
function addModifier(modifier:Modifier<T>):Void;
}
class Foo implements Modifiable<Foo> {
public function new() {}
public final modifiers = new Array<Modifier<Foo>>();
public function addModifier(modifier:Modifier<Foo>):Void {
this.modifiers.push(modifier);
}
}
As for the original problem, you can use tink_lang’s partial implementations:
@:tink interface X<T> {
function foo(arg:T) {
return arg.bar();
}
}
class Y implements X<SomethingWithBar> {
// foo is automatically generated
}
You can also get it to work with @:genericBuild, with the restriction that the type itself (X in this case) is not usable anymore, because all references to it are replaced.
No, you can’t. That’s precisely the problem. EDIT: Specifically that Modifiable then also uses Modifier, which requires an infinite regression of Modifiable parameters.
Also it’s not possible to use arg.bar() just because it’s in a partial implementation.
It’s not impossible, but much more cumbersome and doesn’t scale as well in terms of code size as the number of Modifiables goes up. If the type system could potentially do something for me and prevent me from repeating myself, it should do that.
Not got it down pat, but a ModifiableModifier with a type constraint?
If you’re not putting in the recursive type on the ground floor, you’ll always hit the terminal in any case.
class ModifiableModifier<T:Modifiable<T>> extends Modifier<T>{}
class AFooModifier extends ModifiableModifier<Foo> {
public function doSomethingWithFooMember() {
// Do something with Foo member
for( modifier in this.member.modifiers ){
modifier.addModifier
}
}
}