June 18, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Fritz | Sean Fritz wrote: > In article <e7346j$1uo9$2@digitaldaemon.com>, Walter Bright says... >> Sean Fritz wrote: >>>> T sqr(T) ( T x ) >>>> { >>>> return x*x; >>>> } >>> Is the way Java Generics do it, >> I didn't think Java supported function templates (only class templates). > > Yes, there are class and method level generics. There are none of the linking > issues that come up from function templates (thank gods!). > > Class generics are (of course): > > class Foo<T> { ... } > > While method generics are: > > public void <T> T[] toArray(T[] arr) { ... } > So let's say we want to implement a generic sqr method in Java... How would we do it? I came up w/ this after just a quick look at the spec. to get the syntax right: public class Test { public static void main(String args[]) { Integer i = 100; System.out.println(sqr(i)); int j = 1000; System.out.println(sqr(j)); } public static <T> T sqr(T x) { return x * x; } } However, I get this when I compile: Test.java:10: operator * cannot be applied to T,T return x * x; ? Thanks, - Dave > The distinction in placment of the type parameter is one of the weirdest > syntactical choices in Java. It doesn't take long to master, but it constantly > leaves you wondering why they did it. > > Also, they aren't really anything like templates except that they allow generic > programming. It really takes several months to fully grok generics (especially > with the Java Language Spec being the only decent reference at the moment). > > Sean > > |
June 18, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dave | Dave wrote: > > public class Test > { > public static void main(String args[]) > { > Integer i = 100; > System.out.println(sqr(i)); > int j = 1000; > System.out.println(sqr(j)); > } > public static <T> T sqr(T x) > { > return x * x; > } > } > > However, I get this when I compile: > > Test.java:10: operator * cannot be applied to T,T > return x * x; > > ? > > Thanks, > > - Dave This is correct behaviour. You are now stating: T must be of type Object. Type object doesn't have the * operator implemented. Even extending it from Number won't help, since the * operator doesn't work on class instances, only on primitives. To get it work you need quite a hack: package generic.test; import sun.reflect.generics.reflectiveObjects.NotImplementedException; public class Test { public static void main(String args[]) { Integer i = 100; System.out.println(sqr(i)); int j = 1000; System.out.println(sqr(j)); } public static <T extends Number> T sqr(T x) { if(x instanceof Integer) { return (T)(Number)new Integer(x.intValue() * x.intValue()); } else if(x instanceof Byte) { return (T)(Number)new Byte((byte)(x.byteValue() * x.byteValue())); } else if(x instanceof Long) { return (T)(Number)new Long(x.longValue() * x.longValue()); } else if(x instanceof Double) { return (T)(Number)new Double(x.doubleValue() * x.doubleValue()); } else if(x instanceof Float) { return (T)(Number)new Float(x.floatValue() * x.floatValue()); } else { throw new NotImplementedException(); } } } Which is, if you ask me, not the best way of using Generics, well, I didn't invent them in Java, and it shows that it is really syntactic sugar. Regards, Sjoerd |
June 18, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sjoerd van Leent | Sjoerd van Leent wrote:
> Dave wrote:
>>
>> public class Test
>> {
>> public static void main(String args[])
>> {
>> Integer i = 100;
>> System.out.println(sqr(i));
>> int j = 1000;
>> System.out.println(sqr(j));
>> }
>> public static <T> T sqr(T x)
>> {
>> return x * x;
>> }
>> }
>>
>> However, I get this when I compile:
>>
>> Test.java:10: operator * cannot be applied to T,T
>> return x * x;
>>
>> ?
>>
>> Thanks,
>>
>> - Dave
>
>
> This is correct behaviour. You are now stating:
>
> T must be of type Object. Type object doesn't have the * operator implemented. Even extending it from Number won't help, since the * operator doesn't work on class instances, only on primitives. To get it work you need quite a hack:
>
> package generic.test;
>
> import sun.reflect.generics.reflectiveObjects.NotImplementedException;
>
> public class Test {
> public static void main(String args[]) {
> Integer i = 100;
> System.out.println(sqr(i));
> int j = 1000;
> System.out.println(sqr(j));
> }
> public static <T extends Number> T sqr(T x) {
> if(x instanceof Integer) {
> return (T)(Number)new Integer(x.intValue() * x.intValue());
> } else if(x instanceof Byte) {
> return (T)(Number)new Byte((byte)(x.byteValue() * x.byteValue()));
> } else if(x instanceof Long) {
> return (T)(Number)new Long(x.longValue() * x.longValue());
> } else if(x instanceof Double) {
> return (T)(Number)new Double(x.doubleValue() * x.doubleValue());
> } else if(x instanceof Float) {
> return (T)(Number)new Float(x.floatValue() * x.floatValue());
> } else {
> throw new NotImplementedException();
> }
> }
> }
>
> Which is, if you ask me, not the best way of using Generics, well, I didn't invent them in Java, and it shows that it is really syntactic sugar.
>
> Regards,
> Sjoerd
Yikes! :)
|
June 19, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sjoerd van Leent | Sjoerd van Leent wrote: > Dave wrote: >> >> public class Test >> { >> public static void main(String args[]) >> { >> Integer i = 100; >> System.out.println(sqr(i)); >> int j = 1000; >> System.out.println(sqr(j)); >> } >> public static <T> T sqr(T x) >> { >> return x * x; >> } >> } >> >> However, I get this when I compile: >> >> Test.java:10: operator * cannot be applied to T,T >> return x * x; >> >> ? >> >> Thanks, >> >> - Dave > > > This is correct behaviour. You are now stating: > > T must be of type Object. Type object doesn't have the * operator implemented. Even extending it from Number won't help, since the * operator doesn't work on class instances, only on primitives. To get it work you need quite a hack: > > package generic.test; > > import sun.reflect.generics.reflectiveObjects.NotImplementedException; > > public class Test { > public static void main(String args[]) { > Integer i = 100; > System.out.println(sqr(i)); > int j = 1000; > System.out.println(sqr(j)); > } > public static <T extends Number> T sqr(T x) { > if(x instanceof Integer) { > return (T)(Number)new Integer(x.intValue() * x.intValue()); > } else if(x instanceof Byte) { > return (T)(Number)new Byte((byte)(x.byteValue() * > x.byteValue())); > } else if(x instanceof Long) { > return (T)(Number)new Long(x.longValue() * x.longValue()); > } else if(x instanceof Double) { > return (T)(Number)new Double(x.doubleValue() * > x.doubleValue()); > } else if(x instanceof Float) { > return (T)(Number)new Float(x.floatValue() * x.floatValue()); > } else { > throw new NotImplementedException(); > } > } > } > > Which is, if you ask me, not the best way of using Generics, well, I didn't invent them in Java, and it shows that it is really syntactic sugar. > > Regards, > Sjoerd Aah, "generics"... I remember a fairly important language person (obviously can't remember the damn name *grumble*) was having a go at .NET 2.0's generics for exactly the same reason. This basically cripples generics in both Java and .NET since it makes them utterly useless for any kind of numerical work: there are no interfaces or base classes for arithmetic operations, which is a complete pain in the arse. Generics in .NET and Java should really be called Object Generics, since it's all but useless for basic types. Of course, D doesn't suffer this problem because its templates simply get expanded until it becomes clear that it can't be done, and THEN it fails. .NET and Java seem to treat templates more like compile-time object casting. I suppose the one advantage that .NET has over Java *and* C++/D is that its templates are compiled without being expanded first. This means that arbitrary libraries can come along and instantiate the templates, even without the source code. AFAIK, Java does what C++ and D do, which is to expand all the templates on compilation. Ah well. Not our problem, after all :) Just another wart to add to Java's list ^_^ -- Daniel -- Unlike Knuth, I have neither proven or tried the above; it may not even make sense. v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP http://hackerkey.com/ |
June 19, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep |
> I suppose the one advantage that .NET has over Java *and* C++/D is that
> its templates are compiled without being expanded first. This means
> that arbitrary libraries can come along and instantiate the templates,
> even without the source code. AFAIK, Java does what C++ and D do, which
> is to expand all the templates on compilation.
Actually, Java doesn't do any expansion at all - all the generic type information is in fact lost upon compilation (so-called "type erasure") and the only purpose generics have is improved type safety in source - you can now finally read/write what a container is supposed to contain..
xs0
|
June 19, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | Daniel Keep wrote:
> Generics in .NET and Java should really be called Object Generics, since
> it's all but useless for basic types.
They call it Generics and not templates for a reason, methinks. I know nothing about C#, but Java's Generics are not equivalent to templates in C++/D at all. For now, the implementation does little more than ensure type-safety at compile time and handle class casts and autoboxing behind the scenes so that you don't have to.
This is one thing, among many, that trips up a lot of C++ programmers when they come to Java. Generics are not templates, the usual operators can't be used on objects (except that String allows + for concatenation), and what have you. Because of this, someone very experienced in C++ is not going to be a good Java programmer without a lot of time and patience. Most don't bother. The languages have two different paradigms and you just can't attack the same problem the same way. There was some grumbling in the Java community when Generics were first introduced, but once people got comfortable with it the noise settled down. It's really better having them than not, though there are still a few week points.
If you ask a Java programmer what Java's warts are, they'll give you a nice long list, but it's going to be very different from the list a C++ programmer would give for the same question. What C++ programmers consider Java warts, many Java programmers see as strengths. It's a different language with a very different paradigm. Java is from Venus and C++ is from Mars.
The thing about D is that it lives on Mars, too, but it's like the first generation child of immigrants from Venus. I think that's why both Java and C++ programmers can get comfortable with it. They can each find something of their own cultures. I'll take Java over C++ any day of the week for most tasks. But D kicks them both in the teeth.
|
June 20, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dave | In article <e747sa$nn9$1@digitaldaemon.com>, Dave says... > >So let's say we want to implement a generic sqr method in Java... How would we do it? I came up w/ this after just a quick look at the spec. to get the syntax right: > >public class Test >{ > public static <T> T sqr(T x) > { > return x * x; > } >} Java Generics are typesafe, you must bound the type with something that implements multiply(). public class Test { public static <T extends Multiplyable<T>> T sqr(T x) { return x.multiply(x); } } Assuming multiplyable is a generic interface that takes a type paramter. |
June 20, 2006 Re: [Proposal] | ||||
---|---|---|---|---|
| ||||
Posted in reply to Daniel Keep | In article <e7583j$2drm$1@digitaldaemon.com>, Daniel Keep says... >I suppose the one advantage that .NET has over Java *and* C++/D is that its templates are compiled without being expanded first. This means that arbitrary libraries can come along and instantiate the templates, even without the source code. AFAIK, Java does what C++ and D do, which is to expand all the templates on compilation. This is incorrect. It is even more complicated than that. Generics are compiled <i>away</i> at compile time and the only thing left at runtime is the erasure (which is the least specific class that represents the type). Generics have very little to do with templates, and to treat them as such is simply going to lead to frustration. You are correct in saying they are mostly for compile time casting, because that's exactly what they do. A different goal than C++ templates. |
Copyright © 1999-2021 by the D Language Foundation