# Checking Go Package API Compatibility
The `apidiff` tool in this directory determines whether two versions of the same
package are compatible. The goal is to help the developer make an informed
choice of semantic version after they have changed the code of their module.
`apidiff` reports two kinds of changes: incompatible ones, which require
incrementing the major part of the semantic version, and compatible ones, which
require a minor version increment. If no API changes are reported but there are
code changes that could affect client code, then the patch version should
be incremented.
Because `apidiff` ignores package import paths, it may be used to display API
differences between any two packages, not just different versions of the same
package.
The current version of `apidiff` compares only packages, not modules.
## Compatibility Desiderata
Any tool that checks compatibility can offer only an approximation. No tool can
detect behavioral changes; and even if it could, whether a behavioral change is
a breaking change or not depends on many factors, such as whether it closes a
security hole or fixes a bug. Even a change that causes some code to fail to
compile may not be considered a breaking change by the developers or their
users. It may only affect code marked as experimental or unstable, for
example, or the break may only manifest in unlikely cases.
For a tool to be useful, its notion of compatibility must be relaxed enough to
allow reasonable changes, like adding a field to a struct, but strict enough to
catch significant breaking changes. A tool that is too lax will miss important
incompatibilities, and users will stop trusting it; one that is too strict may
generate so much noise that users will ignore it.
To a first approximation, this tool reports a change as incompatible if it could
cause client code to stop compiling. But `apidiff` ignores five ways in which
code may fail to compile after a change. Three of them are mentioned in the
[Go 1 Compatibility Guarantee](https://golang.org/doc/go1compat).
### Unkeyed Struct Literals
Code that uses an unkeyed struct literal would fail to compile if a field was
added to the struct, making any such addition an incompatible change. An example:
```
// old
type Point struct { X, Y int }
// new
type Point struct { X, Y, Z int }
// client
p := pkg.Point{1, 2} // fails in new because there are more fields than expressions
```
Here and below, we provide three snippets: the code in the old version of the
package, the code in the new version, and the code written in a client of the package,
which refers to it by the name `pkg`. The client code compiles against the old
code but not the new.
### Embedding and Shadowing
Adding an exported field to a struct can break code that embeds that struct,
because the newly added field may conflict with an identically named field
at the same struct depth. A selector referring to the latter would become
ambiguous and thus erroneous.
```
// old
type Point struct { X, Y int }
// new
type Point struct { X, Y, Z int }
// client
type z struct { Z int }
var v struct {
pkg.Point
z
}
_ = v.Z // fails in new
```
In the new version, the last line fails to compile because there are two embedded `Z`
fields at the same depth, one from `z` and one from `pkg.Point`.
### Using an Identical Type Externally
If it is possible for client code to write a type expression representing the
underlying type of a defined type in a package, then external code can use it in
assignments involving the package type, making any change to that type incompatible.
```
// old
type Point struct { X, Y int }
// new
type Point struct { X, Y, Z int }
// client
var p struct { X, Y int } = pkg.Point{} // fails in new because of Point's extra field
```
Here, the external code could have used the provided name `Point`, but chose not
to. I'll have more to say about this and related examples later.
### unsafe.Sizeof and Friends
Since `unsafe.Sizeof`, `unsafe.Offsetof` and `unsafe.Alignof` are constant
expressions, they can be used in an array type literal:
```
// old
type S struct{ X int }
// new
type S struct{ X, y int }
// client
var a [unsafe.Sizeof(pkg.S{})]int = [8]int{} // fails in new because S's size is not 8
```
Use of these operations could make many changes to a type potentially incompatible.
### Type Switches
A package change that merges two different types (with same underlying type)
into a single new type may break type switches in clients that refer to both
original types:
```
// old
type T1 int
type T2 int
// new
type T1 int
type T2 = T1
// client
switch x.(type) {
case T1:
case T2:
} // fails with new because two cases have the same type
```
This sort of incompatibility is sufficiently esoteric to ignore; the tool allows
merging types.
## First Attempt at a Definition
Our first attempt at defining compatibility captures the idea that all the
exported names in the old package must have compatible equivalents in the new
package.
A new package is compatible with an old one if and only if:
- For every exported package-level name in the old package, the same name is
declared in the new at package level, and
- the names denote the same kind of object (e.g. both are variables), and
- the types of the objects are compatible.
We will work out the details (and make some corrections) below, but it is clear
already that we will need to determine what makes two types compatible. And
whatever the definition of type compatibility, it's certainly true that if two
types are the same, they are compatible. So we will need to decide what makes an
old and new type the same. We will call this sameness relation _correspondence_.
## Type Correspondence
Go already has a definition of when two types are the same:
[type identity](https://golang.org/ref/spec#Type_identity).
But identity isn't adequate for our purpose: it says that two defined
types are identical if they arise from the same definition, but it's unclear
what "same" means when talking about two different packages (or two versions of
a single package).
The obvious change to the definition of identity is to require that old and new
[defined types](https://golang.org/ref/spec#Type_definitions)
have the same name instead. But that doesn't work either, for two
reasons. First, type aliases can equate two defined types with different names:
```
// old
type E int
// new
type t int
type E = t
```
Second, an unexported type can be renamed:
```
// old
type u1 int
var V u1
// new
type u2 int
var V u2
```
Here, even though `u1` and `u2` are unexported, their exported fields and
methods are visible to clients, so they are part of the API. But since the name
`u1` is not visible to clients, it can be changed compatibly. We say that `u1`
and `u2` are _exposed_: a type is exposed if a client package can declare variables of that type.
We will say that an old defined type _corresponds_ to a new one if they have the
same name, or one can be renamed to the other without otherwise changing the
API. In the first example above, old `E` and new `t` correspond. In the second,
old `u1` and new `u2` correspond.
Two or more old defined types can correspond to a single new type: we consider
"merging" two types into one to be a compatible change. As mentioned above,
code that uses both names in a type switch will fail, but we deliberately ignore
this case. However, a single old type can correspond to only one new type.
So far, we've explained what correspondence means for defined types. To extend
the definition to all types, we parallel the language's definition of type
identity. So, for instance, an old and a new slice type correspond if their
element types correspond.
## Definition of Compatibility
We can now present the definition of compatibility used by `apidiff`.
### Package Compatibility
> A new package is compatible with an old one if:
>1. Each exported name in the old package's scope also appears in the new
>package's s
没有合适的资源?快使用搜索试试~ 我知道了~
[mirror] Go Tools.zip
共2000个文件
go:1626个
txt:217个
md:40个
需积分: 5 0 下载量 158 浏览量
2023-12-28
20:46:39
上传
评论
收藏 4.37MB ZIP 举报
温馨提示
[mirror] Go Tools
资源推荐
资源详情
资源评论
收起资源包目录
[mirror] Go Tools.zip (2000个子文件)
libimportsar.a 9KB
long.a 802B
short.a 710B
hello.c 77B
style.css 14KB
styles.css 10KB
jquery.treeview.css 3KB
dir.css 2KB
article.css 2KB
notes.css 602B
static.go 1.08MB
tsprotocol.go 210KB
zstdlib.go 198KB
completion.go 97KB
packages_test.go 89KB
api_json.go 87KB
inline.go 84KB
snapshot.go 81KB
builder.go 76KB
marker_test.go 74KB
yacc.go 70KB
check.go 62KB
ssa.go 61KB
generator.go 61KB
tsjson.go 55KB
fix_test.go 53KB
analysis.go 51KB
tsserver.go 50KB
fix.go 50KB
editor.go 49KB
diagnostics_test.go 48KB
settings.go 48KB
rename.go 46KB
extract.go 44KB
command.go 43KB
packages.go 43KB
index.go 42KB
view.go 40KB
inline_test.go 40KB
a.go 39KB
golist.go 37KB
iexport.go 35KB
errorcode.go 34KB
ops.go 34KB
file.go 34KB
loader.go 33KB
overlay_test.go 33KB
session.go 33KB
parser.go 33KB
printf.go 32KB
hover.go 32KB
builder_test.go 32KB
gcimporter_test.go 31KB
rename_check.go 30KB
workspace_test.go 28KB
checker.go 28KB
modfile_test.go 28KB
mod_test.go 28KB
semantic.go 27KB
diagnostics.go 27KB
cmd.go 27KB
integration_test.go 27KB
iimport.go 27KB
rename_test.go 26KB
conn.go 26KB
check.go 26KB
godoc.go 26KB
vuln_test.go 26KB
imports_test.go 25KB
describe.go 25KB
server.go 25KB
completion_test.go 25KB
parse.go 25KB
load.go 24KB
referrers.go 24KB
main.go 24KB
expectation.go 24KB
falcon.go 23KB
sparse.go 23KB
graph.go 23KB
objectpath.go 23KB
a.go 23KB
serve.go 23KB
asmdecl.go 23KB
references.go 22KB
refs.go 22KB
code_action.go 22KB
loader_test.go 21KB
analysistest.go 21KB
generate.go 21KB
mod.go 21KB
stringer.go 21KB
export.go 20KB
builder_generic_test.go 20KB
filecache.go 20KB
general.go 20KB
interp.go 20KB
main.go 19KB
diagnostics.go 19KB
change_signature.go 19KB
共 2000 条
- 1
- 2
- 3
- 4
- 5
- 6
- 20
资源评论
Lei宝啊
- 粉丝: 2064
- 资源: 1330
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功