Using "map index expressions" as the value for a range loop

385 views
Skip to first unread message

Kyle Stanly

unread,
Jul 7, 2016, 10:05:42 AM7/7/16
to golang-nuts
I noticed that the specification states:

"As with an assignment, if present the operands on the left must be addressable or map index expressions; they denote the iteration variables."


Here is the thing I am having trouble imagining... if the iterator keeps a snapshot of the map at the time the iterator was created, would the map index expression obtain the actual, up-to-date value for the given key? Maybe even determine if it was deleted? 

I.E...

for k, m[k] := range m {...}

Apparently is valid Go syntax, however what are the semantics behind this? If another Goroutine calls delete(...) and removes that element from the map, would this pretty much restore that value back into the map (from what is held in the snapshot)? How would you go about retrieving that value again? Do you need to re-enter the map to obtain the value again through that key, 'k'? What are the practical applications for this? 

Jan Mercl

unread,
Jul 7, 2016, 10:19:47 AM7/7/16
to Kyle Stanly, golang-nuts

On Thu, Jul 7, 2016 at 4:06 PM Kyle Stanly <thei...@gmail.com> wrote:

> for k, m[k] := range m {...}
>
> Apparently is valid Go syntax, however what are the semantics behind this?

It is not a valid Go syntax. The short variable declaration syntax requires variable names on its left side. You probably meant '=' instead of ':='.

> If another Goroutine calls delete(...) 

Concurrent map updates and reading is a data race. Within the same goroutine it works, but I did not expect the result I've got: https://play.golang.org/p/ECno0PVdBF

It seems like a bug to me.

--

-j

Konstantin Khomoutov

unread,
Jul 7, 2016, 10:33:25 AM7/7/16
to Jan Mercl, Kyle Stanly, golang-nuts
Indeed, given that "normal" iteration -- using a variable for the
map values -- works as one would expect it to:
https://play.golang.org/p/phmsYAov7S

Jesse McNelis

unread,
Jul 7, 2016, 10:41:51 AM7/7/16
to Jan Mercl, golang-nuts, Kyle Stanly


On 8 Jul 2016 12:19 a.m., "Jan Mercl" <0xj...@gmail.com> wrote:
>
>  I did not expect the result I've got: https://play.golang.org/p/ECno0PVdBF
>
> It seems like a bug to me.
>

Looks fine to me. The k in m[k] is the value of k before the assignment.

So the value at m["foo"] is assigned to m[""] and the value at m["bar"] is assigned to m["foo"]

Jan Mercl

unread,
Jul 7, 2016, 10:53:55 AM7/7/16
to Jesse McNelis, golang-nuts, Kyle Stanly
On Thu, Jul 7, 2016 at 4:41 PM Jesse McNelis <jes...@gmail.com> wrote:

> Looks fine to me. The k in m[k] is the value of k before the assignment.

> So the value at m["foo"] is assigned to m[""] and the value at m["bar"] is assigned to m["foo"]

Took me a while to run it through a mind emulator, but you're right. Thanks!



--

-j

Kyle Stanly

unread,
Jul 7, 2016, 11:52:06 AM7/7/16
to golang-nuts
So, what would be the appropriate use-cases for this; I.E, using a map index expression as the value?

keith....@gmail.com

unread,
Jul 7, 2016, 7:44:07 PM7/7/16
to golang-nuts
I don't think there are any.  Because you can do it doesn't mean you should.  It's incredibly confusing for readers (hence the confusion in this thread).

Matt Harden

unread,
Jul 9, 2016, 6:48:13 PM7/9/16
to keith....@gmail.com, golang-nuts
OK but based on Jesse's explanation, I expect the map to contain keys "bar" and "". But in fact, in the playground at least, we get "foo" and "bar", with the values reversed:

foo
bar

map[foo:314 bar:42]

I can't think of a valid explanation for that behavior.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Matt Harden

unread,
Jul 9, 2016, 6:57:15 PM7/9/16
to keith....@gmail.com, golang-nuts
OK, after initializing k to an actual value, I see what's happening:

k = ""  prior to the loop
m = {"foo": 314, "bar": 42} prior to the loop

loop, round 1
k gets set to "foo"
m[""] gets set to 314 -- AND by chance, the map iterator is going to visit this new map entry later (round 3).
m["foo"] gets deleted

loop, round 2
k gets set to "bar"
m["foo"] gets set to 42
m["bar"] gets deleted

loop, round 3
k gets set to ""
m["bar"] gets set to 314 -- the value of m[""]
m[""] gets deleted

At the end of the loop, m is left with foo and bar as keys, and the values have been swapped.

Reply all
Reply to author
Forward
0 new messages