Skip to content

CONCEPT Cited by 1 source

reflect.MethodByName linker pessimism

reflect.MethodByName(name) with a non-constant name is the single Go language feature that most aggressively defeats the linker's method dead-code elimination.

Mechanism

When a Go program calls v.MethodByName(name) and name is a compile-time constant, the linker can trace exactly which method is invoked and include only that one. When name is dynamic — the normal use case — the linker can't know at build time which method will be resolved. Safe behaviour: keep every exported method of every reachable type, plus every symbol those methods transitively depend on.

This can balloon binary size dramatically — Datadog measured 16-25 % per binary when method-DCE was blocked, and the savings recovered when they fixed every offender.

Canonical stdlib offenders

text/template and html/template are the primary real-world sources: their execution engine calls reflect.MethodByName with the method name parsed from the template body at runtime ({{ .Error }} → call .Error() on the piped value). Any binary importing either one (directly or transitively) loses method-DCE across the entire reachable type graph.

Diagnosis

go build -ldflags=-dumpdep prints why each symbol is reachable; whydeadcode consumes that output and names the first call chain that disabled method-DCE. Only the first entry is guaranteed correct — iterate (fix, re-run) until the output is empty.

Workarounds

  • Patch the site. Replace dynamic MethodByName with exhaustive switch / interface dispatch where feasible.
  • Build-tag-guard. If the dynamic path is optional, put it behind a build tag (patterns/build-tag-dependency-isolation).
  • Package-split. Move the dynamic surface to a separate package that only binaries needing it import (patterns/single-function-forced-package-split).
  • Fork stdlib. Datadog's last-resort move for text/template + html/template: fork into pkg/template/ with method-call path statically disabled. Maintenance burden, but the only option while the upstream Go issue #72895 is unresolved.

Datadog's upstream patches

The 2026-02-18 post lists PRs to ~a dozen dependencies, e.g.:

Canonical patterns/upstream-the-fix datum: Kubernetes itself subsequently enabled method-DCE and reports 16-37 % of its own.

Seen in

Last updated · 200 distilled / 1,178 read