COMMUNITY

How can I have an interface function that returns a base type implemented in classes returning child types?


(Kyliathy) #1

I have an interface that should allow access to an Array<BaseClass>. Then, classes inheriting BaseClass have to implement that interface, but they have to return Array<ChildClass1> instead.

What’s the best way to do this in Haxe? I’ve looked at Abstract and tried to create a parent field to the BaseClass using an Abstract type that is typed as the BaseClass. But it doesn’t seem to work the way I thought it would. Declaring a variable in the base class using the abstract type doesn’t compile when assigning to it from a child class.


abstract AbstractParent(BaseClass)
{
	inline public function child (parent: BaseClass)
	{
		this = parent;
	}
}

//Declaration in parent class:

public var parent: AbstractParent;

//then in ChildClass

parent = this; //error, should be AbstractParent

I’m pretty sure this can be achieved. I think it may be related to using the -> token to define a type mapping? Sorry, my Haxe terminology is not yet up to snuff.

Can you please point me to the right manual page? :smiley:


(David Bruce) #2

Just a heads up an abstract in Haxe is not the equivalent to an abstract class in say Java or C#. https://haxe.org/manual/types-abstract.html

Also I think this might be what you are attempting to do:
https://try.haxe.org/#9e428

interface HasArray<T> {
    public function getArray(): Array<T>; 
}

class HasArrayImpl<T> implements HasArray<T> {
    var myArray: Array<T>;
    
    public function new () {
        myArray = new Array<T>();
    }
    
    public function getArray() {
        return myArray;
    }
}

class Person extends HasArrayImpl<Person> {
    public var name(default, null): String;
    
    public function new(name: String) {
        super();
        this.name = name;
    }
}

class Test {
    static function main() {
        var child = new Person("John");
        var siblings = child.getArray();
        siblings.push(new Person("Josh"));
        siblings.push(new Person("Jacob"));
        trace('${child.name}\'s siblings are:');
        for (sibling in siblings) {
            trace(sibling.name); 
       }
    }
}

Also check out both generics and variance:


Hopefully that will lead you in the right direction.


(Kyliathy) #3

That’s one awesome reply man :slight_smile:. Thank you for the work you’ve put into that! It really helped. I didn’t know that one can add generics when inheriting something! :smiley:. I’m now trying to implement the changes in my code. I simplified my situation in my original post. I have to implement a parent/child relationship between 2 classes that have a common ancestor but diverge quite a bit. And there’s also a class that unifies behavior from 2 classes via composition. It’s a bit tricky but you definitely pointed me in the right direction.

Man I love this community :slight_smile:. And I’m becoming quite fond of Haxe. It’s quite a nifty language. I plan to go into macros eventually, but I still have to work through some of the basics. I have not used generics in a long time (been using them in C# and C++ but that was more than 5 years ago so obviously I’m a bit rusty).

Thank you again!

LOL just after typing that reply I hit RUN and it worked, hahaha :). I had done one change before switching to type the reply, thinking I’d better thank you for the work before it gets too late (thought that if I wait until I fix this it’s gonna be Monday :smiley: ). And then I switched back, hit run and boom, compiled & functioning too.

Well, I broke some parent/child relationships out of necessity (2 different generics <T,U> cannot join back into the same base class). I need both T and U because T is used for a ancestor: T field and U for a children Array<U>. The two are different because the T class (the ancestor) is used to summarize behavior which can work with children of type U. And as I said above, there are 2 different inheritance chains. This is a filtering system that uses 2 very different filters, both with different behavior both in the ancestor (base class) and in the children.

I wrote more about what I’m building in this other post:

Anyway, it’s definitely coming together very nicely!


(Allan Dowdeswell) #4

You’re the most active poster on here lately; I look forward to hearing more about your adventures!


(Kyliathy) #5

Hahaha :slight_smile:, yes, I’ve noticed, with slight embarrassment. You’d say after 20 years of software I’d be more capable of figuring some of these things out, but to my defense, 10 of those years were not exactly full time and I’ve taken a long break from “real” coding for about 5 years. What I’ve done in the past 5 years can hardly be named coding, more like fiddling around and working with scripts, build systems (with one 6-months exception).

In any case, if it does you any good, I’m working on an open source game logic engine (centered on driving story, skills and math rather than graphics). It’s something that gives me a tremendous drive. I believe in this with all my heart, which is why I’m quite quick on the trigger sometimes (posting here asking for help in order to advance quicker).

Everything I’ve ever coded (including about 3 applications and a game) was free and mostly open source. I think that’s the case for many here.