F-bounded polymorphism limitations
trait X[A: X[A] box]
fun f() =>
P[A](this)
class C is X[C box]
class D is X[C box]
primitive P
fun apply[A: X[A] box](a: A) =>
None
This code is incorrect. Compilation fails with the following error:
Error:
a.pony:3:12: argument not a subtype of parameter
P.g[A](this)
^
Info:
a.pony:3:12: X[A box] box is not a subtype of A box: the type parameter has no lower bounds
P.g[A](this)
The definition of D highlights the problem. In X, this isn't always an A because it is possible to define a type that implements such a trait with a different type as the type argument.
I can see two functionalities that could be implemented to fix the problem.
- Self types. This is probably the most generic solution and it would fix many problems related to the example here, but getting the design right wouldn't be trivial.
- A new syntax for constraints that would allow expressing F-bounded polymorphism as a first class concept. I.e. with such a constraint,
class D is X[C]would be an error, onlyclass D is X[D]would be allowed. Here too, there are some important design decisions to consider.
Note that the problem can also be solved in the current state of the language by implementing the function in the subtypes instead of in the trait. Unfortunately this isn't practical if you have a lot of functions and/or a lot of subtypes.
Any thoughts?
Ah, I misunderstood this sorry. I thought you were saying the implementation of F-Bounded polymorphism was incorrect. I see now that you are saying that the above program cannot type check whilst adopting only F-Bounded polymorphism. (I only write this here in case anybody else made this mistake).
trait X[A: X[A] box]
fun apply[B: X[B] box](a: B) =>
None
fun f() =>
apply[X[A]](this)
class C is X[C box]
As an aside, this causes a segmentation fault in the compiler (I'll raise a bug)
Aside: I experimented with this in Java to see what it would do (my other goto language for F-Bounded polymorphism):
public class MyClass {
private class X<A extends X<A>> {
public void foo() {
new P().apply(this);
}
}
private class P {
public <A extends X<A>> void apply(A a) {
}
}
public static void main(String args[]) {
}
}
and the Java compiler throws up a bit (this was JDK 9.0.1) in a totally sane way that it can't satisfy the bounds:
/MyClass.java:4: error: method apply in class MyClass.P cannot be applied to given types;
new P().apply(this);
^
required: A#1
found: MyClass.X<A#2>
reason: inference variable A#1 has incompatible bounds
equality constraints: A#2
lower bounds: MyClass.X<A#2>
where A#1,A#2 are type-variables:
A#1 extends MyClass.X<A#1> declared in method <A#1>apply(A#1)
A#2 extends MyClass.X<A#2> declared in class MyClass.X
1 error