skip to content

When may a Go method declaration leave the receiver unnamed, and why would you?

level: middleimportance: nice to knowfreq 25%

answer

  1. only one half is required
  2. the body never reads it
  3. underscore works in this slot too
  4. a method returning a fixed string

basics

~20 s

Whenever the body never uses it. Only the receiver's type is required, so func (Celsius) Unit() string is legal. Omitting the name — or writing an underscore — tells a reader the method's answer does not depend on the value it was called on.

solid answer

~50 s

The receiver is a parameter, and like any Go parameter it may be declared with a type and no name. `func (Celsius) Unit() string { return "C" }` compiles fine, and so does the explicit blank form `func (_ Celsius) Unit() string`. You do this when the method exists to attach behaviour to the type rather than to read the value: a constant answer, a kind or unit string, a method that exists only so the type satisfies an interface. The signal is the point — a reader scanning the declaration sees immediately that the receiver is ignored, which is stronger than reading the body to find out. It also removes a name that could shadow a package inside the body. Use it only when the body genuinely ignores the receiver; do not use it to dodge picking a name.

code

go · 6 lines
go
type Meters float64

// The receiver is never read, so it is left unnamed.
func (Meters) Unit() string { return "m" }

func (m Meters) Feet() float64 { return float64(m) * 3.28084 }

go deeper

for a junior

Know that the receiver's type is required but its name is not, and that a method returning a constant answer for the whole type is the usual case for leaving it out.

for a middle

Explain the signalling value: a reader sees from the declaration alone that the result depends on the type, not the value, and an absent name cannot shadow an imported package inside the body.

for a senior

Show judgment about when the omission is honest. Be ready to say you would name the receiver again the moment the body needs it, rather than leaving a misleading signature in the package.

for a principal

Treat this as a house-style decision worth settling once — bare type or explicit blank — so a package of value types reads uniformly and reviewers are not relitigating it per pull request.

## Receivers, like parameters, may be nameless Go requires a receiver's **type** in a method declaration, not its **name**. All three of these are valid, and they compile to the same thing: ```go func (m Meters) Unit() string { return "m" } func (_ Meters) Unit() string { return "m" } func (Meters) Unit() string { return "m" } ``` The first names the receiver and never uses it. The second names it explicitly blank. The third omits the name entirely. Go allows the same thing for ordinary parameters — `func handle(_ int, s string)` — because a signature sometimes has to accept a value it does not want. ## When to reach for it The honest test is whether the body reads the receiver. If it does not, the name is noise, and worse, it is a small lie: it suggests the method's result depends on the value when it does not. Typical cases in a value package: - **Constant answers about the type.** A unit string, a dimension name, a scale factor — every `Meters` returns `"m"`, so the particular `Meters` is irrelevant. - **Methods that exist to make a type satisfy an interface** where the implementation needs no state. - **Methods that only inspect their arguments**, using the receiver purely for dispatch. In each case the unnamed receiver is documentation that cannot go stale: a reader knows from the first line that this method's answer is a property of the type, not of the value. ## The secondary benefit: nothing to shadow A named receiver occupies an identifier inside the body's scope, and that identifier hides anything of the same name from the enclosing scope — an imported package, a package-level variable. A receiver you do not name cannot shadow anything, which is a small extra reason not to invent a name you will not use. ## When not to use it Do not leave a receiver unnamed because you cannot decide what to call it, and do not leave it unnamed in a method that would use it after one more line of work. If a later change needs the value, you add the name then — a one-character diff — but a reviewer reading the intermediate state was told something untrue. There is also nothing to be consistent with here in the way there is for names. A type whose twenty-nine methods use `p` and whose thirtieth omits the receiver is not inconsistent: the thirtieth has no receiver name to disagree about. The convention that every method on a type shares one receiver name applies to the methods that actually name one. ## Named blank versus omitted Both `(_ Meters)` and `(Meters)` are idiomatic and mean the same thing to the compiler. The bare-type form is the more common in Go code and reads slightly cleaner; the explicit `_` is sometimes preferred in a file where other declarations use `_` for the same purpose, so the intent is spelled out rather than inferred from an absence. Pick one and keep the package uniform. ## What it is not An unnamed receiver changes nothing about how the method is called, what type it belongs to, or whether it is exported — that is decided by the method's own name, its capitalisation, and its receiver type. It is purely a statement about the body: this method ignores the value it was called on.

  • Does omitting the receiver name change how the method is called or whether it is exported?
    No. Export is decided by the capitalisation of the method name, and dispatch by the receiver's type; the receiver name is only an identifier for the body. Callers write the same call either way and cannot tell the difference from outside the package.
  • Is `func (_ Meters) Unit() string` different from `func (Meters) Unit() string`?
    Not to the compiler — both declare a receiver of type `Meters` that the body cannot reference. The bare-type form is more common in Go code; the explicit blank spells the intent out. Choose one and use it consistently within a package.

saying these in an interview costs you the question

  • Says every receiver must be named or the code will not compile
  • Leaves the receiver unnamed just to avoid choosing a name
  • Thinks an unnamed receiver makes the method unexported
  • Believes the method can then be called without a receiver value