views:

527

answers:

4

Suppose I have the following class:

public class FixExpr {
  Expr<FixExpr> in;
}

Now I want to introduce a generic argument, abstracting over the use of Expr:

public class Fix<F> {
  F<Fix<F>> in;
}

But Eclipse doesn't like this:

The type F is not generic; it cannot be parametrized with arguments <Fix<F>>

Is this possible at all or have I overlooked something that causes this specific instance to break?

Some background information: in Haskell this is a common way to write generic functions; I'm trying to port this to Java. The type argument F in the example above has kind * -> * instead of the usual kind *. In Haskell it looks like this:

newtype Fix f = In { out :: f (Fix f) }
+4  A: 

In order to pass a type parameter, the type definition has to declare that it accepts one (it has to be generic). Apparently, your F is not a generic type.

UPDATE: The line

F<Fix<F>> in;

declares a variable of type F which accepts a type parameter, the value of which is Fix, which itself accepts a type parameter, the value of which is F. F isn't even defined in your example. I think you may want

Fix<F> in;

That will give you a variable of type Fix (the type you did define in your example) to which you are passing a type parameter with value F. Since Fix is defined to accept a type parameter, this works.

UPDATE 2: Reread your title, and now I think you might be trying to do something similar to the approach presented in "Towards Equal Rights for Higher-Kinded Types" (PDF alert). If so, Java doesn't support that, but you might try Scala.

Hank Gay
Can you please elaborate a bit? I have declared the type to accept a type parameter -- Fix<F>. Or is this not what you mean?
Martijn
But the type you have picked - <Fix<F>> - is not generic; it only works for Fix<f> - you should declare it as type <Fix>, surely?
That paper is interesting -- thank you!
Martijn
You're welcome. I'm not well-versed in type theory, so it's been heavy going so far, but it is quite interesting. I'm glad I found your question this morning or I might never have read the paper.
Hank Gay
Seconding the suggestion you look at Scala. You can intermix Scala and Java fairly freely, so it's easy enough to dip in your toes.
Zarkonnen
A: 

It looks as if you may want something like:

public class Fix<F extends Fix<F>> {
    private F in;
}

(See the Enum class, and questions about its generics.)

Tom Hawtin - tackline
Hi Tom, that solution looks really interesting but I don't really get yet what it does. Doesn't that impose some hierarchy on F? I don't want to do that -- all I ask of F is that it still receives a type argument to be complete.
Martijn
if thats the case, then it is not possible in java to do what you want - the language is not expressive enough.
Chii
It says that F is a type of Fix. Because Fix is generic it needs to be given the correct generic argument. Your question is extremely abstract. I understand Haskell has a complicated type system that is different to Java's. It's not surprising that there is not a 1:1 map for every feature.
Tom Hawtin - tackline
In Scala lingo, what OP is asking for is this: http://paste.pocoo.org/show/261389/, and what you are suggesting is this: http://paste.pocoo.org/show/261393/.
missingfaktor
+10  A: 

I think what you're trying to do is simply not supported by Java generics. The simpler case of

public class Foo<T> {
    public T<String> bar() { return null; }
}

also does not compile using javac.

Since Java does not know at compile-time what T is, it can't guarantee that T<String> is at all meaningful. For example if you created a Foo<BufferedImage>, bar would have the signature

public BufferedImage<String> bar()

which is nonsensical. Since there is no mechanism to force you to only instantiate Foos with generic Ts, it refuses to compile.

PS If I got this wrong, please correct me in the comments, don't just vote me down...

Zarkonnen
+4  A: 

Maybe you can try Scala, which is a functional language running on JVM, that supports higher-kinded generics.


[ EDIT by Rahul G ]

Here's how your particular example roughly translates to Scala:

trait Expr[+A]

trait FixExpr {
  val in: Expr[FixExpr]
}

trait Fix[F[_]] {
  val in: F[Fix[F]]
}
ZelluX