Created
December 4, 2018 23:06
-
-
Save jba/aa37cb95d8420719a470339379a88590 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
API Compatability in Go | |
26 November 2018 | |
Jonathan Amsterdam | |
* Goal | |
Help the developer make an informed choice about how to change the semantic version of their module. | |
- Incompatible change (major version bump) | |
- Compatible but visible change (minor version bump) | |
- No visible change (patch bump) | |
Most important: is the new code backwards compatible with the old? | |
From now on, "compatibility" means backwards compatibility. | |
* What is Compatibility? | |
- What do we really mean when we say the new version is backwards-compatible with the old? | |
A better question: | |
- What do we want compatibility to be for our tool? | |
We get to pick a workable definition. | |
Not behavioral compatibility. Has to be something we can compute. | |
Hence compile-time compatibility. | |
* Strict Compile-Time Compatibility | |
- A new version of a package is compatible with the old if every program that compiles with the old version also compiles with the new version. | |
Clear and sane. | |
But too restrictive: | |
- Unkeyed struct literals | |
- Embedding and shadowing | |
- Writing the identical type externally | |
- unsafe.Sizeof and friends | |
* What we Want | |
- Allow valuable changes | |
- Point out incompatibilities | |
- Avoid noise | |
- Keep the underlying principles simple | |
* The Basic Idea | |
For each exported package-level symbol in the old package: | |
- If it was removed or changed incompatibly in the new: incompatible | |
- If the new added an exported symbol: compatible | |
On the right track, but much is missing. | |
* Exposure | |
// pkg | |
type u1 int | |
func (u1) M() {} | |
var V u1 | |
// outside | |
V.M() | |
`u1.M` is visible outside the package | |
* Type Correspondence | |
Type identity doesn't work. Consider: | |
// old | |
type T int | |
// new | |
type u int | |
type T = u | |
Or what if I rename an exposed but unexported type? | |
// old | |
type u1 int | |
var V u1 | |
// new | |
type u2 int | |
var V u2 | |
We need to establish a _correspondence_ between old and new names. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment