Lambda the Ultimate

inactiveTopic Bruce Eckel on Java generics
started 3/12/2004; 2:27:51 PM - last post 3/19/2004; 4:55:25 AM
Ehud Lamm - Bruce Eckel on Java generics  blueArrow
3/12/2004; 2:27:51 PM (reads: 17174, responses: 21)
Bruce Eckel on Java generics
Bruce Eckel doesn't like Java generics, to say the least.

I don't trust Eckel, so don't take this post to mean I endorse his view. I just want to get the item out while the server is up, and I don't have the time to read his argument. From a quick glance, I have a feeling he is incorrect about a couple of observations.

And by the way, it's Ada - a person's given name - not ADA...


Posted to general by Ehud Lamm on 3/12/04; 2:29:37 PM

Marc Hamann - Re: Bruce Eckel on Java generics  blueArrow
3/12/2004; 3:41:31 PM (reads: 1547, responses: 0)
I think his comments boil down to the fact that he wishes Java were Python (or some other language).

Complaining that Java generics are not like generics in other languages is pointless, and I think "just" fixing the hole in collections (and similar situations in other Java frameworks) is well worth the price of admission (which is darn near free).

Sure, wouldn't it be great if <fill your favourite language and its best features here> could get you work as easily as Java, or if Java could at least be made more like it, but that doesn't invalidate the goal of making Java better on it own terms, however modestly.

I'm starting to think that Bruce Eckel is becoming an old grump who has come to resent the thing he is most known for.

(But then I'm an old grump who likes to point out that others have become old grumps. ;-) )

Josh Dybnis - Re: Bruce Eckel on Java generics  blueArrow
3/12/2004; 5:08:38 PM (reads: 1553, responses: 3)
Eckel: The following won't compile.

public class Communicate  {
  public <T> void speak(T speaker) {
    speaker.talk();
  }
}

However, this will:

interface Speaks { void speak(); }

public class Communicate { public <T extends Speaks> void speak(T speaker) { speaker.speak(); } }

There seems to be an argument that if <T> could really use an "anything" argument, it wouldn't be type-safe. This is obviously incorrect because C++ catches such errors at compile-time.

C++ templates have several intrinsic problems that make them unsuitable for Java. 1) C++ templates don't let you do separate compilation. You need to have the source of a generic class or function in order to use it. 2) C++ templates are difficult to debug. 3) C++ template create almost indecipherable compiler errors (this is being fixed but its still an open problem).

If I have to specify a subclass, why not just use the normal extension mechanism and avoid the extra clutter and confusion? Like this:

interface Speaks { void speak(); }

public class CommunicateSimply { public void speak(Speaks speaker) { speaker.speak(); } }

The following example using generics cannot be done cleanly without them.

interface Animal { ... }

class Dog extends Animal { ... }

class Cat extends Animal { ... }

class Breeder <A extends Animal> { public static A reproduce (A, A) { ... } }

public class DogsAndCats {

Cat c1 = new Cat(); Cat c2 = new Cat(); Cat c3; Dog d1 = new Dog(); Dog d2 = new Dog(); Dog d3;

c3 = Breeder.reproduce(c1, c2); // ok d3 = Breeder.reproduce(c1, c2); // error d3 = Breeder.reproduce(d1, c2); // error

}

Isaac Gouy - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 12:28:55 AM (reads: 1395, responses: 0)
Hasn't enough breath been wasted on this Thinking in Generics?

Michael Manti - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 6:03:54 AM (reads: 1331, responses: 1)
How does one delete redundant messages?

Sorry. Safari doesn't seem to handle Lamba too well.

andrew cooke - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 6:38:19 AM (reads: 1334, responses: 2)
should Speaker be Speaks, and should Dog and Cat extend Animal?

i think this would be more convincing as an argument if it didn't use a collection class - eckel already concedes that templates are necessary for collections.

i think he has a point - templates in java look like parametric polymorphism in a functional language to me. that's fine in a functional language because your data structures are separate from your functions. but in an oo language you have this mix of containers and functions that requires something more like extensible records in ocaml (sorry, can't remember the correct term), which is where he's going with "latent types". this is certainly possible - ocaml does it and is statically checked with separately compilable modules.

on the other hand, maybe it will enourage oo programmers to separate structures and operations more cleanly. i'm not sure that's a bad thing at all.

Ehud Lamm - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 8:51:02 AM (reads: 1312, responses: 0)
I come along and delete them for you...

Jean-Philippe Bernardy - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 11:32:51 AM (reads: 1290, responses: 1)
" Java Generics use "erasure," which drops everything back to Object if you try to say "any type." So when I say <T>, it doesn't really mean "anything" like C++/ADA/Python etc. does, it means "Object." " ... Already shows he does not understand the subject. (Careful readers have noticed that it's his first non trivial statement about Java)

Then, what is worth a rant about generics that seem to ignore that classes can be parameterized?

Almost every time I discuss language design, I think "Learn haskell, then we'll continue the discussion". Is it a worth saying in this particular case?

sean - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 2:17:07 PM (reads: 1248, responses: 0)
Almost every time I discuss language design, I think "Learn haskell, then we'll continue the discussion". Is it a worth saying in this particular case?

Um... not if you want to have a discussion. On the other hand, if you think Eckel is ill-informed, would rather not have the discussion with him, and would like to communicate that to LtU readers, this is a concise way of saying it. Not to pick on you in particular, but it seems like this sort of "talk to me after you've learned research-language-X" response, by discouraging discussion and learning, is a significant factor in keeping advanced language features out of industry languages.

Ehud Lamm - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 2:19:40 PM (reads: 1266, responses: 0)
Yes. One of the things that I saw when I skimmed Eckel's essay was this uneducated understanding of compilation by erasure.

Example. You can compile Java into x86 machine code that has no notion of objects: does this mean objects don't have any semantic significance?

Josh Dybnis - Re: Bruce Eckel on Java generics  blueArrow
3/13/2004; 4:02:40 PM (reads: 1256, responses: 1)
should Speaker be Speaks, and should Dog and Cat extend Animal?

Yep. Typos.

i think this would be more convincing as an argument if it didn't use a collection class - eckel already concedes that templates are necessary for collections.

Good point. I've changed my original post so it doesn't involve collections.

andrew cooke - Re: Bruce Eckel on Java generics  blueArrow
3/14/2004; 4:27:05 AM (reads: 1135, responses: 0)
just collecting my thoughts here:

generics add polymorphism to the language in a new way. when you do that you need to specify how types are handled. java uses subclass typing in generics, eckel wants an ad-hoc typing solution.

ad-hoc typing like this is supported in ocaml, with static checking and separate compilation, i believe. the idea is that the type of a class is the set of methods it has. a class is consistent with an interface if it has at least the set of methods specified in the interface.

supporting this kind of typing in java would have some advantages. first, it is more "open" (interfaces accept a wider range of types). second, i *think* it provides a neat solution to the co/contra-variant method problem. third, providing a different kind of typing system within the language gives a programmer more options - makes the language more expressive.

counter-arguments also exist. first, as josh's example (which i now understand better having thought about it a bit, thanks) shows, sometimes you want a less "open" type system. i can't see how this can be achieved with the ad-hoc "set of methods" approach (the best i can see is to say that interfaces must be matched exactly, but that is cutting off your nose to spite your face, since you lose all subtyping). you could argue that people can use the existing language features when this kind of "exclusive" container is required, but then you hit the problem of code-reuse (without generics you have to write new container classes or do dynamic casting). second, the language becomes more complicated - the usual social factors. third, it's not clear to me how you cleanly integrate the two approaches within one language. i suspect that c++ is avoiding some problems by having a staged approach - can you subclass a particular instance of a template, for example?

i'm not sure how knowing haskell helps here. i don't think its approach is "ad-hoc enough" - but maybe it is possible if you define enough different inter-related type classes (just as you could define a java interface for each combination of methods and so try to simulate the ad-hoc solution).

given the "eckel doesn't use enough long words to belong to my club" comments, i'm worried i'm missing something obvious / saying something stupid here. corrections welcomed.

Jim Apple - Re: Bruce Eckel on Java generics  blueArrow
3/14/2004; 12:47:34 PM (reads: 1046, responses: 1)
FWIW, Scala, running on the JVM, implements its generics similarly.

scruzia - Re: Bruce Eckel on Java generics  blueArrow
3/15/2004; 7:09:00 AM (reads: 878, responses: 0)
Indeed, Scala's generics and Java's are very close siblings: Martin Odersky (along with Phil Wadler) designed Pizza, and then stripped it down a bit to create Generic Java, which led directly to the proposal that turned into Java Generics. Meanwhile, Odersky was designing Scala. I believe the Scala compiler was derived (in part) from the Pizza compiler.

Franck Arnaud - Re: Bruce Eckel on Java generics  blueArrow
3/15/2004; 4:15:39 PM (reads: 742, responses: 2)
supporting this kind of typing [structural subtyping] in java would have some advantages. first, it is more "open" (interfaces accept a wider range of types).

This has the disadvantage that some possible type errors caught in usual OO typesystems are not detected, e.g. erronously giving a class with a 'draw' procedure in the sense of card games to a routine that expects a drawable object (with a type equal interface) in the graphics sense. Not necessarily an overwhelming disadvantage, but worth taking into account.

second, i *think* it provides a neat solution to the co/contra-variant method problem.

Well, I may be mistaken but I think it removes what covariance aims at doing, as a covariantly redefined class will not be a subtype (killing the patient as a way to cure it). I don't think covariance has a neat solution. This has been an embarassement for us in the Eiffel community for years, so we would be most grateful for a solution! The current solution for the next version of Eiffel is also largely killing the patient. In fact, perhaps not the wrong thing to do for a such a patient.

third, providing a different kind of typing system within the language gives a programmer more options - makes the language more expressive.

This is also a possibly double-edged sword, leading to a balkanisation of styles with work developed by heterogenous teams more likely to have clashing styles and being harder to combine or maintain (e.g. would a library in substyle A fit well in a program in substyle B?).

andrew cooke - Re: Bruce Eckel on Java generics  blueArrow
3/16/2004; 5:37:56 AM (reads: 635, responses: 0)
I think it removes what covariance aims at doing

i'm on very uncertain ground here, but i was thinking about this while walking to work today and i'm pretty sure my original comment was wrong. it's a pity no-one here uses ocaml!

Daniel Bonniot - Re: Bruce Eckel on Java generics  blueArrow
3/17/2004; 5:25:52 AM (reads: 497, responses: 0)
I don't think covariance has a neat solution. This has been an embarassement for us in the Eiffel community for years, so we would be most grateful for a solution!

Covariance is only a problem when one tries to replace a function by another one (after dispatch on the implicit argument). See G. Castagna. Covariance and contravariance: conflict without a cause. ACM Transactions on Programming Languages and Systems 17(3):431-447, March 1995.

Practically, this means that one should see a covariant method as a specialization of the original method, which is applicable only if all the arguments belong to the new method. That is, you need to perform multiple-dispatch. In the syntax of Nice:

class A
{
  boolean equals(A that) {
    ...
  }
}

class B extends A { equals(B that) { // this is executed when both 'this' and 'that' are instances of B } }

That is, if you compare a B to an A, the method in A will be executed. Just as comparing an A to a B would (equals is a symmetrical predicate after all!). Note that if you need different behaviour for these cases, you can specify them explicitely too.

Ian Griffiths - Re: Bruce Eckel on Java generics  blueArrow
3/19/2004; 4:55:25 AM (reads: 375, responses: 0)

Bruce is not quite correct when he claims that the type of a template parameter is effectively Object. It's not that simple. If you use the C# typeof operator, it will correctly tell you the correct type for the template argument. This is not merely relying on retrieiving type information from an instance at runtime - the typeof operator takes a type name not an instance. And in a generic class or method, it can take the name of one of the generic parameters. So in this case:

  public Foo<T>()
  {
    Type t = typeof(T);
  }

t will be the type object for whatever the argument supplied for T was on whichever instance you invoke this on. You definitely don't get back the type object for System.Object. So Bruce is wrong to suggest to say that T is effectively of type Object.

However, a limitation still exists. In C#, the set of methods you are allowed to call on an instance of T is only those supported by Object. So as far as method invocations go, it's as though what Bruce says is correct. (Not all languages have this restriction - if you're using a language that supports dynamic late bound method invocation, then you can invoke any method. This has nothing to do with generics though...)

Interestingly, IL does not impose this restriction - it appears to be a C#ism. However, if you generate IL that invokes non-Object methods on T, although it compiles fine, you get a MissingMethodException from the JIT compiler when you try to instantiate the generic function in question, somewhat disappointingly.

(I wrote a little more details on this in my blog here: http://www.interact-sw.co.uk/iangblog/2004/03/14/generics