July 13, 2017·6 min read·engineeringgodesigncompatibility

Go 2 starts by asking for evidence of problems

Russ Cox asks the community to document where Go fails at production and development scale. Compatibility and a limited capacity for major changes shape the proposed process.

A proposed feature can sound unnecessary when its motivating problem is unfamiliar. Go has encountered that difficulty with both clock behavior and codebase refactoring. In his July 13 GopherCon talk, Russ Cox uses those examples to explain why planning Go 2 should begin with experience reports. The request is for descriptions of actual programs and their limitations, with enough context for someone working elsewhere to understand the cost.

This is the start of a public design effort. It does not announce an accepted generics design or a new error-handling syntax. Cox names those areas among possible major changes, alongside immutable or read-only values and problems not yet suggested. The proposed process asks the community to establish which problems deserve that level of intervention.

I like the pressure Go places on programmers to keep abstractions understandable. That preference also makes language changes expensive. Every new mechanism becomes something a reader may need to know years after the original author chose it, so a concrete account of the problem is a useful condition for adding one.

Scale has a development dimension

The talk restates two goals that have guided Go. Production scale concerns concurrent systems interacting with other servers. Development scale concerns large bodies of code maintained by engineers whose work is only loosely coordinated. A small organization can encounter both through cloud services and open-source dependencies, even when its own code is comparatively small.

Development scale is particularly relevant to the history of aliases. Cox describes work on large code changes at Google and the need to migrate an API over multiple steps. The issue is not limited to the total number of files in one repository. It also appears when callers and libraries live in different repositories and cannot be changed in one commit.

The earlier codebase refactoring article, based on a November 2016 talk, explains the mechanics. A gradual repair introduces a replacement API that can coexist with the old one, converts callers over time, and removes the old API when permitted. This requires the intermediate state to work. Merely having a correct final state does not make the migration possible.

That article gives a concrete historical example in the move from io.ByteBuffer to bytes.Buffer. The initial change repaired many source files but retained a compatibility stub for generated code. It also explains the limitation of the stub. A wrapper structure is not interchangeable with the original type in every function signature, so some callers still cannot move independently.

These details turn a preference for aliases into an argument about program maintenance. The desired capability is a transition in which two names denote the same type. Cox explicitly distinguishes describing that need from prescribing every detail of a solution. The Go 2 process seeks similarly useful descriptions in other areas.

Why an example must explain its importance

Cox separates stating a problem from explaining why it matters. A precise test case can demonstrate that behavior is inconvenient or incorrect without showing how often it arises or what it prevents people from building. A community discussion needs the surrounding facts that coworkers may already share implicitly.

The alias discussion provides an example of an incomplete explanation. The original abstract examples used package names that did not show readers where the difficulty arose in their own work. Cox says many responses consequently treated aliases as a solution to a Google-specific concern. Concrete examples from open-source code helped make the broader maintenance problem understandable.

This changes what a useful contribution looks like. A request for generics becomes more informative when it includes the code being duplicated or the abstraction that cannot be expressed cleanly. A request to change errors becomes more informative when it shows how a large program attempts to understand and handle them. Those examples allow a designer to compare competing mechanisms against the same work.

Cox gives generic methods as a design question he cannot answer without clearer use cases. Whether methods should have parameters separate from the receiver is not settled merely by agreeing that generics would be useful. Real examples can reveal whether that particular capability is necessary and what complexity it would impose.

An experience report can therefore remain useful even if its author proposes no syntax. It provides material for evaluating several solutions and may expose a library or tooling answer. The report should describe the existing program closely enough that a proposed change can be judged by what it improves there.

Clock behavior changes the assessment

The other example concerns elapsed time across a clock reset. Cox describes the ordinary operation of recording a start time and an end time, then subtracting them. If the wall clock moves backward between those observations, the calculated duration can become negative even though the operation completed normally.

An earlier request proposed exposing a monotonic clock through a new API. Cox initially considered the problem insufficient to justify the cost of explaining two clocks and converting existing code. His talk describes the expectation that leap smearing might reduce the practical need. That was an assessment of significance, not a claim that the arithmetic could never fail.

Cloudflare subsequently published an account of a DNS failure around the end-of-2016 leap second. In the talk, Cox identifies that account as evidence that changed the assessment. It showed a production system of the kind Go was intended to support encountering the problem. The resulting solution is planned for Go 1.9 without a new public API.

The sequence demonstrates why an experience report should preserve the problem independently of its first suggested solution. A report can establish that a failure needs attention while leaving the API design open. Here the practical evidence supported action, and the implementation approach avoided requiring callers to adopt a second timing convention.

I find that distinction especially useful for Go. The language can keep common code simple when a runtime or library change solves the actual problem. A feature request framed only as a syntax demand makes it harder to compare that possibility with a language change.

Existing programs constrain the design

The talk makes existing code a central constraint. Cox says Go 2 must bring existing developers along, and asks that old habits change only for substantial benefit. He uses his own lingering habit of naming an error method String as an example of how a small rename can continue to affect programmers years later.

More substantially, the proposed transition must let packages written in Go 1 and Go 2 import each other over a period of multiple years. The exact mechanism remains unresolved. Automated tools such as go fix are expected to help, but the talk does not present a finished migration system.

That requirement limits the number of major changes. Cox estimates capacity for only a few and explicitly separates those from minor housekeeping changes. The cost includes design, implementation, and the tooling needed to move existing users. This means that identifying a real inconvenience is only part of the argument. Its importance must justify consuming some of that limited capacity.

Compatibility also changes delivery. Cox proposes shipping compatible parts incrementally through the Go 1 release sequence. This would preserve ordinary releases and avoid dividing implementation effort between divergent lines. The proposal encourages changes that existing code can adopt without a single disruptive migration.

The release numbers mentioned in the talk are speculative placeholders. They express a possible sequence, not a promised schedule. The current action is the call for reports and a public discussion, with no basis for claiming that a particular major feature will arrive in a named release.

Solutions can live in tools and libraries

Cox uses math/bits as an example of a library answer to a problem once considered for language syntax. A compiler can recognize functions and replace them with machine instructions while keeping the operation available through ordinary function calls. That allows implementation support without assigning new meanings to familiar arithmetic expressions.

The race detector provides a different example. Shared memory and goroutines allow data races, but forbidding them through language rules presents difficult design questions. The project instead supplied a runtime and tooling mechanism that programmers can use to find races. The talk treats that as a successful response within the broader development environment.

These examples make the requested reports relevant beyond a language-feature vote. The same concrete program might motivate a diagnostic, a library operation, or a language rule. Contributors can publish a report using their preferred medium and add it to the experience-reports wiki named in the announcement. The immediate contribution is evidence that helps others assess the problem and compare those possible responses.