3

I would appreciate someone explaining to me why the following is true:

def t = "test"
assert [test: 1] == ["test": 1]  // 1. expected
assert ["$t": 1] != ["test": 1]  // 2. unexpected
assert ["$t": 1] != [test: 1]    // 3. unexpected
assert ["$t": 1] == ["$t": 1]    // 4. expected
println ["$t": 1]                // output: [test: 1]
println ["test": 1]              // output: [test: 1]

I don't understand why there is the inequality for results #2 and #3.

I ran into this in writing a test where the key get dynamically created in the code, but given the test conditions I know it should be the string "test". The problem is that the returned "appears" correct but is not considered equal. And I don't understand why.

Further, the following "works":

def t = "test"
def odd = ["$t": 1]
assert !odd["$t"]
assert !odd.test
assert !odd["test"]
assert !odd."$t"
println odd           // output: [test: 1]

def d = new Date()
def t2 = "$t"
def odd2 = [(t2): 1, (d): 2]
assert odd2[d] == 2
assert !odd2[d.toString()]
assert !odd2[t2]        // expected 1
odd2.put(t2, 3)
println odd2            // output: [test: 3, /* date#toString */: 2]
assert odd.getAt(d) == 2
assert !odd2.getAt(t2)  // expected 3
Simon
  • 521
  • 2
  • 9
  • 1
    And if someone can think of a better title? "Why does groovy map key evaluation make no sense?" – Simon Mar 05 '14 at 00:57

1 Answers1

5

Add these 2 lines

assert "$t".class.simpleName == 'GStringImpl'
assert t.class.simpleName == 'String'

or just

println "$t".class
println t.class

after the first line, you will be able to understand why. :)

If you actually want to use the value of t then you should use as:

assert [(t): 1] == ["test": 1] //use (t) to use the variable value as key
assert [(t): 1] == [test: 1]
assert [(t): 1] != ["$t": 1]

UPDATE

//String key as before, hence encouraged to use (t) instead of GStringImpl
def odd = [("$t".toString()): 1]

assert odd["$t"]
assert odd.test
assert odd["test"]
assert odd."$t"

//Equality by reference and by value in Groovy
assert "$t" == "test" //Value Equality == overridden in Groovy
assert !"$t".is("test") //Object Reference equality equivalent to == in Java
dmahapatro
  • 49,365
  • 7
  • 88
  • 117
  • Okay. So this is clearly correct. But I would like to explore it slightly further...Since 'assert "$t" == "test"' is true, but when evaluated as a Map keys they are not equal. And why does the odd["$t"] give null rather than the 1 I would expect? – Simon Mar 05 '14 at 01:34
  • Responding to your edit: I didn't know about that syntax being available. I assume then that you can have "any" expression on the left of the colon? As long as it ends with a #toString method...going to experiment. – Simon Mar 05 '14 at 01:37
  • In groovy `==` basically means equality of value (`equals()`) instead of equality by reference (`==` in Java), so `"$t" == "test"` is true. Second, `odd["$t"]` yields null because "$t" is a GStringImpl key now instead of a simple String key. Hence a `toString()` on the object will give you a String key. Check my recent update. – dmahapatro Mar 05 '14 at 01:45
  • 2
    Map key equality is then using Object reference, rather than value. And, as you have said the way to deal with strings is using parenthesis rather than GStrings. Thanks! Although there seems to be some oddness still with GStrings as even when you save them and use them as objects it doesn't work, see updated question with 'odd2' (if you want, you have already answered the core of this question) – Simon Mar 05 '14 at 02:09