This Groovy behavior blew my mind. Is this common knowledge?

What would you expect the output of this to be?

    def styleA = [abc:"ABC",def:"DEF",ghi:"GHI"]
    state.styleA = styleA
    styleA.remove("def")
    pauseExecution(5000)
    log.info("state.styleA is: ${state.styleA}")

I would have bet money on the result being:

state.styleA is: [abc:"ABC",def:"DEF",ghi:"GHI"]

but I would have been wrong which is why I spent the morning chasing a bizarre issue that defied logic.

The actual result is:

state.styleA is: [abc:ABC, ghi:GHI]

I know about atomicState vs State but it seems to be required when dealing with maps. Repeating the test with atomicState

def styleB = [abc:"ABC",def:"DEF",ghi:"GHI"]
atomicState.styleB = styleB
styleB.remove("def")
log.info("state.styleB is: ${atomicState.styleB}")

I get the expected result.
state.styleB is: [abc:ABC, def:DEF, ghi:GHI]

1 Like

so

map.remove('key') removes the 'key' from the map.

So for state, things are working correctly.

You want to read about pass by value vs. reference. In short maps are passed by reference, so folks are 'sharing' the map. Anyone that changes the map, all get the change. If you want to copy it you need to do something like

Map newMap = [:]+oldmap

Now atomicState in HE is 'special', in that it is its own copy of the data. This is an HEism on on atomicState works.

You also cannot do atomicState.remove('key'). You need to

Map tempMap=atomicState.someMap

tempMap.remove(key)

atomicState.someMap=tempMap

In general, if you can avoid atomicState, you will make your life simpler and reduce load on the hub.

5 Likes

Is this true if a Map is passed as a parameter to a method? If the Map is modified within the method, is the modified data then available at the level of the caller?

yes....I use this all the time

1 Like

Very good information, thanks for sharing. I was under the mistaken impression that doing state.myNewMap = myOldMap was basically a database write. So the idea that changing myOldMap after the "database write" was rather wierd. This was the solution I came up with after a little reading.

def myEffectiveSettingsMap = myBaseSettingsMapwithRGBA.clone() + myOverridesMap.clone()

Thanks again for the post.

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.