Skip to content

proposal: Go 2: add sugar multiple keys to map to be tuples #63431

Closed
@Jorropo

Description

@Jorropo

Author background

  • Would you consider yourself a novice, intermediate, or experienced Go programmer? experienced
  • What other languages do you have experience with? python, lua, assembly, ...

Related proposals

  • Has this idea, or one like it, been proposed before? a quick is:issue label:proposal maps in:title search suggest to me no
    • If so, how does this proposal differ?
  • Does this affect error handling? No
    • If so, how does this differ from previous error handling proposals?
  • Is this about generics? No
    • If so, how does this relate to the accepted design and other generics proposals?

This is based with concepts of #63221 (but could be refactored to not be).
In case #63221 is refused then I think this is especially valuable.

Proposal

  • What is the proposed change?
    Allow to define multiple types in the keys of maps:
type edges map[string, string]struct{}

And have it be equivalent to creating a tuple of the same types:

type edges map[struct(string, string)]struct{}

Indexing into the map would be sugar for pack:

func (m edges) Link(a, b) {
 m[a, b] = pack()
}

func (m edges) IsValidPath(path ...string) bool {
 a := path[0]
 for _, b := range path {
   if _, ok := m[a, b]; !ok {
    return false
   }
   a = b
 }
 return bool
}

Would be:

func (m edges) Link(a, b string) {
 m[pack(a, b)] = pack()
}

func (m edges) IsValidPath(path ...string) bool {
 a := path[0]
 for _, b := range path {
   if _, ok := m[pack(a, b)]; !ok {
    return false
   }
   a = b
 }
 return bool
}

Lastly maps literals would get the same treatment:

m := edges{"Nantes", "Paris": pack()}

Into:

m := edges{pack("Nantes", "Paris"): pack()}
  • Who does this proposal help, and why?
    Current alternatives are:
    • Create an anonymous struct for the key (or use an array if the usecase fits for it).
      Which works but is verbose.
    • Use proposal: spec: tuples as sugar for structs #63221, this is not yet accepted and is still a more verbose.
    • Use nested maps, this gives a good enough syntax m[a][b] but is very awkward to deal with when considering keys that can be missing, awkward collection when deleting elements and adding elements which need to check if the inner map exists. This gets very bad to use fast when using lots of elements in the key. And performance is in almost all cases worst. *This fits unique edge cases you need to iterate over an inner map, or pass the inner map around.
  • Please describe as precisely as possible the change to the language.
  • What would change in the language spec?
    • see above
  • Please also describe the change informally, as in a class teaching Go.

Ok so imagine you just explained and demonstrated how maps exists.

Well you can have multiple keys:

m := map[int, int, int]block{
  0, 0, 0: stone,
  0, 1, 0: dirt,
}
m[0, 2, 0] = water
fmt.Println(m[0, 1, 0])
  • Is this change backward compatible? Yes
    • Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
      Show example code before and after the change.
    • Before
    • After
  • Orthogonality: how does this change interact or overlap with existing features? It makes maps with multi-factorial keys more readable and easier to use.
  • Is the goal of this change a performance improvement? No
    • If so, what quantifiable improvement should we expect?
    • How would we measure it?

Costs

  • Would this change make Go easier or harder to learn, and why? I think this is very slightly harder, I belive map[string, float64, int]complex128 and m["a", 42, 1337] are self explanatory however in the rare cases someone would try to integrate this with iteration and encoding/json (through reflect) this would yield surprising results, at least if theses aren't updated to have special behavior for tuples.
  • What is the cost of this proposal? (Every language change has a cost). More lines in the spec. Require the compiler to read and understand map keys and canonicalize them into single type forms.
  • How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected? I don't know, this could range to all of them to few of them depending on whether or not updating go/parser would be enough.
  • What is the compile time cost? None
  • What is the run time cost? None
  • Can you describe a possible implementation? Update the parser following rules described above, when walking the AST right after binding types to names run proposal: spec: tuples as sugar for structs #63221 packing (create anonymous structs with F0, F1, ... Fn names) on map keys and map indexes with multiple entries.
  • Do you have a prototype? (This is not required.) No

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions