changed:
-
Is latent typing (in a staticly-typed language) desirable? Or rather, does it "go against the grain" of the language?
Let's say I have classes Gun and Camera, both with a shoot() method. If I had another method <T>void makeMyDay(T t){t.shoot()}, do I really want to be able to pass an instance of either Gun or Camera to it, without caring? Am I better of using an interface like FireArm and making that the parameter to makeMyDay()?
Doesn't it make it likely I'll "shoot myself in the foot" (pun intended) if I just call "shoot()" on any old object? In java, the symantics of a method are not bound to its name, so much as they are bound to the interface the method belongs to. eg: print() means different things to a Stream than it does to an AWT component.
=Matt Quail http://madbean.com/blog/
I was going to say what Matt said, but then he said it first. Interfaces imply not just signatures, but semantics. Good systems that use latent interfaces try hard to make method names that are unambiguous (and Smalltalk even went as far as to combine method names and signatures). But in a statically typed system you don't need to be as careful about naming in the same way, so it may be more of a concern to Java designers.
-- Ian Bicking http://blog.ianbicking.org
I think one thing that is missing in this discussion is attributes/metadata that is created with a "generic" class. Instead having the compiler produces a bunch of classes, for each generic type, just use the "object" class. Then if you reach a point where the VM says its a performance problem, look at the metadata create the class and optimize it all away.
I think the fundamental misunderstanding between you and people who think 'static typing/strong contracts' is that it could be desirable to call the talk() method without an interface. (Disclaimer: i am in the latter group)
Dog/Robot example, your mistake is that Dog and Robot have a method called 'talk()' and you assume that both have the same contract just because the methods happen to share the name. It may be that way, but there is no guarantee that both have the same meaning without putting 'talk()' into an interface and specifying the exact meaning of 'talk()' in the API description. So calling a function just because of it's name is not guaranteed to work, one of the classes may have a talk() function with a completely different meaning.
There's also a second problem with the Python- and C++-implementation. It's very hard to specify the API contract for a function like 'speak()', or more precisely, to describe the allowed types for the 'anything' argument. In your example it is relatively simple, the description of 'anything' would be 'an object that has a method called talk() which prints something to STDOUT'. In the real life is would be much more difficult, you would need to list all methods that the type needs to implement and describe their behaviour. Just 'anything must implement Speaks' is shorter, more precise and more elegant as API contract.
The only real use of Generics is to get rid of the casts. It's correct that Generics can't do everything that C++ templates (or late-binding languages like Python) can do, but most of the extra capabilities just make your life more difficult, if you have strong API contracts. And for the (few) remaining cases strong-contract languages could use multi-methods, but that's a different discussion and not part of Java 1.5...
<hr><b>2004/03/11 07:31 EST (via web):</b><br>
---
Can you give an example where multi-methods are used for something you could also do with C++ templates?
-- Daniel Bonniot http://www.jroller.com/page/dbr
"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."
Multi-methods are useful if you need special handling for some types. Let's assume that you
have a generic function to count bytes. Using multi-methods you can have a single implementation that counts bytes from both java.io.InputStream and java.nio.ByteBuffer (assuming that Java had multi-methods):
<pre>
{{{
byte getByte(Object src) {
throws new Exception("Unsuported type");
}
byte getByte(InputStream src) {
return is.read();
}
byte getByte(ByteBuffer src) {
if (src.remaining() == 0)
return -1;
return src.get();
}
int countBytes(Object o) {
int c = 0;
while (getByte(o) != -1)
c++;
return c;
}
}}}
</pre>
Because you lose type-safety in countBytes() you may want to make countByte() private
and wrap it in type-safe methods, but you only need to implement the algorithm for
counting bytes once.
Effectively multi-methods are used for adding virtual methods to a class.
>But don't implement something whose sole purpose is to solve the casting problem in containers, and then insist that on calling it "Generics."
Arent they called parameterized types?
---
Another disadvantage in the C++ and Python version is that if you want to extend speak() later, you can not call any of "anything"'s function except talk() without modifying the contract of speak(). And if you modify the contract, code that uses it may break without any compile-time warning for the API users.
In the Java version users will immediately notice that the contract has changed, because their app does not compile anymore. And because many interfaces already have more than one useful function, you may not even have to change the contract at all.
<hr><b>2004/03/11 10:38 EST (via web):</b><br>
You can actually do this in a type-safe way in Nice ( http://nice.sf.net ), which is an extensions of Java. In addition to multi-methods, it also has abstract interfaces, which allow you to declare that existing classes implement your specific interface. Here is the code::
abstract interface ByteSource
{
/** @return the next byte of the source, or -1 if the end is reached. */
int getByte();
}
// Make java.io.InputStream implement our new abstract interface
class java.io.InputStream implements ByteSource;
// Provide the corresponding implementation of getByte
getByte(java.io.InputStream src)
{
return src.read();
}
class java.nio.ByteBuffer implements ByteSource;
getByte(java.nio.ByteBuffer src)
{
if (src.remaining() == 0)
return -1;
return src.get();
}
<ByteSource T> int countBytes(T src)
{
int c = 0;
while (getByte(src) != -1) c++;
return c;
}
This gives you as much flexibility as C++ templates to define generic operations, without the potential semantics errors of latent typing, and with complete type safety.
-- Daniel Bonniot http://www.jroller.com/page/dbr
What I don't like about the abstract interface concept (and all other mechanisms that add members to classes) is that it makes the source code hard to read. If you read the source for countBytes() it doesn't give you any hint where to look for getByte()'s documentation or source code - it could be literally anywhere. Classes have two purposes in most OO-languages: to associate code with data, and to organize the code. You lose the second when declarations have no fixed location. The MultiMethod solution makes the invocation less elegant, but at least it's obvious where the method came from.
<hr><b>2004/03/11 11:19 EST (via web):</b><br>
If you read the source for countBytes, you see that getByte is invoked on src, which is declared of type T. T is constrained to be a ByteSource. So you know where to look for the declaration and documentation of getByte: in ByteSource. If you want to see the implementation of getByte, you can simply look for 'class X implements ByteSource'. An IDE would typically present you with the list of implementations of getByte automatically.
getByte _is_ a multi-method in this example. The only difference is that the type of getByte is more precise, because it tells you which classes are valid arguments: those that implement ByteSource. So there is more information than in the initial multi-method implementation, not less.
I guess I must be missing something. In your example, how do you know where the multi-method is defined? Why would it be different if you simply give that method a more precise type?
Maybe I misunderstood the abstract interface use, I should spend more time reading the doc.
In the multi-method example the multi-method must be in the same class, otherwise the expression "getCount()" cant be dispatched.
It seems the article confuses the quirky behavior of C++ templates with dynamic typing which aren't really related concepts. C++ templates gives you statically checked parametric polymorphism while dynamic languages like Python give you dynamically checked parametric polymorphism. So you don't get dynamic or latent typing from C++.
At best C++ templates give you a static version of what the Ruby folks like to call duck typing.
More on this at http://www.25hoursaday.com/weblog/PermaLink.aspx?guid=ec2608d8-3ca6-4dcc-a756-3023859ff94b
As I see it, I prefer the strongest way.
I still remember how hard was when I was developping in C++ using template libraries, and I considered myself a "templates" fan. After working some years using Java, now I really hate C++ templates, but welcome Java Generics. In this case, for me, less is much much more.
On the other way, Java has a way to get around its strong type system, if you want more freedom, you always can use the Reflection API, and reimplement your example as:
<pre>
public class Communicate {
public <T> void speak(T speaker) {
try {
Method speakmethod = speaker.getClass().getMethod("speak", new Class[]{});
speakmethod.invoke(speaker, new Object[]{});
}
catch (Exception ex) {
throw new RuntimeException("method speak() not supported", ex);
}
}
}
</pre>
Although in this example you obviously don't need genericity...
<hr><b>2004/03/11 14:55 EST (via web):</b><br>
It really is C++ that is odd in this case, not Java. The implementation of generics in Java 1.5 corresponds to what most of the world understands by the term, including Ada programmers. Ada does not allows latent typing of type parameters: they must either have a "private" type, which means you can't do much with them at all, or a declared supertype. This is basically the same situation as Java, where they can extend "Object" which everything does (except primitives, which problem boxing and unboxing solves), and which means you can't do much, or extend some known type.
I also doubt the importance of the issue raised: All you're doing with the "latent" type in C++ is concealing the constraint from the compiler until it is almost too late. You don't get real dynamic typing: the type is still defined at compile time. The only difference is that in Java you actually have to declare the interface you expect to be implemented. You could add a preprocessor (not that I recommend this) to generate that intgerface for you if you wanted to: ergo this is just a syntactic issue. In C++ there is no way to declare and use that type, even if you want to.
Which isn't to say that the latent typing in C++ isn't useful: it lets you get the same effect as virtual functions without the overhead, albeit in an inelegant and syntactically divergent way. But it really is C++ that is out of tune with normal usgage here, not Java.
<hr><b>2004/03/11 22:57 EST (via web):</b><br>
Back to multi-methods: ok, so your idea is that multi-methods cannot be declared outside classes, right? Even then, you could still use an abstract interface to make the type of getByte more precise.
Independently of this idea, I think that the ability to define multi-methods gives you a flexibility which enables truly modular programming when traditional OO does not. True, that means that you don't know at once where a method is defined. But you can think about it this way: methods are now contained in packages, just like classes. How do you know which package a certain class name belongs to? Either the name is fully qualified, and then it's obvious. You could also fully qualify method names. Or the name is not fully qualified, and then you rely on the import statements to find out where that name comes from. Moreover, a good IDE will typically give you that information automatically, and that can also work for a method.
-- Daniel Bonniot http://www.jroller.com/page/dbr
My opinion, that I would like to share with you, is that generics addresses the target your bullet missed widely. It is not likely to comprehent it (the target) with the casual overview, not even by Bruce Eckel. With type-safety, speed & legacy code interop in mind, I find the generics implementation more than a up/down casting util. Please consider this piece of code again, page 17, generics tutorial you mentioned.
Please dont trust me when I assume it compiles.
<pre>
Collection<EmpInfo> emps =
sqlUtility.select(EmpInfo.class, ”select name, id from emps”); ...
public static <T> Collection<T> select(Class<T>c, String sqlStatement) { Collection<T> result = new Vector<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) { T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
} return result;
}
</pre>
I see the new, «generic» type of coding available and much wider area for «generic» patterns to excersize.
Latent typing is well and good, but it essentially requires either a per-type instantiation of the template code *or* extremely late binding, i.e. reflection. For example, in C++ you get different object code for T<A*>, T<B*>, T<int*>, T<long*>, T<unsigned long*>, etc -- even if there are *no* differences between T's implementation for each type -- due in large part to latent binding. In Lisp, Smalltalk, etc, I presume you have the other extreme -- ultra-late binding.
Neither approach is good for Java. Per-type instantiation leads to excessive object code bloat (and is a huge issue with using templates in C++ as I see it -- which requires very careful inline template coding, etc, to avoid). Binding everything via reflection would cut the template's performance in half in the best case.
While I'd like to see further byte code and/or JVM optimizations to drop runtime casting from within generics, I am happy to see that Sun took neither extreme on this front. [Besides casting I'd really like to see generics for primitive types with per type code generation in *this* case, but I do understand this adds a huge amount of complexity to the implementation.]
FYI, "duck typing" is an awful name intended to bring to mind the phrase "if it looks like a duck, and quacks like a duck, it must be a duck." It represents the concept of looking at the methods implemented instead of the object's type to determine what you can do with the object. Ruby and SmallTalk and Objective-C allow this. The object may throw an exception (ie "method missing") if it doesn't support the method.
My view as a late convert to dynamic typing is that generics in any language are a kludge used to work around the intentionally limited (broken, in other words) facilities of the language's native static type system.
Also, Java, although mostly static, doesn't really need the feature, in my humble opinion -- it's only because Microsoft shoved all of the C++ programmer's pet features into C# that Sun was forced to add similar ill-conceived language additions.
<hr><b>2004/03/12 20:17 EST (via web):</b><br>
test
<pre>test</pre>
<i>test</i>
<hr><b>2004/03/12 20:19 EST (via web):</b><br>
<i>Eckel: The following won't compile.
<pre>public class Communicate {
public <T> void speak(T speaker) {
speaker.talk();
}
}</pre>
However, this will:
<pre>interface Speaks { void speak(); }
public class Communicate {
public <T extends Speaks> void speak(T speaker) {
speaker.speak();
}
}</pre>
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.</i>
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).
<i>If I have to specify a subclass, why not just use the normal extension mechanism and avoid the extra clutter and confusion? Like this:
<pre>interface Speaks { void speak(); }
public class CommunicateSimply {
public void speak(Speaks speaker) {
speaker.speak();
}
}</pre></i>
The following example using generics cannot be done cleanly without them.
<pre>public class Speaker {
String message = "";
public void talk(); { print(message); }
public String getMessage() { return message; }
}
public class SpeakerMap <T extends Speaks> {
public List<T> lookup (String message) { ... }
public void insert (T speaker) { ... }
}
class Animal extends Speaks {
public void reproduce() { }
}
class Dog extends Speaks { ... }
class Cat extends Speaks { ... }
class Robot extends Speaks {
public void oilChange() { }
}
public class AnimalsAndRobots
{
SpeakerMap<Animal> pound = new SpeakerMap<Animal>();
SpeakerMap<Robot> factory = new SpeakerMap<Robot>();
List<Animal> alist;
Robot r = new Robot();
Dog d = new Dog();
Cat c = new Cat();
pound.insert(d); // ok
pound.insert(c); // ok
pound.insert(r); // error r isn't an animal
factory.insert(r); // ok
alist = pound.lookup("meow");
for (Animal a : alist) {
a.reproduce()
}
// error factories don't contain animals
for (Animal a : factory.lookup("click")) {
a.reproduce()
}
}</pre>
<hr><b>2004/03/13 19:07 EST (via web):</b><br>
Lots of people seem to be pounding the pulpit here about the wonders of keeping type safety. That's not the issue, as C++'s generics implementation shows. What Java generics are doing is providing a generics system that isn't quite so orthogonal to inheritance. This is a really, really, really bad idea. One of the things that makes C++ templates so useful is precisely that they allow you to escape the brittle inheritance system but still keep type safety. By not really doing this, all Sun is really doing with Java is making macros.
It's dissapointing, but this is Java we're talking about. You know, programming language for the "average programmer."
The reason why C++'s templates are useful for other purposes than Java's generics are 1) C++ lacks multi-methods and 2) C++ has a hybrid type system.
Most templates functions exist to allow you to write a single function that works with all of C++'s built-in number types. If they were full objects and they all had a common base class for numbers that contained the arithmetic operators as virtual functions, you could easily eliminate most template functions by using the generic number base class.
> Lots of people seem to be pounding the pulpit here about the wonders of keeping type safety. That's not the issue, as C++'s generics implementation shows.
Indeed, the issue is not static type safety, it is having a program in which the identifiers must be declared before being used. C++ "solves" this problem by doing its "static type checking" at link time. The result is that the link between what went wrong and what you wrote is arbitrarily obscure. In Java, every identifier must be declared before it is used.
> What Java generics are doing is providing a generics system that isn't quite so orthogonal to inheritance.
On the contrary, you are not required to use inheritance, except insofar as all object types extend Object.
> One of the things that makes C++ templates so useful is precisely that they allow you to escape the brittle inheritance system but still keep type safety. By not really doing this, all Sun is really doing with Java is making macros.
This is a very strange comment, given that C++ templates are defined to be a kind of macro expansion, and Java's generics are given precise semantics. As for the brittleness of the interaction of generics and inheritance, that would perhaps be true if wildcards were not part of Java's type system.
Java generics are intended to make collections type-safe. They'd be useful even if the generic class could not call any methods on the instances whose type is given by the type parameter, i.e., if the type parameter was completely opaque. For example, if you define a parameterized List[T] type, the List can manipulate its elements without ever invoking any methods on them.
The ability to specify constraints on type parameters and invoke methods on instances of type parameters is already an extension beyond that.
The traditional way of invoking operations on objects of a generic type is to have related types; that is (sorry for the square brackets, but there is no help on this Wiki), your "sort" method looks something like "List[T].sort(Comparator[T] comparator)", instead of "List[T extends Comparable].sort()". However, to do this correctly is also tricky, and I'm not sure Java generics got the required typing right.
Neither Lisp, nor C++, nor Ada are the right languages to look at in order to understand how this works. The Java generics system was more inspired by ML's type system, and CLU also had decent parameterized types.
The reason why Java generics look so inconsistent and confused is because first of all, the use of generics in many OOLs is already poorly thought out (e.g., constrained type parameters make little sense), and on top of that, in the case of Java, generics were grafted on top of Java under serious constraints imposed by the runtime and language. As I was saying, Java generics let you catch some type errors and avoid some casting, mostly involving collection classes, but that's all. The situation with generics is pretty symptomatic of Java: Java is more and more becoming a collection of kludges, patches, and fixes. It is scary that Java is going to be the first exposure many people are going to have to features like generics and dynamic typing.
<hr><b>2004/03/16 10:54 EST (via web):</b><br>
Java generics are intended to make collections type-safe. They'd be useful even if the generic class could not call any methods on the instances whose type is given by the type parameter, i.e., if the type parameter was completely opaque. For example, if you define a parameterized List[T]? type, the List can manipulate its elements without ever invoking any methods on them.
The ability to specify constraints on type parameters and invoke methods on instances of type parameters is already an extension beyond that.
The traditional way of invoking operations on objects of a generic type is to have related types; that is (sorry for the square brackets, but there is no help on this Wiki), your "sort" method looks something like "List[T]?.sort(Comparator[T]? comparator)", instead of "List[T extends Comparable]?.sort()". However, to do this correctly is also tricky, and I'm not sure Java generics got the required typing right.
Neither Lisp, nor C++, nor Ada are the right languages to look at in order to understand how this works. The Java generics system was more inspired by ML's type system, and CLU also had decent parameterized types.
The reason why Java generics look so inconsistent and confused is because first of all, the use of generics in many OOLs? is already poorly thought out (e.g., constrained type parameters make little sense), and on top of that, in the case of Java, generics were grafted on top of Java under serious constraints imposed by the runtime and language. As I was saying, Java generics let you catch some type errors and avoid some casting, mostly involving collection classes, but that's all. The situation with generics is pretty symptomatic of Java: Java is more and more becoming a collection of kludges, patches, and fixes. It is scary that Java is going to be the first exposure many people are going to have to features like generics and dynamic typing.
Like several contributors to this discussion, I don't grasp what's so desirable about latent typing. Why, in what circumstances, is it a good idea to treat objects of completely different types as the same just because both expose a method with the same name? If Bruce Eckels could give a real world example where this might be useful, he might convince me. The robot and dog example is hardly convincing. I can, however, immediately see the disadvantage: It is hard to understand the code if a method name is used of which I don't know where (in what class or interface) it is defined. I have no way of knowing its contract, its semantics, no javadoc to look up. If the method call includes parameters, I have no idea what they might be meaning. I can only hope that the programmer knew what they were doing. I prefer the Java approach.
(The last paragraph is a separate contribution by piglet, 16 march 14:11)
------
"Like several contributors to this discussion, I don't grasp what's so desirable about latent typing."
Eckle's blog and the various responses to it seem like
the blind talking about color.
Folks, forget all the terminology, which nobody seems to be using
consistently or correctly anyway. Java generics were primarily intended
to achieve one thing: to make collection classes more type-safe and easier
to use, but in a way that was compatible with existing libraries and the
existing JVM. They mostly achieved that goal. The resulting Java type
system is a kludge, and it is hardly state-of-the-art, but it is still
better than what Java had before it got generics.
"The conclusion that the Silicon Valley Patterns Group came to was that these so-called Generics seem to only solve the problem of automatically casting in and out of containers."
Uhm well, Class and Enum are "java generic" for example.
For Class the "java generics" allow you to say of what class a class object is.
For Enum, "java generics" allow to define operations on a subtype.
--------------------------------------
Could the last contributor please tell us what he's talking about, or leave us alone? Why does he quote but not refer to the question "what's so desirable about latent typing", and what the hell is "For Class the "java generics" allow you to say of what class a class object is" supposed to mean? Bullshit? Thank you very much.
<hr><b>2004/03/23 20:29 EST (via web):</b><br>
As the original article rightly said there is no point in using generics when normal polymorphism will surfice. However there are already examples of people who are making this mistake, so no doubt many people will. Presumable people think that a great new feature must be used, not that it is only intended when the original feature isn't appropriate. However generics let you do things that polymorphism doesn't. For example:
< C extends Collection< E > & E extends Comparable< E > > void sort( C c ) { ... }
Is a sort function that excepts any Collection, like polymorphism, except that the elements of the collection must be comparable with themselves, something polymorphism can't say. Note also that type infering languages (latent typing) can't do this, e.g. sort is STL requires two itterator arguments and not a list to overcome this limitation.
This form of generics, F-type polymorphism as it is known, is popular in many languages. The Java version was probably influenced by Haskell, same guy did both!
The original article expressed surprise at the use of the extends keyword, but this really is the best choice since the constraint can be a class or interface.
You should be "Thinking in Java" (or C#) and not "Thinking in C++" (or Smalltalk).
"Again, speak() doesn't care about the type of its argument. But it still makes sure – at compile time – that it can actually send those messages."
That is a Smalltalk way of thinking about methods i.e. A.x() means send an x message to A. This is not that Java/C# way. In those languages, a method is identified with the class or interface where it is declared (as distinct from where it is implemented). For example you override the Object.toString() method, and may invoke the Object.toString() on an object of any class. It is wrong to say that e.g. a door.close() method should be treated as a the same as databaseConnection.close(). The Smalltalk way allows that, but that is a weakly/dynamically typed language. C++ allows it, but that is because its templates are in effect a code generation system / hack. Java/C# generics are not templates and if they worked as you propose, it would be inconsistent.
"interface Speaks { void speak(); }
public class Communicate {
public <T extends Speaks> void speak(T speaker) {
speaker.speak();
}
}"
"What this says is that "T must be a subclass or implementation of Speaks." So my reaction is "If I have to specify a subclass, why not just use the normal extension mechanism and avoid the extra clutter and confusion?"
"
You don't seem to see the point of generics. There are places where they are needed and others where they are not. You would use generics with your Communicate class, if there were potentially multiple Speak implementations, and you wanted to be able to create Communicate intances which worked with one of those implementations (so certain methods only accepted or returned that class). This is useful in things like collections.
<hr><b>2004/03/25 09:46 EST (via web):</b><br>
#####################################
As I am unfamiliar with the Wikis, my comments were added without a heading, or attribution. Sorry, if any one can correct this, I would appreciate it. The text starting with
"You should be "Thinking in Java" (or C#) and not "Thinking in C++" (or Smalltalk)."
...and ending with
"This is useful in things like collections."
was added by myself, Dylan Walsh.
################################
<hr><b>2004/03/30 16:46 EST (via web):</b><br>
</B>
Dear Bruce,
please remember that with Java 1.5 the bytecode did not change and generics are mangled down to the usual "java-way-of-workaround".<BR>
So if you say <pre>Vector<int> myvec;</pre> in Java, the compiler resolves that to bytecode with added typecasts. <BR>
Decompile the bytecode to see that in action. I have recently read an article about that, however that is in german (c't 26/03, Seite 206) <BR>
Bye, Dennis
In the final paragraph of your HTML you use unescaped angle-brackets, instead of < and >, so that it renders "class<Hat> and class<Cloud>" as "class and class".
mildly confusing.
hth!
pmg
WWJD?
What would Jython Do?
A lot of this discussion is tied to the specific proposal that was accepted for Java generics. I personally preferred PolyJ's proposal (http://www.pmg.lcs.mit.edu/polyj/). It allows you to use 'where' clauses to specify what methods the type parameter should have.
About JAVA AND CSS discussion,you can come to <a href="http://www.google163.net/blog/archives/">SEO</a>
Another good use for Java generics: Mixins. With no precompiler, a little protection of OnceAndOnlyOnce is a good thing. I just wish there was constructor inheritence and other similar features in C++ - while such things aren't true OOP, they'd make mixins feasable to implement as templates. Anyways, perhaps these generics that aren't tied down to the text-form of the code will work well with non-Java languages on the same VM, similar to .NETS MSIL?
After all, C++ templates are really glorified macros. They're just text manipulation with a lot of rules. I think I prefer the Java approach, even if it is more limited.
Another good use for Java generics: Mixins. With no precompiler, a little protection of OnceAndOnlyOnce is a good thing. I just wish there was constructor inheritence and other similar features in C++ - while such things aren't true OOP, they'd make mixins feasable to implement as templates. Anyways, perhaps these generics that aren't tied down to the text-form of the code will work well with non-Java languages on the same VM, similar to .NETS MSIL?
After all, C++ templates are really glorified macros. They're just text manipulation with a lot of rules. I think I prefer the Java approach, even if it is more limited.
After all, code != strings.
Declaring constraints on the type to be used in a generic class allows very strong typing during compilation. You write a bit more but get a much better checking, and better error messages too. C++ doesn't do that and the messages are extremely messy. So messy indeed that the Boost library adds facilities to virtually eliminate latent typing and make messages better (although there you have the option of declaring which methods should be available to the class rather than naming an existent class, while being able to do that too).