Description
This issue describes a language feature proposal to Immutable Types. It targets the current Go 1.x (> 1.11) language specification and doesn't violate the Go 1 compatibility promise. It also describes an even better approach to immutability for a hypothetical, backward-incompatible Go 2 language specification.
The linked Design Document describes the entire proposal in full detail, including the current problems, the benefits, the proposed changes, code examples and the FAQ.
Updates
- October 7th: This proposal is approaching its second revision addressing major flaws such as
const
-poisoning, verbosity,const
-keyword overloading and others.
Introduction
Immutability is a technique used to prevent mutable shared state, which is a very common source of bugs, especially in concurrent environments, and can be achieved through the concept of immutable types.
Bugs caused by mutable shared state are not only hard to find and fix, but they're also hard to even identify. Such kind of problems can be avoided by systematically limiting the mutability of certain objects in the code. But a Go 1.x developer's current approach to immutability is manual copying, which lowers runtime performance, code readability, and safety. Copying-based immutability makes code verbose, imprecise and ambiguous because the intentions of the code author are never clear. Documentation can be rather misleading and doesn't solve the problems either.
Immutable Types in Go 1.x
Immutable types can help achieve this goal more elegantly improving the safety, readability, and expressiveness of the code. They're based on 5 fundamental rules:
- I. Each and every type has an immutable counterpart.
- II. Assignments to objects of an immutable type are illegal.
- III. Calls to mutating methods (methods with a mutable receiver type) on objects of an immutable type are illegal.
- IV. Mutable types can be cast to their immutable counterparts, but not the other way around.
- V. Immutable interface methods must be implemented by a method with an immutable receiver type.
These rules can be enforced by making the compiler scan all objects of immutable types for illegal modification attempts, such as assignments and calls to mutating methods and fail the compilation. The compiler would also need to check, whether types correctly implement immutable interface methods.
To prevent breaking Go 1.x compatibility this document describes a backward-compatible approach to adding support for immutable types by overloading the const
keyword (see here for more details) to act as an immutable type qualifier.
Immutable types can be used for:
- immutable fields
- immutable methods
- immutable arguments
- immutable return values
- immutable variables
- immutable interfaces
- immutable reference types and containers
- immutable package-scope variables
Immutable Types in Go 2.x
Ideally, a safe programming language should enforce immutability by default where all types are immutable unless they're explicitly qualified as mutable because forgetting to make an object immutable is easier, than accidentally making it mutable. But this concept would require significant,
backward-incompatible language changes breaking existing Go 1.x code. Thus such an approach to immutability would only be possible in a new backward-incompatible Go 2.x language specification.
Related Proposals
This proposal is somewhat related to:
- proposal: spec: add read-only slices and maps as function arguments #20443
- proposal: spec: read-only types #22876
- proposal: frozen slices / arrays / maps and derivatives (immutable subscript-able objects) #22048
Detailed comparisons to other proposals are described in the design document, section 5..
Please feel free to file issues and pull requests, become a stargazer,
contact me directly at [email protected] and join the conversation on Slack Gophers (@romshark), the international and the russian Telegram groups, as well as the original golangbridge, reddit and hackernews posts! Thank you!