COMMUNITY

Implementing "friends" relationships -- depricated?


(Arnim) #1

Dear Community,

I have found an interesting (but old) article, that describes that any class is a an interface as well and can be used as such.

Trying to reproduce that, I failed. Is this feature depricated?

Background:

I have a BaseClass and several ChildClasses. The BaseClass itself is supposed never to be instanciated. It just delivers (as the name tells) the base of all children.

The most children do not extend each other, but they all store a graphic element. A different type of graphic element each. So the types differ enormously. But they all are supposed to access the basic features of a graphic element: get/ set width, height, x, y

What I want to do is, to create an interface granting access to these fields. But I also want to have a type that has full access to the fields of the BaseClass aswell as to the fields of the interface.

So I would tell the interface to extend the BaseClass somehow (or that the fields of the BaseClass are required as well if the interface is implemented).

Do you have an idea how can I accomplish this?

Kind regards
Arnim

PS:
It’s this article, I was talking about


(George Corney) #3

Do the @:allow(…) and @:access(…) metas solve your problem?

To grant access to a specific type you can add @:allow(<package.Type>) type, to request access from another type you use @:access(<package.Type>)

Here’s an example: https://try.haxe.org/#1D52E

And docs https://haxe.org/manual/lf-access-control.html


(Arnim) #4

Hello George,

thank you for your reply.

No. The problem does not lie in the accessabiilty of the fields.

It’s rather to tell the mashine a logic conclusion:

When you have an interface, that makes fields only of the ChildClasses of a Class accessable, logically it also could make the fields of that actual Class (the ParentClass of the ChildClasses) visible, as it could never come to a contradictive or ambigue situation.

I have worked out, what I am talking about into your proposal, @haxiomic.

The example only shows, that it does not work with @:allow
But it also shows, the constellation, that I wish to crack.

If you’re interested, please have a look here.

I was hoping, that I could tell the mashine, that the interface extends ( and demands ) all fields of the parentClass and additionally demands some fields that the ChildClasses mandatorily have implemented.

I have found a workaround anyway.

But if someone has an idea, it would be great to get to know it, as I always try to improve my skills.

So thanks again to anybody who thinks about that problem, even if he/ she does not find an answer yet :purple_heart:

Kind regards
Arnim


(Mark) #5

I think what you are trying to do won’t work, unless you are going to use type checks. Imaging having multiple classes use same interface, how can you ever use a specific parent class variable. It might not exist in a certain context.

Hope this clears it up a bit:

@:allow(Test) class Base1 {
	private var b1: Int = 44;
    public function new() { }
}

@:allow(Test) class Base2 {
	private var b2: Int = 55;
    public function new() { }
}


class Child1 extends Base1 implements ChildInterface {
    public var y : Int = 66;
}

class Child2 extends Base2 implements ChildInterface {
    public var y : Int = 77;
}

class Test {
    static function main() {
		var c1 : Child1 = new Child1();
        trace(c1.b1);
        
		var c2 : Child2 = new Child2();
        trace(c2.b2);
        
        var childArray : Array<ChildInterface> = [c1, c2];
        
        // first item is of type "ChildInterface"
        var firstItem = childArray[0];
        
        // problem: does child have b1 or b2 ? 
        trace( firstItem.b1 ); // COMPILE ERROR HERE
        // answer: It only has "y", because that is what interface defines
        trace( firstItem.y ); // NO COMPILE ERROR, because its part of interface
        
        // solution: use a type check
        if (Std.is(firstItem, Child1)) {
            var firstItem:Child1 = cast firstItem;
            trace(firstItem.b1);
        } else if (Std.is(firstItem, Child2)) {
            var firstItem:Child2 = cast firstItem;
            trace(firstItem.b2);
        }
    }
}

interface ChildInterface {
    public var y : Int;
}

https://try.haxe.org/#802Ba


(Arnim) #6

Hello Mark,

thank you for your reply. And sorry for answering with this delay (I’ll have to take a look at the settings of the notification-system, again).

I am not quite sure, if your example fits what I imagine.

What would be, if the ChildInterface could extend one of the base classes?

I only need one base class. So the identification of the base class’ fields would not be ambigue. It just would be the complement of the ‘blueprint’ demanded by the interface.

The interface then would say: “If you implement me, you have to implement all of the fields of my parent class as well!” This demand is granted by heritage, as the implementors would have the same base class anyway.

This would allow, having a virtual type for siblings (so having common fields), without the need to cast them.

To make it less abstract:

I am working on a WYSIWYG generator for a dynamic layout for OpenFl. It’s supposed to be as flexible as HTML5 and CSS (but less confusing).

For that purpose I have ‘shelfs in a rack’. These shelfs necessarily hold one displayObject each. But they do not hold the same type of displayObject (e.g. Sprite, TextField, MovieClip, etc.) . So they have a common base. This base class does not know, what displayObject the childClass instance holds.

Each displayObject has its own type shelf (eg.: BaseClass --> SpriteShelf)
In OpenFl the Sprite class extends the display class. It has the same base class like a textfield (DisplayObject --> Sprite | DisplayObject --> TextField).

So, if I could build a ‘virtual type’ via an interface, it would demand the fields of DsplayObject. And of cause also the base class’ fields are supposed to be present as well.

Alternatively casting the baseType (instead of addressing this ‘virtual type’) would cause having a bunch of differently typed instances for within the accrodung functions, which I do not consider to be the best solution.

At the moment I have build an interface for the baseClass, which is extended by the DisplayObjectInterface. This solution is not satisfying as well, as I have to mirror the BaseClass into its own interface which is redundant. It also makes it inevitable, that every work on BaseClass must be done on the interface as well.

The article, I have found, suggests (at least in my understanding) that creating this ‘virtual type’ (an interface extending a class) is possible.

Of cause, there are workarounds. I can reconcile with the thaught, that my preferred solution does not work.

But theoretically, I do not see a problem with the concept.

Kind regards
Arnim