ponyc icon indicating copy to clipboard operation
ponyc copied to clipboard

F-bounded polymorphism limitations

Open Praetonus opened this issue 7 years ago • 3 comments

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, only class 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?

Praetonus avatar Feb 14 '18 21:02 Praetonus

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

lukecheeseman avatar Feb 21 '18 21:02 lukecheeseman

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)

lukecheeseman avatar Feb 21 '18 21:02 lukecheeseman

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

lukecheeseman avatar Feb 21 '18 21:02 lukecheeseman