Skip to content

proposal: Go 2: Safe navigation operator (?.) #42847

Closed
@kevburnsjr

Description

@kevburnsjr

Proposal

Add a new operator (?.) to support safe navigation.

Example

package main

type a struct {
	b *b
}

type b struct {
	c int
}

Current Behavior

Navigation across pointer of nil value causes runtime panic.

func main() {
	x := a{&b{1}}
	y := a{}
	println(x.b.c)
	println(y.b.c)
}

x.b.c evaluates to 1
y.b.c panics

1
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x45db4c]

goroutine 1 [running]:
main.main()
	/tmp/sandbox869110152/prog.go:16 +0x6c

Proposed Behavior

Safe navigation across pointer of nil value evaluates to nil value of same type as target property.

func main() {
	x := a{&b{1}}
	y := a{}
	println(x.b?.c)
	println(y.b?.c)
}

x.b?.c evaluates to 1
y.b?.c evaluates to 0 (nil value of type similar to c)

1
0

Reasoning

Null property traversal is a common cause of runtime panic. Frequently developers must disrupt the flow of their program by adding nil checks in order to reproduce the behavior of a safe navigation operator. These nil checks add to the maintenance cost of the program by making the code less readable and introduce new opportunities for error.

Current idiom

func (a *a) getC() int {
	if a.b == nil {
		return 0
	}
	return a.b.c
}

Proposed idiom

func (a *a) getC() int {
	return a.b?.c
}

Similar features in other languages

See https://en.wikipedia.org/wiki/Safe_navigation_operator

Also known as

  • Optional chaining operator
  • Safe call operator
  • Null-conditional operator

Go 2 language change template

  • Would you consider yourself a novice, intermediate, or experienced Go programmer?
    Experienced

  • What other languages do you have experience with?
    PHP, Javascript, Java, TCL, Bash, Actionscript, Erlang, Python, C++

  • Would this change make Go easier or harder to learn, and why?
    Adds one more operator to learn which should feel familiar to people having experience with analogous operators in other languages popular among Gophers (C#, Ruby, Python, PHP, Typescript, Rust, Scala).

  • Has this idea, or one like it, been proposed before?
    Not found in github issues. One slightly similar golang-nuts post from 2013.

  • If so, how does this proposal differ?
    Previous discussion appears to relate specifically to null pointer receiver methods rather than nested struct traversal or command chaining.

  • Who does this proposal help, and why?
    Developers moving to Go from languages that already support safe navigation.

  • What is the proposed change?
    Add operator ?. (see above).

  • Please describe as precisely as possible the change to the language.
    Add token QUES_PERIOD = "?.". Modify selector expression or add new safe selector expression to achieve behavior described above. Not valid on left hand side.

  • What would change in the language spec?
    Expansion of selector expression definition and operator list

  • Please also describe the change informally, as in a class teaching Go.
    The safe navigation operator?. can be used to short circuit property traversal when a nil pointer is encountered, avoiding panic.

  • Is this change backward compatible?
    Yes.

  • What is the cost of this proposal? (Every language change has a cost).
    Higher maintenance costs due to increase in number of operators and more complex selector expression code.

  • How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?
    Possibly several. Depending on implementation, maybe none.

  • What is the compile time cost?
    Presumably low

  • What is the run time cost?
    Presumably low

  • Can you describe a possible implementation?
    Add new token QUES_PERIOD = "?.". Then either modify ast.SelectorExpr or add new ast.SafeSelectorExpr

  • Do you have a prototype? (This is not required.)
    In development

  • How would the language spec change?
    Expansion of selector expression definition and operator list

  • Orthogonality: how does this change interact or overlap with existing features?
    Syntactically identical with . operator in selector expressions except where the value of the expression is nil (where the . operator would panic)

  • Is the goal of this change a performance improvement?
    No.

  • Does this affect error handling?
    No.

  • Is this about generics?
    No.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions