Skip to content

proposal: spec: type inferred composite literals #12854

Open
@neild

Description

@neild

Composite literals construct values for structs, arrays, slices, and maps. They consist of a type followed by a brace-bound list of elements. e.g.,

x := []string{"a", "b", "c"}

I propose adding untyped composite literals, which omit the type. Untyped composite literals are assignable to any composite type. They do not have a default type, and it is an error to use one as the right-hand-side of an assignment where the left-hand-side does not have an explicit type specified.

var x []string = {"a", "b", "c"}
var m map[string]int = {"a": 1}

type T struct {
  V int
}
var s []*T = {{0}, {1}, {2}}

a := {1, 2, 3} // error: left-hand-type has no type specified

Go already allows the elision of the type of a composite literal under certain circumstances. This proposal extends that permission to all occasions when the literal type can be derived.

This proposal allows more concise code. Succinctness is a double-edged sword; it may increase or decrease clarity. I believe that the benefits in well-written code outweigh the harm in poorly-written code. We cannot prevent poor programmers from producing unclear code, and should not hamper good programmers in an attempt to do so.

This proposal may slightly simplify the language by removing the rules on when composite literal types may be elided.

Examples

Functions with large parameter lists are frequently written to take a single struct parameter instead. Untyped composite literals allow this pattern without introducing a single-purpose type or repetition.

// Without untyped composite literals...
type FooArgs struct {
  A, B, C int
}
func Foo(args FooArgs) { ... }
Foo(FooArgs{A: 1, B: 2, C:3})

// ...or with.
func Foo(args struct {
  A, B, C int
}) { ... }
Foo({A: 1, B: 2, C: 3})

In general, untyped composite literals can serve as lightweight tuples in a variety of situations:

ch := make(chan struct{
  value string
  err   error
})
ch <- {value: "result"}

They also simplify code that returns a zero-valued struct and an error:

return time.Time{}, err
return {}, err // untyped composite literal

Code working with protocol buffers frequently constructs large, deeply nested composite literal values. These values frequently have types with long names dictated by the protobuf compiler. Eliding types will make code of this nature easier to write (and, arguably, read).

p.Options = append(p.Options, &foopb.Foo_FrotzOptions_Option{...}
p.Options = append(p.Options, {...}) // untyped composite literal

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions