Is it possible to incrementally specificate method parameter types in a Haxe class hierarchy?

44 views
Skip to first unread message

Hitmark7

unread,
Jan 27, 2016, 11:15:53 AM1/27/16
to Haxe

Hello everybody.

I'm trying to implement a simple MVC framework in Haxe (compiler v3.2.1), but I'm having problems with parameter types covariance and structural subtyping (if I understood the manual).

Basically, the program receives a request, passes it to a router class, that obtains the controller, that creates the response, that is dispatched by a dispatcher. I want a core package that does the basics, and several other packages that incrementally specificates it all. This way, I could have a HTTP package and a CLI package both inheriting from the Core one, changing only parameters, returns types and some concrete behavior. I have been a PHP programmer until very recently, and I think that is possible for that language. However, Haxe has a much more complex typing system, and I can't get to the perfect solution.

You can find a simplification of my code here: http://try.haxe.org/#Fb9A8 . Demo- is the package for an example application using my framework.

As you can see, the return types can be incrementally specified "from top to bottom", but that is not true for the method parameters. Using the Core type all along will make the framework work, but I would prefer to "tighten them up" into the concrete expected types.

Type parametrization of the classes didn't work for me. If I parametrize the CoreRouter class to receive Http or CliRequests, I can't refer to it from the CoreApp class.

I have also tried doing some type casts but I think that is messy and the errors may raise on run time. I definitely prefer compile time errors.

Is it possible to incrementally specificate method parameter types in a Haxe class hierarchy? If it is not possible, or not advisable, any ideas for a workaround?

Thanks.

Simon Krajewski

unread,
Jan 27, 2016, 11:25:45 AM1/27/16
to haxe...@googlegroups.com
It's not sound to do that. While return types are covariant (allow more
specific types), argument types are contravariant (allow more generic
types). It's easy to see why this is not sound:

```haxe
class Base {
public function new() { }
public function test(v:Base) { }
}

class Child1 extends Base {
public override function test(v:Child1) { }
}

class Child2 extends Base { }

class Main {
static function main() {
var child1:Base = new Child1();
child1.test(new Child2()); // Uh oh
}
}
```

As you can see this would allow us to pass an instance of `Child2` as
the argument, even though what we actually call is `Child1.test` and
that expects an instance of `Child1`.

Simon

Hitmark7

unread,
Jan 27, 2016, 11:48:40 AM1/27/16
to Haxe
Hello Simon.

I see your point, but: does not the compiler casts the child1 var from Base to Child1 type when it is asigned? I mean, the instantiation is "hardcoded" so the compiler should see the real type. If it knows that child1 is of type Child1 instead of Base, it would be able to throw an error on the "Uh oh" line at compile time.

I'm not arguing about the conveniency of this language contravariance decision. If the child1 instantiation were more "dynamic", a run time error would raise. But, what will be a better aproach for my problem then?

Thanks.

Simon Krajewski

unread,
Jan 27, 2016, 12:24:15 PM1/27/16
to haxe...@googlegroups.com
Am 27.01.2016 um 17:48 schrieb Hitmark7:
Hello Simon.

I see your point, but: does not the compiler casts the child1 var from Base to Child1 type when it is asigned? I mean, the instantiation is "hardcoded" so the compiler should see the real type. If it knows that child1 is of type Child1 instead of Base, it would be able to throw an error on the "Uh oh" line at compile time.

Sure it might be possible here, but not in the general case. Imagine `var child1:Base = someFunctionThatHappensToReturnAnInstanceOfChild1()` and you're out of luck.

I'm not arguing about the conveniency of this language contravariance decision. If the child1 instantiation were more "dynamic", a run time error would raise. But, what will be a better aproach for my problem then?

I've been staying away from inheritance in general for a while now, so I'm probably not the best person to give advice on code architecture. My usual approach is to turn everything into constrained type parameters, then discard it because it gets too complicated.

Simon

--
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.

Simon Krajewski

unread,
Jan 27, 2016, 12:32:43 PM1/27/16
to haxe...@googlegroups.com
Am 27.01.2016 um 17:48 schrieb Hitmark7:
> Hello Simon.
>
> I see your point, but: does not the compiler casts the child1 var from
> Base to Child1 type when it is asigned? I mean, the instantiation is
> "hardcoded" so the compiler should see the real type. If it knows that
> child1 is of type Child1 instead of Base, it would be able to throw an
> error on the "Uh oh" line at compile time.
>
> I'm not arguing about the conveniency of this language contravariance
> decision. If the child1 instantiation were more "dynamic", a run time
> error would raise. But, what will be a better aproach for my problem then?

For what it's worth I seem to have some success with your demo:
http://try.haxe.org/#1e6d6

Simon

Hitmark7

unread,
Jan 27, 2016, 2:55:17 PM1/27/16
to Haxe
 
I don't have much experience with parametrized classes, and I couldn't find that solution earlier. The code seems more complicated now, indeed, but with some practice I hope to get used to this wonderful language soon.

Thank you very much Simon, you saved my day. :D


Simon
Reply all
Reply to author
Forward
0 new messages