6

I have a source-code generator that risks generating the following type of code (just an example):

public class Outer {
    public static final Object Inner = new Object();

    public static class Inner {
        public static final Object Help = new Object();
    }

    public static void main(String[] args) {
        System.out.println(Outer.Inner.Help);
        //                             ^^^^ Cannot access Help
    }
}

In the above example, Inner is ambiguously defined inside of Outer. Outer.Inner can be both a nested class, and a static member. It seems as though both javac and Eclipse compilers cannot dereference Outer.Inner.Help. How can I access Help?

Remember, the above code is generated, so renaming things is not a (simple) option.

Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • 2
    Related: http://stackoverflow.com/questions/8130060/static-classes-in-java-something-is-being-shadowed – aioobe May 28 '12 at 10:26
  • Are you sure that this doesn't work as-is? It looks like what I'd expect to work. – Louis Wasserman May 28 '12 at 10:28
  • It's a very lucky circumstance that you got it to work at all. You are basically accessing the static field by qualifying it with an instance of that type. This is why we have Java naming conventions, to prevent such clashes. – Marko Topolnik May 28 '12 at 10:28
  • "ambiguous" how? `Inner` is **not** an inner class, by definition, because it's static. – CodeClown42 May 28 '12 at 10:28
  • @goldilocks So it's a nested class. It doesn't change the point. – Marko Topolnik May 28 '12 at 10:29
  • 1
    @LukasEder, Your workaround doesn't seem to work for me. I get a class cast exception. – aioobe May 28 '12 at 10:29
  • @MarkoTopolnik: okay, but then the distinction "both an inner class and a static member" 1) does not make sense, 2) is false. Member `Inner` is just an object. – CodeClown42 May 28 '12 at 10:30
  • @aioobe I'm testing in Eclipse Helios, Java 6, works for me. – Marko Topolnik May 28 '12 at 10:31
  • @goldilocks OP has a naming clash problem. It's a real problem. Maybe his wording isn't JLS-perfect, but the problem is clear. – Marko Topolnik May 28 '12 at 10:32
  • 3
    I personally would do one of three things: (1) rule illegal any input that results in this code; (2) adopt a name mangling scheme so that the two things always end up having different names; (3) ensure that `Inner` (the variable) is always of type `Inner` (the class). – NPE May 28 '12 at 10:33
  • @MarkoTopolnik: I agree 100%, I just wanted to point the language problem out, because they often indicate a misconception. I'd say the clash is not a matter of "ambiguity" it is just a mistake, period. – CodeClown42 May 28 '12 at 10:33
  • @LouisWasserman: Yes, I'm sure – Lukas Eder May 28 '12 at 10:33
  • @goldilocks: I changed the wording from "inner" to "nested" – Lukas Eder May 28 '12 at 10:34
  • @aix (and others): Yes, I'd prefer to rename things. But let's assume renaming is not an option (as this is about generated code) – Lukas Eder May 28 '12 at 10:35
  • But do you control the generation of the code? If yes, then aix's approach is valid. Especially because Java is unescapably vulnerable to naming clashes. – Marko Topolnik May 28 '12 at 10:36
  • @LukasEder: It's your question, so you are of course free to rule things out. :-) However, I don't understand what's so hard (or undesirable) about an automatic name mangling scheme. – NPE May 28 '12 at 10:36
  • 1
    Ie, you have a generator that generates "worst practice" -> "invalid" code? – CodeClown42 May 28 '12 at 10:37
  • 1
    @MarkoTopolnik, what have I misunderstood? ([link](http://ideone.com/fNGPx)). – aioobe May 28 '12 at 10:38
  • @aioobe Ha ha, cool, you actually **ran** it! Yes, that settles the misunderstanding -- when I said "works" I only meant "compiles" :) – Marko Topolnik May 28 '12 at 10:39
  • @MarkoTopolnik (and others): Yes I control the generation of the code. I want to figure out whether this is really "worst practice" in case of which I'll find a mangling scheme. The collision will be quite rare. But before I think about that, I want to understand that aspect of the Java language – Lukas Eder May 28 '12 at 10:40

2 Answers2

6

The following works for me (with a warning about accessing static members in a non-static way):

public static void main(String[] args) {
    System.out.println(((Inner)null).Help);
}
NPE
  • 486,780
  • 108
  • 951
  • 1,012
1

How about

public static void main(String[] args) {
    System.out.println(new Inner().Help);
}
Robert
  • 8,406
  • 9
  • 38
  • 57
  • 1
    That would work, yes. But I don't want to instanciate `Inner` in order to access a static member of it – Lukas Eder May 28 '12 at 10:32
  • I appreciate that it looks unclean, but it is about a simple code as you are going to get, given the ambiguity. I doubt the cost of the instantiation would be much. – Robert May 28 '12 at 10:36
  • 1
    OK, I agree. As a workaround, it would be OK. Although I'd still prefer the casting (if that is a formally correct solution) – Lukas Eder May 28 '12 at 10:37