December 12, 2023

Calling all gophers!

It’s time to talk about… Calls!


Given an expression f with a core type F of function type,

f(a1, a2, … an)

calls f with arguments a1, a2, … an.

This basic syntax is common to many languages, so should not feel at all strange if you have any programming experience at all.

So let’s dive right into the nitty-gritty details…

… Except for one special case, arguments must be single-valued expressions assignable to the parameter types of F and are evaluated before the function is called.

So we’ll talk about the special case later. For today, we’ll address the two other points made in this sentence.

  1. Arguments must be single-valued expressions. Let’s consider some examples and counter-examples. Assuming a function f of type func(int, int, int):
f(1, 2, 3) // valid: Three single-valued expressions, 1, 2, and 3
f(1+2, 10-9, 3*4) // valid: Each expression evaluates to a single value

func one() int {
	return 1
f(one(), one(), one()) // valid: one() evaluates to a single expression

func two() (int, int) {
	return 2, 3

f(two(), one()) // invalid: two() evaluates to two expressions

// However, the  likely intent of the above can be rewritten as:
a, b := two()
f(a, b, one())
  1. Arguments must be assignable to the parameter types of F. This one should be pretty obvious, especially if you’re familiar with strictly-typed languages.
f("one", float64(1.23), struct{ Name string}{Name: "Bob"}) // Invalid: f expects three ints

Quotes from The Go Programming Language Specification Version of August 2, 2023

Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content

Refresher on methods

In yesterday’s email, I failed to include the example included in the spec, which doesn’t make sense to include otherwise. I’ve updated the web version of the email in case you’re super curious to see what I left out. We’ve already covered these details, but they’re logically mentioned again in the section about function calls, so we’ll cover them here: Calls … A method call x.m() is valid if the method set of (the type of) x contains m and the argument list can be assigned to the parameter list of m.

Special case: Multi-value arguments to functions

You may recall that when we started the section on function calls, we were told about a “special case”… well here it is! Calls … As a special case, if the return values of a function or method g are equal in number and individually assignable to the parameters of another function or method f, then the call f(g(parameters_of_g)) will invoke f after binding the return values of g to the parameters of f in order.

nil functions

Calls … Calling a nil function value causes a run-time panic. So, calling a nil function causes a panic. Sensible enough. But when would you ever run across a nil function? Let’s look at some examples. This is probably the most obvious example, and perhaps one that popped to your mind: var fn func(int) // fn is of type func(int), but uninitialized, so nil fn(3) // run-time panic But let’s consider another example, which can be a bit more confusing.