10

While playing with Go code, I found out that map values are not addressable. For example,

package main
import "fmt"

func main(){
    var mymap map[int]string = make(map[int]string)
    mymap[1] = "One"
    var myptr *string = &mymap[1]
    fmt.Println(*myptr)
}

Generates error

mapaddressable.go:7: cannot take the address of mymap[1]

Whereas, the code,

package main
import "fmt"

func main(){
    var mymap map[int]string = make(map[int]string)
    mymap[1] = "One"
    mystring := mymap[1]
    var myptr *string = &mystring
    fmt.Println(*myptr)
}

works perfectly fine.

Why is this so? Why have the Go developers chosen to make certain values not addressable? Is this a drawback or a feature of the language?

Edit: Being from a C++ background, I am not used to this not addressable trend that seems to be prevalent in Go. For example, the following code works just fine:

#include<iostream>
#include<map>
#include<string>
using namespace std;
int main(){
    map<int,string> mymap;
    mymap[1] = "one";
    string *myptr = &mymap[1];
    cout<<*myptr;
}

It would be nice if somebody could point out why the same addressability cannot be achieved (or intentionally wasn't achieved) in Go.

Tanmay Garg
  • 801
  • 11
  • 20
  • 2
    See also http://stackoverflow.com/questions/20224478/dereferencing-a-map-index-in-golang – nos Jul 03 '16 at 15:30
  • 3
    As top answer says, it's a hashtable that stores values in the buckets. When it rehashes the values move. If you want to get around this, using a pointer as your value type will do it. – twotwotwo Jul 04 '16 at 07:22
  • C++ `map`s get away with this because they're binary trees that needn't move existing nodes around in RAM to add new ones (but its operations average O(log n), not O(1)). C++ `unordered_map` is a hashtable, but has to impose certain restrictions on implementations to avoid values moving; http://stackoverflow.com/a/31113618/2714852 and http://stackoverflow.com/q/37428119/ discuss. – twotwotwo Jul 04 '16 at 07:35
  • I think you mean `map is addressable` (e.g `&m`), but `map elements are not addressable` (e.g `&(m[1])`), that's different. – Eric Jul 29 '18 at 13:19

2 Answers2

21

Well I do not know about the internal Go implementation of maps but most likely it is a kind of hash table. So if you take and save the address of one of its entries and afterwards put another bunch of entries into it, your saved address may be invalid. This is due to internal reorganizations of hash tables when the load factor exceeds a certain threshold and the hash table needs to grow.
Therefore I guess it is not allowed to take the address of one of its entries in order to avoid such errors.

DAXaholic
  • 33,312
  • 6
  • 76
  • 74
1

Being from a C++ background.

Why are [Go] map values not addressable?


If all other languages were like C++ there would be no point in having other languages.

C++ is a complex, hard-to-read language.

Remember the Vasa! - Bjarne Stroustrup

Go, by design, is a simple, readable language.

dotGo 2015 - Rob Pike - Simplicity is Complicated


A Go map is a hash map. A deterministic hash function is applied to a map key. The hash value is used to determine the primary map bucket for the entry (key-value pair). A bucket stores one or more map entries. A primary bucket may overflow to secondary buckets. Buckets are implemented as an array. As the number of map entries increases by insertion, the hash function adapts to provide more buckets. The map entries are copied incrementally to a new, larger bucket array. If the number of map entries decreases by deletion, space may be reclaimed.

In summary, a Go map is a dynamic, self-organizing data structure. The memory address of an entry (key-value pair) is not fixed. Therefore, map values are not addressable.

GopherCon 2016 Keith Randall - Inside the Map Implementation

In Go, map value addressability is not necessary.

peterSO
  • 158,998
  • 31
  • 281
  • 276
  • Slices are also self organizing i.e. they also copy over to new locations when you append more elements into it, but yet it is allowed to take address of any element in a slice. – Rohit Jul 21 '23 at 09:46