Quirk with generics

  • Thread starter secret decoder ring
  • Start date
S

secret decoder ring

public interface Foo<T extends Foo<T>> {
T method (T otherFoo);
}

public interface Bar<T extends Bar<T,S>, S extends Foo<S>> {
T method (S foo);
}

public interface Baz<T extends Baz<T>> implements Foo<T>, Bar<T,T> {
// Empty.
}

public class Quux implements Baz<Quux> {
Quux method (Quux other) {
return null;
}

public static void main (String[] args) {
Baz b1 = new Quux();
Baz b2 = new Quux();
System.out.println(b1.method(b2)); // Error
}
}

The error goes away if one adds a seemingly-redundant

T method (T other);

to interface Baz.
 
R

Roedy Green

public interface Baz<T extends Baz<T>> implements Foo<T>, Bar<T,T> {
// Empty.
}

implements means provides the concrete methods for. An interface
can't implement anything can it, just extend? Language lawyers?
--
Roedy Green Canadian Mind Products
http://mindprod.com
"Humanity is conducting an unintended, uncontrolled, globally pervasive experiment
whose ultimate consequences could be second only to global nuclear war."
~ Environment Canada (The Canadian equivalent of the EPA on global warming)
 
R

RedGrittyBrick

Roedy said:
implements means provides the concrete methods for. An interface
can't implement anything can it, just extend? Language lawyers?


C:\> type Q.java
public class Q {
interface F {
public void m();
}
interface G implements F {
}
}

C:\> javac Q.java
Q.java:5: '{' expected
interface G implements F {
^
1 error

C:\> javac -version
javac 1.6.0_02


At the same point, Eclipse says
Syntax error on token "implements", extends expected.

As we can see, this has nothing to do with Generics.
 
A

Andreas Leitgeb

Roedy Green said:
implements means provides the concrete methods for.
An interface can't implement anything can it, just extend?

Entirely correct.

Btw., the .class-file format stores the list of an interface's
*extended* interfaces at exactly the same place as a class's
*implements*-list :) That means nothing -- except that this
distinction is made only on the level of the Java language, but
(for practical reasons) not at JVM level.
 
L

Lew

RedGrittyBrick said:
C:\> type Q.java
public class Q {
interface F {
public void m();
}
interface G implements F {
}
}

C:\> javac Q.java
Q.java:5: '{' expected
interface G implements F {
^
1 error

C:\> javac -version
javac 1.6.0_02


At the same point, Eclipse says
Syntax error on token "implements", extends expected.

As we can see, this has nothing to do with Generics.

You also don't need to be a "language lawyer" for this bit of elementary Java
knowledge. One could refer to the tutorials or the JLS to clear this up in a
jiffy.
 
R

Roedy Green

You also don't need to be a "language lawyer" for this bit of elementary Java
knowledge. One could refer to the tutorials or the JLS to clear this up in a
jiffy.

That is correct. I often affect a way of speaking intended to make
newbies welcome to speak up. You usually like to do the opposite. You
get some perverse pleasure in putting newbies down. You usually
behave like some dominant meerkat. Grow up!


--
Roedy Green Canadian Mind Products
http://mindprod.com
"Humanity is conducting an unintended, uncontrolled, globally pervasive experiment
whose ultimate consequences could be second only to global nuclear war."
~ Environment Canada (The Canadian equivalent of the EPA on global warming)
 
S

secret decoder ring

Roedy said:
implements means provides the concrete methods for. An interface
can't implement anything can it, just extend? Language lawyers?

Shit, I meant extends. I was paraphrasing the actual code, to simplify
it and wash it of any proprietary hints or details.
 
A

Arne Vajhøj

secret said:
Shit, I meant extends. I was paraphrasing the actual code, to simplify
it and wash it of any proprietary hints or details.

It is better for everybody to post actual code tested. Not necessarily
the real code with context - just what it takes to show the
problem - but real code.

Arne
 
L

Lew

Roedy said:
That is correct. I often affect a way of speaking intended to make
newbies welcome to speak up. You usually like to do the opposite. You
get some perverse pleasure in putting newbies down. You usually
behave like some dominant meerkat. Grow up!

Oh, shut up, Roedy. I was pointing out additional places people could go to
research these things, lest people be put off by *your* implication that one
needs to be a language lawyer to understand things. It is my intention to
make it easier for people by letting them know that things are simpler than
*you* implied.

So get that bug out of your ...
 
S

secret decoder ring

Arne said:
It is better for everybody to post actual code tested. Not necessarily
the real code with context - just what it takes to show the
problem

That is exactly what I did. The code was hand-copied (and hand-edited)
from actual code. Perhaps I did not make that clear.
 
L

Lew

secret said:
That is exactly what I did. The code was hand-copied (and hand-edited)
from actual code. Perhaps I did not make that clear.

No worries - transcription error. The danger is that some folks might've not
realized that it was erroneous, and so the corrections were necessary.

Arne's advice
> It is better for everybody to post actual code tested.
was meant to exclude hand-copying. He was referring to copy-and-paste from
real code. So it wasn't exactly what you did. However, I disagree with
Arne's advice slightly. Many folks do post non-real code, and frequently get
mistakes as a result. If you mark the code as "untested nor compiled", you
warn people that such transcription errors (or worse) may have occurred. I
only disagree slightly, because actually he's right - it really is better to
post real code, except sometimes the snippet is so short that it's easier to
be lazy and take the risk of making mistakes.

The beauty of this group is that people will catch the error most of the time.
Happens to me a lot.
 
S

secret decoder ring

Lew said:
Arne's advice
was meant to exclude hand-copying. He was referring to copy-and-paste
from real code.

Copy-and-paste is not always reasonable to expect. In this instance, for
example, to do it by copy-and-paste would have entailed copying from
four separate source files, then doing quite a lot of hand-deleting,
since the actual classes and interfaces involved are considerably larger
than the distilled-down examples. It would have easily taken ten or more
times as long.

And it would have been very easy to introduce an error, for example by
deleting something essential by accident while trimming the irrelevant
or by leaving in a reference to yet another class or interface that
would no longer resolve.

Most likely, instead of one minor keyword substitution (where the
intended meaning, to humans, was not even affected) there would have
been two or more errors, possibly more serious.
I only disagree slightly, because actually he's right - it really is
better to post real code, except sometimes the snippet is so short

Like this time? Twenty lines, including one only-a-comment line and one
blank line inside a class. Three of the classes only three lines long each.

The original source runs to dozens of lines (a lot of it Javadoc, of
course) per interface and a couple of hundred in the concrete class.
Copying that and then deleting most of it and editing the rest would
probably have resulted in a higher error rate, as well as consumed more
time, than writing out "the gist" longhand.
The beauty of this group is that people will catch the error most of the
time. Happens to me a lot.

What I find disturbing is that nobody could see past it to the matter
actually at issue, which still does not seem to have been addressed. The
pedantic focus on the implements-vs.-extends issue completely derailed
the thread and the actual matter of original interest got completely
sidelined.

This is doubly odd in light of the observation that this is a nonlinear
medium where both could be addressed, concurrently, in disparate
branches, even by separate people.

I therefore have to wonder if there are other motives to the
fault-finding behavior observed than purely to altruistically alert
others that might not be as familiar with Java's normal usage of the
extends and implements keywords, given how eagerly that was pursued --
indeed, it was pursued *so* eagerly that it was apparently pursued to
the exclusion of *any* pursuit of the intended topic of the thread.
 
M

Mike Schilling

secret said:
Copy-and-paste is not always reasonable to expect. In this instance,
for example, to do it by copy-and-paste would have entailed copying
from four separate source files, then doing quite a lot of
hand-deleting,
since the actual classes and interfaces involved are considerably
larger than the distilled-down examples. It would have easily taken
ten or more times as long.

The ideal is for the poster to make the "distilled-down examples"
actually work, and then cut-and-paste *them*. I, at least, have
limited time (and even more limited patience) for looking at code
samples; once something fails to compile, I'll rarely do anything
further with it beyond cursing a bit. Posting a question here is
asking people to help you with no reward other than that of doing a
good deed (and in some cases, yours included, looking at an
interesting issue); you want to make it easy for them.
 
H

Harold \Curly\ Phillips

secret decoder ring said:
Copy-and-paste is not always reasonable to expect. In this instance, for
example, to do it by copy-and-paste would have entailed copying from four
separate source files, then doing quite a lot of hand-deleting, since the
actual classes and interfaces involved are considerably larger than the
distilled-down examples. It would have easily taken ten or more times as
long.

Bullshit, the following can be cut and pasted in one chunk between a Java
editor and a newsreader. You should have made the tiny effort involved
rather than expecting dozens of potential helpers to each repeat this work
for you.

public class AllegedGenericsQuirk {

public interface Foo<T extends Foo<T>> {
public T method (T otherFoo);
}

public interface Bar<T extends Bar<T,S>, S extends Foo<S>> {
public T method (S foo);
}

public interface Baz<T extends Baz<T>> extends Foo<T>, Bar<T,T> {
// Empty.
}

public class Quux implements Baz<Quux> {
public Quux method (Quux other) {
return null;
}
}

public static void main (String[] args) {
Baz<Quux> b1 = new Quux();
Baz<Quux> b2 = new Quux();
System.out.println(b1.method(b2)); // Error
}

}
What I find disturbing is that nobody could see past it to the matter
actually at issue, which still does not seem to have been addressed. The
pedantic focus on the implements-vs.-extends issue completely derailed the
thread and the actual matter of original interest got completely
sidelined.

Your mistakes have consequences.
 
A

Arne Vajhøj

secret said:
That is exactly what I did. The code was hand-copied (and hand-edited)
from actual code. Perhaps I did not make that clear.

No.

You take your real code, edit it down to the what is needed
to demonstrate the problem, compile and possible run it to ensure that
it still has the problem and then copy paste the code unedited.

If you "hand-edit" it in the news group post, then all types
of problems may arise, which will cause people to spend the
time on those problems instead of what you really are interested in.

Arne
 
A

Arne Vajhøj

Lew said:
No worries - transcription error. The danger is that some folks
might've not realized that it was erroneous, and so the corrections were
necessary.

Arne's advice
was meant to exclude hand-copying. He was referring to copy-and-paste
from real code. So it wasn't exactly what you did. However, I disagree
with Arne's advice slightly. Many folks do post non-real code, and
frequently get mistakes as a result.

It happens frequently with answers. I think it is bad style
for questions.
If you mark the code as "untested
nor compiled", you warn people that such transcription errors (or worse)
may have occurred. I only disagree slightly, because actually he's
right - it really is better to post real code, except sometimes the
snippet is so short that it's easier to be lazy and take the risk of
making mistakes.

The beauty of this group is that people will catch the error most of the
time. Happens to me a lot.

The problem is when people think the transcription error was
the real error.

Arne
 
S

secret decoder ring

Mike said:
The ideal is for the poster to make the "distilled-down examples"
actually work, and then cut-and-paste *them*.

You're joking. That would have required:
* Creating a new project in my IDE.
* Configuring this.
* Creating a new Java package within the project.
* Creating four new source files within the package.
* All of the copying, pasting, and editing noted above.
* A second round of copying, pasting, and editing (to remove auto-added
top-of-file comments).
* Deleting the project, its package, and the four source files.
That could easily take half an hour or more, and requires messing with
my IDE potentially disturbing the way I'd had it (current project/recent
files, etc.).

How utterly ridiculous.

The ideal is also that every software program have a formal proof of
correctness, but we live in the real world where people have limited
time, energy, and resources.
 
S

secret decoder ring

Arne said:

Yes. The code was hand-copied (and hand-edited) from actual code.

By saying "no" there, you are pretty much accusing me of lying, since I
surely ought to have known and correctly remembered how I'd copied
something that I'd copied only hours ago, and therefore would not have
been mistaken. If what I said was not true, but I knew the truth, it
would mean that I was lying.

Of course, I was not lying.

Your post, with its accusation of lying, is nearly as rude as Harold
Phillips' was. (He also accused me of lying, but much more explicitly
and scatologically, and in reference to a different supposed "lie".)

My response to you is therefore more or less the same as my response to him:

Please go away, and don't come back until you've learned some manners.
 
S

secret decoder ring

Steven said:
That error is:

Quux.java:21: reference to method is ambiguous, both method method(S) in Bar and method method(T) in Foo match
System.out.println(b1.method(b2)); // Error
^

Ah, the first post that actually is related to the true purpose of this
thread. Thank you.
b1 and b2 are declared as Baz, without generics. By erasure, they must
have two methods on them:

Foo method(Foo);
Bar method(Foo);

Baz extends Foo, so b2 can be regarded as a Foo, hence either of these
methods matches the call. There is no way to decide which one you mean,
so the compiler issues an error message about the ambiguity.

Well ... except that if something implements both interfaces, surely the
compiler should know that the above methods must be one and the same,
seeing as they have the same signature and will exist in the same class?
The return type would obviously have to be Bar in order to satisfy both
interfaces, but this should be enough for the compiler to infer that a
single method Bar method(Foo) in an implementation of Baz will be needed
to make that implementation satisfy its requirements, and that single
method is then the one to call.
So, by erasure, Baz now has:

Baz method(Baz);

...which is more specific than the others, so the compiler can resolve
the call to it.

Yes, it just seemed to me that the compiler can infer such a method must
exist in a Baz implementation, without needing it spelled out.

The ambiguity rules make sense with concrete methods, ones with
implementations that may differ, but with abstract methods that have
identical (after erasure) signatures, such as "method(Foo)", it seems
that the ambiguity is really "all in the compiler's head", so to speak.
 

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

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,077
Latest member
SangMoor21

Latest Threads

Top