Under Review
over 1 year ago

sdk-4.1.7 constant folds Symbol comparisons incorrectly

With 4.1.7 at -O1 (the default) I tried:

        System.println(:foo == :foo);
        System.println(:foo != :foo);

and got "false, true" as output. That looked wrong, so I tried:

        var x = :foo;
        System.println(x == x);
        System.println(x != x);

and got "true, false". So then for a moment I thought maybe it was "object identity vs object equality" (which would happen if you replaced :foo with "foo", for example). So I tried

        var x = :foo;
        var y = :foo;
        System.println(:foo == :foo);
        System.println(:foo != :foo);
        System.println(x == x);
        System.println(x != x);
        System.println(x == y);
        System.println(x != y);
        System.println(x == :foo);
        System.println(x != :foo);

and got "false, true, true, false, true, false, true, false". So no nothing to do with object identity (no surprise - you can use them in case statements, for example), the compiler is just getting the results wrong when presented with two Symbol literals.

So I tried 4.1.5, and got the expected results. I also tried both 4.1.6 and 4.1.7 at -O0, and also got the expected results. So this is only incorrect at -O1 and -O2 with 4.1.6 and later.

Not a huge deal - you generally wouldn't *write* code like this, but it could show up as a result of copy propagation, for example.

  • and for this reason I don't use symbols at all Slight smile

  • symbol is an object so you should use probably equals

    Well, I explicitly mentioned that I'd thought about that - and then changed the test code to prove thats not what's going on. Yes, if we were using Strings here (eg "foo"), then "foo" == "foo" would be false, while "foo".equals("foo") would be true. But in that case, after  x="foo";y="foo"; x==y would *also* be false. But with symbols thats definitely not what's going on.

    In my example, line 3 (:foo == :foo) prints false, line 5 (x == x) prints true and line 7 (x==y) prints true. The first two *could* be explained by object identity but the third one certainly can't.

    The point is that Symbols behave as value types. They're equal when they refer to the same symbol. You can test this many ways, and my example clearly shows its true *except* for :foo==:foo, which (as I pointed out) is a bug thats been introduced in 4.1.6

  • symbol is an object so you should use probably equals

           var x = :foo1;
            var y = :foo1;
            var z = :foo2;
            System.println(x.equals(y));
            System.println(x.equals(z));
     

    prints true, false....