[インデックス 12865] ファイルの概要
このコミットは、Go言語のツールチェインの一部である cmd/api
コマンドの動作を変更し、APIの追加を許可するように修正したものです。これにより、既存のAPIとの互換性を維持しつつ、新しいAPI要素が追加された場合に cmd/api
がエラーを報告しないようになります。
コミット
commit edf8b03fef1ab4bf8de7d1f01f3110996a6c9f9c
Author: Shenghou Ma <minux.ma@gmail.com>
Date: Tue Apr 10 22:12:09 2012 +0800
cmd/api: allow addition of API
R=bradfitz, rsc
CC=golang-dev
https://golang.org/cl/5991081
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/edf8b03fef1ab4bf8de7d1f01f3110996a6c9f9c
元コミット内容
cmd/api: allow addition of API
R=bradfitz, rsc
CC=golang-dev
https://golang.org/cl/5991081
変更の背景
Go言語は、その安定したAPI互換性ポリシーで知られています。これは、Go 1のリリース以降、既存のコードが新しいバージョンのGoでも動作し続けることを保証するための重要な原則です。cmd/api
ツールは、このAPI互換性を強制するための主要なツールの一つとして機能します。
元々、cmd/api
は、Goの標準ライブラリのAPIが以前のバージョンと比較して変更されていないことを検証するために使用されていました。これには、APIの削除、変更、そして追加も含まれていました。つまり、新しい関数、メソッド、型などが追加された場合でも、cmd/api
はそれを「変更」とみなし、互換性のない変更としてフラグを立てていました。
しかし、Go言語の進化の過程で、APIの追加は後方互換性を壊すものではなく、むしろ言語の機能拡張や改善のために必要不可欠であることが認識されました。APIの追加は、既存のコードの動作に影響を与えないため、Goの互換性ポリシーに反しません。このコミットは、cmd/api
の動作をこの新しい理解に合わせ、APIの追加を互換性のある変更として扱うように修正することを目的としています。これにより、開発者は新しいAPIを安心して追加できるようになり、cmd/api
は本当に互換性を壊す変更(APIの削除やシグネチャの変更など)に焦点を当てることができるようになります。
前提知識の解説
cmd/api
とは
cmd/api
は、Go言語の標準ライブラリのAPI(Application Programming Interface)の互換性をチェックするためのコマンドラインツールです。Go 1の互換性保証の重要な部分を担っており、Goの新しいバージョンがリリースされる際に、以前のバージョンとのAPI互換性が維持されていることを検証するために使用されます。
このツールは、Goのソースコードを解析し、公開されている(エクスポートされた)型、関数、メソッド、定数などのAPI要素を抽出します。そして、現在のAPI定義と、以前のバージョンのAPI定義(通常はGo 1のAPI)を比較します。比較の結果、以下のような変更を検出します。
- APIの削除: 既存のAPI要素が削除された場合。これは互換性を壊す変更です。
- APIの変更: 既存のAPI要素のシグネチャ(引数、戻り値、型など)が変更された場合。これも互換性を壊す変更です。
- APIの追加: 新しいAPI要素が追加された場合。このコミット以前は互換性を壊す変更と見なされていましたが、このコミット以降は許可されるようになりました。
cmd/api
は、これらの変更を報告することで、Goのコア開発者がAPI互換性ポリシーに違反する変更を誤って導入するのを防ぐのに役立ちます。
GoのAPI互換性ポリシー
Go言語は、Go 1のリリース以降、「Go 1の互換性保証」という強力なポリシーを掲げています。これは、Go 1で書かれたプログラムは、Goの将来のバージョンでもコンパイルされ、動作し続けることを保証するというものです。このポリシーは、Goが安定したプラットフォームとして広く採用される上で非常に重要な要素となっています。
API互換性ポリシーの主な原則は以下の通りです。
- 既存のAPIの削除や変更は原則禁止: 一度公開されたAPIは、特別な理由がない限り削除されたり、そのシグネチャが変更されたりすることはありません。これにより、既存のコードが壊れるのを防ぎます。
- APIの追加は許可: 新しい関数、型、メソッドなどを追加することは、既存のコードの動作に影響を与えないため、互換性のある変更と見なされます。このコミットは、
cmd/api
がこの原則に沿って動作するように調整するものです。 - 動作の変更は慎重に: APIのシグネチャは変わらなくても、その動作が変更される場合は、既存のコードに影響を与える可能性があるため、非常に慎重に扱われます。
このポリシーにより、Go開発者は安心してGoの新しいバージョンにアップグレードでき、依存関係の管理やコードのメンテナンスの負担が軽減されます。
技術的詳細
このコミットは、src/cmd/api/goapi.go
ファイル内のAPI比較ロジックを修正しています。goapi.go
は、GoのAPI定義を読み込み、比較を行う主要なファイルです。
cmd/api
は、2つのAPIリスト(通常は古いAPIと新しいAPI)を比較し、差分を検出します。この比較は、API要素をソートされたリストとして扱い、両方のリストを同時に走査することで行われます。
変更が加えられたのは、main
関数内の switch
ステートメントの一部です。この switch
ステートメントは、古いAPIリスト (v1
) と新しいAPIリスト (v2
) の要素を比較し、それぞれのケースでどのような処理を行うかを決定します。
元のコードでは、新しいAPIリスト (v2
) にのみ存在する要素(つまり、APIの追加)が検出された場合、changes = true
と設定していました。これは、APIの追加も互換性のない変更として扱っていたことを意味します。
変更後のコードでは、この changes = true
の行が削除され、代わりに // we allow API additions now
というコメントが追加されています。これにより、APIの追加が検出されても changes
フラグが設定されなくなり、cmd/api
はAPIの追加を互換性のある変更として認識し、エラーとして報告しなくなります。
take(&v2)
は、新しいAPIリストから現在の要素を取り除き、次の要素に進むためのヘルパー関数です。この操作自体は変更されていません。重要なのは、このケースで changes
フラグを設定しないというロジックの変更です。
この修正により、cmd/api
はGoのAPI互換性ポリシーの進化に適合し、APIの追加が許可されるという現実を反映するようになりました。
コアとなるコードの変更箇所
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -147,7 +147,7 @@ func main() {
changes = true
case len(v1) == 0 || v1[0] > v2[0]:
fmt.Fprintf(bw, "+%s\n", take(&v2))
- changes = true
+ // we allow API additions now
default:
take(&v1)
take(&v2)
コアとなるコードの解説
変更されたコードは src/cmd/api/goapi.go
ファイルの main
関数内にあります。
case len(v1) == 0 || v1[0] > v2[0]:
fmt.Fprintf(bw, "+%s\n", take(&v2))
- changes = true
+ // we allow API additions now
この case
文は、APIの比較ロジックの一部です。
len(v1) == 0
: これは、古いAPIリスト (v1
) が空になったことを意味します。つまり、新しいAPIリスト (v2
) にはまだ要素が残っているが、古いAPIには対応する要素がない状態です。これは新しいAPIの追加を意味します。v1[0] > v2[0]
: これは、新しいAPIリストの現在の要素 (v2[0]
) が、古いAPIリストの現在の要素 (v1[0]
) よりも「小さい」ことを意味します(ソート順に基づきます)。これは、古いAPIには存在しない新しいAPI要素がv2
に追加されたことを示唆します。
これらの条件のいずれかが真である場合、それは新しいAPI要素が追加されたことを示します。
元のコードでは、この case
のブロック内で changes = true
という行がありました。これは、APIの追加が検出された場合に、changes
というブール変数に true
を設定していました。この changes
変数は、最終的に cmd/api
が互換性のない変更を検出したかどうかを示すために使用されていました。changes
が true
になると、cmd/api
はエラーコードを返したり、変更を報告したりしていました。
このコミットでは、changes = true
の行が削除され、代わりに // we allow API additions now
というコメントが追加されています。この変更により、APIの追加が検出されても changes
変数は true
に設定されなくなります。結果として、cmd/api
はAPIの追加を互換性のない変更とは見なさなくなり、エラーとして報告しなくなります。
fmt.Fprintf(bw, "+%s\n", take(&v2))
の行は、追加されたAPI要素を標準出力(または指定された出力ストリーム)に +
プレフィックスを付けて表示する役割を担っています。これはデバッグや情報提供のために残されていますが、この変更によってツールの終了ステータスには影響を与えなくなります。
関連リンク
- Go 1 Compatibility Guarantee: https://go.dev/doc/go1compat
cmd/api
のソースコード (現在のバージョン): https://github.com/golang/go/tree/master/src/cmd/api
参考にした情報源リンク
- コミット:
edf8b03fef1ab4bf8de7d1f01f3110996a6c9f9c
(この解説の対象となるコミット自体) - Go言語の公式ドキュメント (特にGo 1の互換性保証に関するセクション)
cmd/api
ツールのソースコード