Why probe with an anonymous interface literal like interface{ Flush() error } instead of a named interface type?
answer
- an interface type needs no name
- satisfaction is by method set, not declaration
- no import needed to name the shape
- the signature must match to the letter
- name it once it is contract
basics
~20 sAn interface literal states the required method set inline, so you can probe for a capability no exported interface names, without importing the package that would. The cost: the signature must match exactly, and nothing checks it.
solid answer
~50 sBecause Go satisfaction is structural, an interface type can be written inline as a type expression: `if f, ok := w.(interface{ Flush() error }); ok { return f.Flush() }`. That buys two things. First, it lets you detect a capability nobody has declared an interface for — plenty of useful methods, like `CloseWrite() error` on a TCP connection, have no exported interface at all. Second, it removes a dependency: you never import the package that owns the type or the interface, which keeps a low-level helper free of upward imports. The costs are real. The match is exact, so a `Flush()` with no result silently fails a probe for `Flush() error`. The literal is invisible to documentation, and repeating it at several call sites lets copies drift apart. Once the capability is part of your own contract, declare a named interface — unexported for internal use, exported if callers should implement it.
code
go · 6 linesfunc flushIfPossible(w io.Writer) error {
if f, ok := w.(interface{ Flush() error }); ok {
return f.Flush()
}
return nil // nothing buffered: nothing to flush
}go deeper
Recall that an interface type can be written inline wherever a type is expected, and that a value matches it by having the method, with no declaration linking the two.
Explain the dependency argument — naming a shape without importing the package that owns it — and the exact-signature risk that makes a mistyped literal fail silently.
Judge when to keep the literal, when to give it an unexported name in your own package, and when the capability has become a contract that deserves an exported interface.
Own the consequence for the ecosystem: an inline probe is a dependency nobody can see, so decide where your codebase requires a named, documented capability instead.
## An interface type does not need a name In Go, `interface{ Flush() error }` is a perfectly ordinary type expression. Anywhere a type is allowed — a variable declaration, a parameter, and in particular the right-hand side of a type assertion — you may write the interface out in full instead of referring to a declared name. Satisfaction is structural: a value qualifies because its method set contains a method with that exact name and signature, not because anyone declared a relationship. So the literal and a declared interface with the same method are the same type for every purpose that matters. ## What the inline form buys **Probing for capabilities nobody named.** Many useful methods have no exported interface anywhere. A TCP connection has `CloseWrite() error` for half-closing; a file has `Sync() error`; assorted types have `Name() string`. If you hold a value through a narrow interface and want to use one of those when present, an inline literal is the only way to ask without inventing your own declaration. **Avoiding an import.** Asserting to a named interface means importing the package that declares it. For a low-level utility package that is sometimes unacceptable — it can create a dependency cycle, drag a heavy package into a small one, or invert the intended layering. The literal names the shape without naming the package, so the dependency disappears while the behaviour stays. **Documenting the requirement at the point of use.** A reader of the assertion sees exactly which method is needed. With a named interface they must go and look it up. ## What it costs **Exact matching, silently.** The probe compares full signatures. `Flush()` and `Flush() error` are different capabilities; a type with the former fails a probe for the latter, and because a failed probe is a normal outcome, nothing reports it. You get the fallback path forever and wonder why the optimisation never fires. When you write a literal, you are hand-copying a signature with no compiler to check it against the intended type. **Invisibility.** An inline interface appears in no documentation and in no list of interfaces the package cares about. A maintainer of the type you are probing has no way to discover that you depend on that method shape. **Drift.** The same literal repeated in five files is five things to change. The cheap middle ground is to declare it once, unexported, in your own package: ```go type flusher interface{ Flush() error } ``` You keep the zero-dependency property — you still declared it yourself rather than importing anyone — while getting one place to maintain and a name the code can read. ## When to promote it to an exported interface If the capability is something you want *callers* to implement, the literal is the wrong shape. Export a named interface so implementers have something to write against and something to see in the documentation, and so an implementer can use a compile-time assertion to check they got the signature right. Keep the literal for the case where you are probing values you do not own and the capability is nobody's declared contract. ## The interaction with wrappers A literal probe is subject to exactly the same failure as a named one: it inspects the dynamic type you are actually holding, so any wrapper that does not forward the method makes the probe return false. Writing the interface inline neither helps nor hurts there — a wrapper hides `interface{ Flush() error }` just as thoroughly as it hides a named interface, because it is the method set of the outermost value that is being examined. ## Style notes Keep literals to one, at most two, methods. A three-method literal inline in an `if` statement is unreadable and is a sign the shape deserves a name. Write the literal on one line where it fits: `x.(interface{ Unwrap() io.Writer })` reads fine, while a multi-line literal buried in a condition does not. And prefer the comma-ok form always — a probe is a question, and a question should never panic.
- What is the failure mode when the literal's signature is slightly wrong?Silence. The assertion compiles, the probe returns false at run time, and your code takes the fallback forever. No panic, no error, no vet complaint — just an optimisation or feature that never engages. That is why a literal copied from memory rather than from the real method declaration is dangerous.
- Is an inline interface slower to assert against than a named one?No. A named interface is only a declaration; the compiler and run time work with the method set either way, and the assertion is the same operation with the same cost. Choose between them on dependency and readability grounds, not performance.
- When should the shape become an exported interface in your package?As soon as you want other people to implement it. An exported interface gives implementers a name to target, a place in your documentation, and the ability to write a compile-time assertion that their type satisfies it. Reserve the literal for probing values whose capability nobody has declared.
saying these in an interview costs you the question
- Thinks an interface must be declared before it can be asserted to
- Believes return types are ignored when matching a method
- Copies the method signature from memory rather than the source
- Repeats the same literal across many files
- Uses a multi-method literal inline where a name is needed