typedef inheritance with mixed types (similar to classes)

76 views
Skip to first unread message

Jedx

unread,
Feb 25, 2015, 5:11:43 AM2/25/15
to haxe...@googlegroups.com
Hi all,

Basically I am trying to get typedefs to behave in the same way that classes do with inheritance, specifically being able to "mix" types as long as they extend the base type. See the compile errors at http://try.haxe.org/#f9788 for a concrete example of what i'm trying to achieve. Doing the same thing with classes works fine, so i'm wondering if there is anyway of achieving this with typedefs (or this this approach should be avoided for any reason)?

Cheers

Simon Krajewski

unread,
Feb 25, 2015, 5:47:10 AM2/25/15
to haxe...@googlegroups.com
My favorite topic! There's some discussion on it at
https://github.com/HaxeFoundation/haxe/issues/3192 and several other issues.

That being said your design is quite strange. You use a finite set
(EquipType) to index into a Map, which is questionable. Even more so if
you lose your concrete type in the process. Why not have a structure
type like this instead?

```
typedef Equipment = {
weapon: Weapon,
shield: Armour,
helmet: Armour
}
```

If you absolutely need your dynamic getEquipped lookup you can keep the
EquipType enum and translate it to Reflect.field calls.

Simon

P.S.: Another problem with your Map approach is that you can literally
end up with your shoes on your head as far as the type system is concerned.

Jedx

unread,
Feb 25, 2015, 6:21:27 AM2/25/15
to haxe...@googlegroups.com
(No wonder I couldn't find any threads on it, i'm obviously not up to scratch with the lingo)

I will not deny that my design is strange, and I do prefer your suggestion for storing equipment. I would still like to be able to have an Array<Item> that contains Weapon/Armour/whatever extended typedef without complaint from haxe. I'm guessing the linked Github issues explain reasons for this, but it all goes over my head atm unfortunately.

Thanks for the help!

Juraj Kirchheim

unread,
Feb 25, 2015, 12:16:13 PM2/25/15
to haxe...@googlegroups.com
This will work: http://try.haxe.org/#74454

The basic issue is that the type of `{ name: "Sword", value: 3, dmg: 4 }` is *not* `Weapon` as you might expect, but instead it is a type I shall call `Exactly<{ name:String, value:Int, dmg:Int }>` (this is not really correct, but it should give you a workable mental model). That type is compatible with exactly one other type, i.e. `{ name:String, value:Int, dmg:Int }` (the type you aliased as `Weapon`), but none that type's supertypes, e.g. `Item`, `{ dmg: Int }`, `{ name: String }`, etc.

So what you have is this:

    var items:Array<Item> = [{ name: "Sword", value: 3, dmg: 4 }];

Which is pretty much equivalent to this: 

    var tmp:Exactly<{ name:String, value:Int, dmg:Int }> = { name: "Sword", value: 3, dmg: 4 };
    var items:Array<Item> = [tmp];

And that doesn't work, because `Exactly<Weapon>` is incompatible with `Item`. If however you put the value into an expression that has the type `Weapon` (by for example defining it as a variable), then it works:

    var tmp:Exactly<{ name:String, value:Int, dmg:Int }> = { name: "Sword", value: 3, dmg: 4 };
    var sword:Weapon = tmp;
    var items:Array<Item> = [sword];

The reason for *why* object literals are inferred to `Exactly<{ ... }>` is that this helps avoiding a certain class of bugs, as is discussed in the issue (and probably a dozen other places).

Best,
Juraj


--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.

Jedx

unread,
Feb 26, 2015, 6:55:23 AM2/26/15
to haxe...@googlegroups.com
Ahh I see, great explanation Juraj, this has cleared it up for me. Thanks!
Reply all
Reply to author
Forward
0 new messages