Java Generics: limitations?

H

Hung Jung Lu

Hi,

I am trying out the beta release of Java generics. (Java 1.5). I have:

class Utils<T extends A> {
public void incx(T me) {
me.x += 1;
}
}

class A {
public int x;
Utils<A> utils;

void run() {
x = 1;
utils = new Utils<A>();
utils.incx(this);
System.out.println(this.x);
}

public static void main(String[] args) {
A a = new A();
a.run();
}
}

It works fine. But if T is not specified as extension of A:

class Utils<T> {
public void incx(T me) {
me.x += 1; // error: cannot find symbol
}
}

this will throw an error. This is kind of disappointing, because in
C++ the template parameter T could be anything. (The address shifts
are calculated intelligently during type-safe compilation.) In Java,
if T does not have a specific parent class, the compiler won't know
what attributes it may have.

Question:

(a) Is this limitation is only temporary in the beta release of
generics?
(b) Is there a way out of this limitation?
(c) Or are Java generics just not very generic at all?

regards,

Hung Jung
 
D

David Forslund

I don't understand how the later case could work. How can it reference
the variable x in T, if such a variable doesn't exist? If it is to
work for any T then one could create a class without the variable x.
Then the error would have to occur at runtime. Is that what you are
looking for? This "limitation" seems reasonable to me because the
compiler is trying to check for errors. If you want to perform
operations on the template class, it seems reasonable that you should
have to know something about its signature to avoid a runtime error. I
basically view generics in Java as trying to move runtime errors to
compilation errors.

Dave
 
H

Hung Jung Lu

David Forslund said:
I don't understand how the later case could work. How can it reference
the variable x in T, if such a variable doesn't exist?

It works in C++. Basically the compiler, at compile time, identifies
what x means. Some people argue it's pre-compile time. Anyway, you may
or may not like how C++ works. But the word "generics" means exactly
that: you don't need to know the specifics. That is also why "generic
programming" is meaningless in weakly-typed languages like Python,
because everything there is generic!
Then the error would have to occur at runtime.

Depends on the language. In weakly-typed languages like Python, yes,
at runtime. In type-safe, strongly-typed languages like C++, at
compile time. C++ templates are pretty much like macros. Per each
usage of the template, a whole new class (or function) binary code is
created, with the right offsets for the right variables like x. So C++
is able to detect problems at compile time.
looking for? This "limitation" seems reasonable to me because the
compiler is trying to check for errors.

You are correct in saying about the checking of error. But if Java
cannot go around and do something similar to what I've said, then Java
generics cannot be called generics, at all. As it turns out, Java has
its way out of this limitation by using getters/setters. This has been
discussed in detail in the Java's Adding Generics developer's forum,
now, by myself and others.

All in all, generics are a bit difficult to use in Java, especially
when they are compounded with multiple inheritance (which in Java is
through containment + delegation). When you hit upon these advanced
designs, you'll understand what I mean. It's surely not for everybody
to understand or worry about it.
If you want to perform
operations on the template class, it seems reasonable that you should
have to know something about its signature to avoid a runtime error. I
basically view generics in Java as trying to move runtime errors to
compilation errors.

Correct.

Here is part of what I wrote in the Adding Generics forum. As others
have pointed out, the HasXY interface is not necessary, and could be
replaced by HasX & HasY in the extends statment.

--------------------
.....

Utils<String> will throw an error. That's the behavior in C++. I
already said C++ has type-safe templates. To others, I already figured
out the way out in Java. See sample code below. Basically, Java does
not allow virtual data fields. Not at runtime, not in generics. C++
does not allow virtual data fields at runtime, but it allows virtual
data fields in templates. Python allows virtual data fields at any
moment. To mimic virtual data fields, Java has to use getters/setters.

My following example is not concise, but it does show the general case
on how to implement utility template classes that operate on target
classes that are bloodline-unrelated. Moreover, it shows in general
how to implement more and more utility template classes. Basically,
per each utility class, you have to define its workspace interface
(HasXY in the example) first. Then, implement the workspace interface
in the target classes. Multiple overlapping workspace interfaces are
OK. That's the essence.

regards,

Hung Jung
-----------------------------------

interface HasX {
public int getX();
public void setX(int value);
}

interface HasY {
public int getY();
public void setY(int value);
}

interface HasXY extends HasX, HasY {
}

class UtilX<T extends HasX> {
public void incX(T me) {
int x = me.getX();
x += 1;
me.setX(x);
}
}

class UtilY<T extends HasY> {
public void doubleY(T me) {
int y = me.getY();
y *= 2;
me.setY(y);
}
}

class UtilXY<T extends HasXY> {

public void addX2Y(T me) {
int x = me.getX();
int y = me.getY();
y += x;
me.setY(y);
}

}

class A implements HasX, HasY, HasXY {

public int x;
public int y;
UtilX<A> utilX;
UtilY<A> utilY;
UtilXY<A> utilXY;

public int getX() {
return x;
}

public void setX(int value) {
this.x = value;
}

public int getY() {
return y;
}

public void setY(int value) {
this.y = value;
}

void run() {
x = 1;
y = 2;
utilX = new UtilX<A>();
utilY = new UtilY<A>();
utilXY = new UtilXY<A>();
utilX.incX(this);
utilY.doubleY(this);
utilXY.addX2Y(this);
System.out.println("x=" + x);
System.out.println("y=" + y);
}

public static void main(String[] args) {
A a = new A();
a.run();
B b = new B();
b.run();
}

}

class B implements HasX, HasY, HasXY {

public int x;
public int y;
UtilX<B> utilX;
UtilY<B> utilY;
UtilXY<B> utilXY;

public int getX() {
return x;
}

public void setX(int value) {
this.x = value;
}

public int getY() {
return y;
}

public void setY(int value) {
this.y = value;
}

void run() {
x = 2;
y = 3;
utilX = new UtilX<B>();
utilY = new UtilY<B>();
utilXY = new UtilXY<B>();
utilX.incX(this);
utilY.doubleY(this);
utilXY.addX2Y(this);
System.out.println("x=" + x);
System.out.println("y=" + y);
}

}
 
J

John C. Bollinger

Hung said:
It works in C++. Basically the compiler, at compile time, identifies
what x means. Some people argue it's pre-compile time.

Apparently, then, it only works as long as T is not structurally
modified between compilation of Utils and runtime. And only if both are
compiled by the same compiler on the same OS and class of hardware. And
if it fails because one of those restrictions does not hold, then you
get erroneous results without much clue as to why.
Anyway, you may
or may not like how C++ works.

Apparently I don't. But I already knew that.
But the word "generics" means exactly
that: you don't need to know the specifics.

And Java's new generics provide that. You don't need to know the
specifics. But you do need to know the broad outlines. That's the case
in C++, too, but C++ doesn't enforce it as formally. In other words,
what if class T in your example didn't have a field "x"? Even C++
generics place requirements on the classes of objects they are applied
to; they don't, however, advertise exactly what those requirements are.
Java's implementation of generics makes it explicit, and in doing so
provides better binary compatibility, better documentation,
cross-platform compatibility, etc..

[...]
You are correct in saying about the checking of error. But if Java
cannot go around and do something similar to what I've said, then Java
generics cannot be called generics, at all. As it turns out, Java has
its way out of this limitation by using getters/setters. This has been
discussed in detail in the Java's Adding Generics developer's forum,
now, by myself and others.

I think you have a somewhat odd view of generics, apparently based on
your C++ experience. Java generics are not as different as you claim.
As I discussed above, few "generic" procedures are in fact so generic
that they can work with any object at all. For those that are you can
always base them on type Object. For the rest, Java allows (requires,
in fact) that the requirements be explicitly expressed and that
compliance with them be explicitly expressed. I am fully satisfied with
that approach, and indeed, it seems better attuned to the Java way of
doing things in general.
All in all, generics are a bit difficult to use in Java, especially
when they are compounded with multiple inheritance (which in Java is
through containment + delegation). When you hit upon these advanced
designs, you'll understand what I mean. It's surely not for everybody
to understand or worry about it.

Oh, forgive me. I didn't realize that I was carrying on a discussion
with an _advanced_ programmer. What I thought were blind faith in the
C++ language design, rigidity, and lack of clear sight must instead be
superior intelligence, vast experience, and sublime transcedental
comprehension of all aspects of software design and development. 8^|
Correct.

Here is part of what I wrote in the Adding Generics forum. As others
have pointed out, the HasXY interface is not necessary, and could be
replaced by HasX & HasY in the extends statment.

[elided]

And am I supposed to be impressed? Surprised? Annoyed? It's exactly
the approach I would have assumed would be appropriate. As I wrote,
Java requires that the underlying contracts be explicit. I see that as
an advantage.

But wait, I'm just too ignorant to know what's best for me. 8^|


John Bollinger
(e-mail address removed)
 
T

Tor Iver Wilhelmsen

It works in C++.

It works in C++ because a C++ template isn't really "code" until it's
used. They have a closer realtion to the preprocessor than to the
compiler proper.

Java templates _are_ code/real classes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

generics puzzle 57
Generics ? 14
Java generics limitations? 9
limitations of Class.forName 4
Generics 24
generics:< ? >vs.< T > 13
How to draw shapes by using mouse 1
Generics 12

Members online

Forum statistics

Threads
473,995
Messages
2,570,228
Members
46,817
Latest member
AdalbertoT

Latest Threads

Top