Date: Sun, 27 Apr 2003 19:37:35 -0400 (EDT)
From: C. Scott Ananian
To: jsr14-prototype-comments@sun.com
Subject: Type inference failure.

I was reading "Subtypes vs. Where Clauses: Constraining Parametric
Polymorphism" (Day,Gruber,Liskov,Myers) in the OOPSLA'95 proceedings, and
came across an example of which it was said, "Langugages whose type
systems are based on F-bounded quantification... cannot express the type
of findpath".  Well, said I, I wonder if JSR-14 can?

The original example, in Theta syntax, I think, was:

  findpath[N,E] (s,d:N) returns (array[N]) signals (no_path)
     where N has edges() yields (E),
                 equal(N) returns (bool),
           E has source() returns (N),
                 dest() returns (N)

The key property here is that there is mutual recursion between the bounds
on N and E.

I translated the example into JSR-14 to obtain:
-------
import java.util.List;
public abstract class Baz {
    static interface Node<N extends Node<N,E>, E extends Edge<N,E>> {
	List<E> edges();
	boolean isEqual(N n);
    }
    static interface Edge<N extends Node<N,E>, E extends Edge<N,E>> {
	N source();
	N dest();
    }

    static <N extends Node<N,E>, E extends Edge<N,E>>
				    List<N> findPath(N source, N dest) {
	return null;
    }
}
------

This compiles.  So far so good.  We *can* express mutual recursion between
type bounds! (I'll have to go fix my javadoc-for-JSR14 tool, since I'd
assumed the lexical scope of type parameter 'E' started at the definition
of E --- but silly me, the spec says clearly that the scope should be the
entire section.)

Anyway, so I go ahead and add an implementation and a invocation of
findPath to Baz:

----
    static class MyNode implements Node<MyNode,MyEdge> {
	public List<MyEdge> edges() { return null; }
	public boolean isEqual(MyNode n) { return true; }
    }
    static class MyEdge implements Edge<MyNode,MyEdge> {
	public MyNode source() { return null; }
	public MyNode dest() { return null; }
    }

    public static void main(String[] args) {
	MyNode a = new MyNode(), b = new MyNode();
	List<MyNode> l = findPath(a, b);
    }
-------

And, unfortunately, this no longer compiles:
---
Baz.java:28: findPath<N extends Baz.Node<N,E>, E extends
Baz.Edge<N,E>>(N,N) in Baz cannot be applied to (Baz.MyNode,Baz.MyNode)
        List<MyNode> l = findPath(a, b);
                         ^
1 error
---
[Complete source code to Baz attached, so you can try this yourself.]

I believe this should be considered a bug in the type inference algorithm.
Am I wrong?

You seem to have hinted that a new (more-powerful?) inference algorithm is
in the works.  Can the new algorithm correctly resolve this code?

Hopefully this example is helpful.
 --scott

Saddam Hussein Bush quiche RUCKUS security South Africa colonel immediate 
[Hello to all my fans in domestic surveillance] Yeltsin India Clinton 
                         ( http://cscott.net/ )

    [ Part 2, ""  Text/PLAIN (Name: "Baz.java")  18 lines. ]

Valid XHTML 1.0!