Understanding go composite literal

mon picture mon · Apr 26, 2020 · Viewed 14k times · Source

Why a function value assignment to f is not a composite literal?

Go lang specification Composite literals says below, hence function value cannot be constructed with composite Literal.

Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated

However, the function value assignment to f in the code looks as a composite literal expression for type func() int.

Is there a reason function object cannot be constructed as a composite literal?

package main
import (
    "fmt"
)

func main(){
    var x int = 0

    var f func() int
    f = func() int{ x++; return x * x }  // <---- Why this cannot be a composite literal?

    fmt.Println(f())   // 1
    fmt.Println(f())   // 4
    fmt.Println(f())   // 9

    // Define a type for "func() int" type 
    type SQUARE func() int
    g := SQUARE{ x++; return x * x}   // <--- Error with Invalid composite literal type: SQUARE 

    fmt.Println(g())
}

Answer

Grigoriy Mikhalkin picture Grigoriy Mikhalkin · Apr 26, 2020

Does f = func() int{ x++; return x * x } looks like composite literal?

Not really)

As spec states:

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

To make this statement clearer, here is production rule for composite literal:

CompositeLit  = LiteralType LiteralValue .

You can see, that production rule for LiteralValue is:

LiteralValue  = "{" [ ElementList [ "," ] ] "}" .

and FunctionBody, doesn't look at all like this. Basically, it's list of Statement's:

FunctionBody = Block .
Block = "{" StatementList "}" .
StatementList = { Statement ";" } .

Why function cannot be constructed as a composite literal?

I wasn't able to find any documented answer to that, but simplest assumption would be that main reasons are:

  • Avoid confusion. Here is example, if it would be allowed to construct composite literal for function:
type SquareFunc func() int

type Square struct {
    Function SquareFunc
}

func main() {
    f := SquareFunc{ return 1 }
    s := Square{ buildSquareFunc() }
}

s:= ... line(which is supposed to be composite type) could be easily confused with 1st line.

  • Besides body, function has one more important thing -- Signature. If you could construct composite literal for function, how would you define it's arguments and return parameters names? You could define names in type definition -- but that would cause inflexibility(sometimes you want to use different parameter names) and code like:
type SquareFunc func(int x) int

func main() {
    x := 1

    f := SquareFunc{ 
        x++
        return x * x
    }
    f(2)
}

would look too unclear, as it wouldn't be obvious what x variable does it actually use.