Inner classes and method signatures

B

Bjorn-Ove.Heimsund

Hi,

I've got an issue where an inner class has a method of the same name
(but different signature) as that of its enclosing class:

public class Foo {
class FooBar {
void foo(int i) { foo(i,i); }
}
int foo(int i, int j) { return i+j; }
}

Compiling this gives an error, indicating a clash between
Foo.foo(int, int) and Foo.FooBar.foo(int). Changing either method name
removes this issue. I've verified this on both vanilla javac and jikes.

I've perused the Java Language Specification, but haven't found a reason
why my code snippet does not compile. Does anyone know why the compiler
should not accept this?
 
D

David Zimmerman

Hi,

I've got an issue where an inner class has a method of the same name
(but different signature) as that of its enclosing class:

public class Foo {
class FooBar {
void foo(int i) { foo(i,i); }
}
int foo(int i, int j) { return i+j; }
}

Compiling this gives an error, indicating a clash between
Foo.foo(int, int) and Foo.FooBar.foo(int). Changing either method name
removes this issue. I've verified this on both vanilla javac and jikes.

I've perused the Java Language Specification, but haven't found a reason
why my code snippet does not compile. Does anyone know why the compiler
should not accept this?

I agree it's a puzzle. If you need a work around
Foo.this.foo(i,i);
will Do the Right Thing (tm)

However, you're probably just interested in the puzzle
 
C

Chris Smith

I've got an issue where an inner class has a method of the same name
(but different signature) as that of its enclosing class:

public class Foo {
class FooBar {
void foo(int i) { foo(i,i); }
}
int foo(int i, int j) { return i+j; }
}

Compiling this gives an error, indicating a clash between
Foo.foo(int, int) and Foo.FooBar.foo(int). Changing either method name
removes this issue. I've verified this on both vanilla javac and jikes.

Bjorn,

I also verified and got the error on Eclipse's compiler. I then checked
the JLS and discovered (to my surprise) that you *should* get an error
here.

To be clear, the error is not that there's a conflict when defining
foo(int, int) in FooBar versus foo(int) in Foo. It's that the method
call to foo(i, j) doesn't match the signature for Foo(int). You might
expect (as I expected until I read the language specification) that
foo(i, j) would be interpreted as a call to foo(int, int) in the
enclosing instance of Foo... but it ain't so.

The relevant section of the JLS is 15.12.1. Specifically, this case is
handled by the first bullet of the bulleted list, and the first
subbullet of that. What it says, basically, is that the method
invocation is resolved by name only, and not by parameters. So the
compiler decides that you're calling FooBar.foo before it even looks at
parameters; then, later, it realizes that the parameters don't match and
spits out an error.

This is not just a quirk of some compiler; it's specified that way, and
a compiler that does otherwise would be compiling some other language
besides Java!

--
www.designacourse.com
The Easiest Way to Train Anyone... Anywhere.

Chris Smith - Lead Software Developer/Technical Trainer
MindIQ Corporation
 
C

Chris Uppal

public class Foo {
class FooBar {
void foo(int i) { foo(i,i); }
}
int foo(int i, int j) { return i+j; }
}

I've perused the Java Language Specification, but haven't found a reason
why my code snippet does not compile. Does anyone know why the compiler
should not accept this?

I think the compiler is right. It's somewhat surprising, but it does seem to
follow from the JLS2:

The expression foo(i,i) is a method invocation, so the compiler must first find
the "Class or Interface to Search". According to the rules in 15.12.1:
If it is a simple name, that is, just an Identifier, then the name of the
method is the Identifier. If the Identifier appears within the scope (§6.3)
of a visible method declaration with that name, then there must be an
enclosing type declaration of which that method is a member. Let T be
the innermost such type declaration. The class or interface to search is T.
In this case the Identifier is "foo" and the type T is the inner class
Foo.FooBar.

Then the second step is to determine the method signature and then (15.12.2.1)
"Find Methods that are Applicable and Accessible":
The class or interface determined by the process described in §15.12.1 is
searched for all method declarations applicable to this method invocation;
method definitions inherited from superclasses and superinterfaces are
included in this search.
Note that although inherited methods are included in this list, methods from
enclosing classes are *not*. In this particular case the list will consist
only of the method Foo.FooBar.foo(int) and that does not match the required
signature. Hence the compiler rejects the expression.

Or at least, that's how I read it.

-- chris
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top