Why can't the eclipse java compiler (ecj) compile this?
Asked Answered
D

1

10

I have the following code:

package test;

import java.util.stream.IntStream;

public class A {
    public static void main(String[] args) {
        IntStream.range(0, 10).mapToObj(n -> new Object() {
            int i = n;
        }).mapToInt(o -> o.i).forEachOrdered(System.out::println);
    }

}

This code works fine when compiled with javac 1.8.0_101, and produces the number 0 to 9 as expected.

But when I use this code in eclipse, it tells me that at o.i:

i cannot be resolved or is not a field

And producing an error when executing this:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    i cannot be resolved or is not a field

    at test.A.main(A.java:9)

Why do I need to use javac to compile this code?
And how do I get eclipse to behave?

Edit:

I did some tests and it works in ecj as long as I don't create the instance in a lambda:

package test;

import java.util.Optional;
import java.util.function.Supplier;

public class B {
    public static void main(String[] args) {

        // This works fine:
        System.out.println(new Object() {
            int j = 5;
        }.j);

        // This also
        System.out.println(trace(new Object() {
            int j = 5;
        }).j);

        // Also no problem
        System.out.println(unwrapAndTrace(Optional.of(new Object() {
            int j = 5;
        })).j);

        // Lambdas work:
        System.out.println(((Supplier & Serializable) () -> new Object()).get()); 

        // This doesn't work.
        System.out.println(invokeAndTrace(() -> new Object() {
            int j = 5;
        }).j);
    }

    public static <T> T trace(T obj) {
        System.out.println(obj);
        return obj;
    }

    public static <T> T invokeAndTrace(Supplier<T> supplier) {
        T result = supplier.get();
        System.out.println(result);
        return result;
    }

    public static <T> T unwrapAndTrace(Optional<T> optional) {
        T result = optional.get();
        System.out.println(result);
        return result;
    }


}
Damiondamita answered 23/6, 2018 at 1:12 Comment(7)
I know, I could use Integer, but that's not the point. And i is visible - not private, same package. But if you like, you can of course make i public. Doesn't matter.Damiondamita
When you create a new Object() class, the variable i isn't part of the base Object class. It isn't a class variable. Create a new class maybe called B with the class variable i as an int in the B class. Then you can assign the n as you pass it in. Not sure why it compiled before however it seems as though the base class Object doesn't have any class variables in it for you to assign to. It would seem that the instance that you are creating of object has int i only for the scope of the braces. Basically int i is a local method variable.Punchdrunk
What is version of eclipse?? Kepler and prev - work with java 1.7, so it wouldn't compile. You need Luna or latest (Mars)Typecase
Eclipse can compile lambdas, no problem there. If I change o.i to 123 then Eclipse will compile it.Damiondamita
Maybe default language level is set to 1.6 (aka Java 6) or 1.7 (Java 7), so lambdas are not legalEdisonedit
Nope, lambdas work fine. I'm using Eclipse IDE for Java Developers Version: Oxygen.3a Release (4.7.3a) Build id: 20180405-1200 - Should be recent enough.Damiondamita
@SergeBreusov, for the records: while Luna indeed introduced support for Java 8, none of the versions you mention are recent in 2018. Indeed, Oxygen.3a is the latest released version -- until next week when Photon will be published.Puissance
P
8

This is a bug in ecj, recently reported also as Bug 535969.

In a nutshell: to avoid a hard technical problem, the compiler drops the anonymous class during type inference, replacing it with its super class (in specific situations, not always). With this, the result of mapToObj() is seen as Stream<Object> where indeed the anonymous class should be used. Original assessment, that this information loss would be OK (because nobody can mention the anonymous class) is proven wrong by the example in this question.

EDIT: The bug has been fixed via the pre-existing report Bug 477894

Puissance answered 23/6, 2018 at 13:42 Comment(4)
Compiler bug? Well... I was always told "It's not the compilers fault, it's your fault. The compiler is battle tested and it is far more likely that you did something wrong". Yeah, sure.Damiondamita
I believe the bottom of my question makes a good test case. BTW, will Photon fix it?Damiondamita
It's fixed, just too late for Photon, but don't worry, the next release is just 3 months away.Puissance
Thanks for the follow up. I'll look forward to do that kind of thing (C# can do that for a while - and with var things get even crazier).Damiondamita

© 2022 - 2024 — McMap. All rights reserved.