[インデックス 14456] ファイルの概要
このコミットは、Go言語の仕様書である doc/go_spec.html
ファイルに対する変更です。具体的には、パッケージ名のスコープに関する記述をより明確にするための修正が行われています。
コミット
spec: be clearer about the scope of a package name
We have the notion of a PackageName, not package identifier.
As is, it could construed that imports that rename a package
don't have an "imported package identifier" but a local one.
R=r, rsc, iant, ken, dsymonds
CC=golang-dev
https://golang.org/cl/6858049
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/e12676304540fa9e160bf4cc28b954574f9ff944
元コミット内容
spec: be clearer about the scope of a package name
We have the notion of a PackageName, not package identifier.
As is, it could construed that imports that rename a package
don't have an "imported package identifier" but a local one.
変更の背景
このコミットの背景には、Go言語のパッケージシステムにおける「パッケージ名 (PackageName)」と「パッケージ識別子 (package identifier)」の概念の明確化があります。
Go言語では、import
宣言によって外部パッケージをプログラムに取り込みます。この際、通常はインポートパスの最後の要素がパッケージ名として使用されますが、import foo "path/to/bar"
のようにエイリアス(別名)を付けてインポートすることも可能です。
元の仕様書の記述では、「imported package identifier(インポートされたパッケージ識別子)」という表現が使われていました。しかし、コミットメッセージにあるように、Go言語の設計思想としては「PackageName(パッケージ名)」という概念があり、「package identifier(パッケージ識別子)」という用語は、特にエイリアスを付けてインポートした場合に混乱を招く可能性がありました。
具体的には、エイリアスを付けてインポートした場合、そのエイリアスはローカルな識別子であり、元のパッケージの「識別子」とは異なるものと解釈される恐れがありました。この曖昧さを解消し、Go言語のパッケージシステムにおける「名前」のスコープと性質をより正確に反映させるために、仕様書の文言が修正されました。これにより、インポートされたパッケージの「名前」のスコープがファイルブロックであることを明確にしています。
前提知識の解説
Go言語のパッケージシステム
Go言語は、コードのモジュール化と再利用を促進するためにパッケージシステムを採用しています。
- パッケージ (Package): Goプログラムの基本的な構成単位です。関連する関数、型、変数などをまとめたものです。
- パッケージ名 (Package Name): パッケージを識別するための名前です。通常、パッケージ内のソースファイルの先頭に
package <name>
と記述されます。この名前は、パッケージがコンパイルされた際に生成されるオブジェクトファイルの名前にも影響します。 - インポートパス (Import Path): パッケージを一意に特定するためのパスです。例えば、
"fmt"
や"net/http"
などがあります。これは、Goモジュールシステムにおけるモジュールパスとリポジトリの構造に対応しています。 - インポート宣言 (Import Declaration): 別のパッケージで定義された識別子(関数、変数、型など)を現在のファイルで使用するために行われる宣言です。
import "path/to/package"
の形式で記述します。 - エイリアスインポート (Aliased Import):
import <alias> "path/to/package"
のように、インポートするパッケージに別名を付けることができます。これにより、同じ名前のパッケージが複数ある場合や、長いパッケージ名を短くしたい場合に便利です。例えば、import net "net/http"
とすると、http.Get
の代わりにnet.Get
と書けるようになります。
識別子 (Identifier) とスコープ (Scope)
- 識別子 (Identifier): プログラム内で変数、関数、型、パッケージなどを参照するために使われる名前です。例えば、
main
、fmt.Println
のPrintln
、myVariable
などが識別子です。 - スコープ (Scope): プログラムのテキスト内で、識別子が意味を持つ(参照可能である)領域を指します。Go言語では、識別子のスコープは以下のブロックによって定義されます。
- ユニバースブロック (Universe Block): 組み込みの識別子(
int
,true
,false
,make
,len
など)のスコープです。プログラム全体で利用可能です。 - パッケージブロック (Package Block): パッケージレベルで宣言された識別子(トップレベルの変数、定数、関数、型)のスコープです。同じパッケージ内のすべてのファイルで利用可能です。
- ファイルブロック (File Block): 各ソースファイル内で宣言された識別子のスコープです。特に、インポートされたパッケージの識別子や、ファイル内で宣言された型や関数のスコープがこれに該当します。
- ローカルブロック (Local Block): 関数内や制御構造(
if
,for
,switch
など)のブロック内で宣言された識別子のスコープです。そのブロック内でのみ有効です。
- ユニバースブロック (Universe Block): 組み込みの識別子(
このコミットでは、特に「インポートされたパッケージの識別子」のスコープに関する記述が、「インポートされたパッケージのパッケージ名のスコープ」という表現に修正され、より正確な用語が使用されています。これは、Go言語の設計において、インポートされたパッケージは「識別子」としてではなく、「パッケージ名」として扱われるというニュアンスを強調しています。エイリアスインポートの場合、エイリアス自体はローカルな識別子ですが、それが参照するのはあくまでインポートされたパッケージの「名前」であるという点が重要です。
技術的詳細
このコミットの技術的な詳細としては、Go言語の仕様書における用語の厳密性が向上した点が挙げられます。
Go言語の仕様書は、言語の挙動を定義する最も権威あるドキュメントです。そのため、そこで使用される用語は非常に重要であり、曖昧さがあってはなりません。
元の記述 <li>The scope of an imported package identifier is the file block of the file containing the import declaration.</li>
は、「インポートされたパッケージ識別子」という表現を用いていました。しかし、Go言語の文脈では、import "fmt"
のようにインポートされた fmt
は、そのパッケージの「名前」として機能します。もし import f "fmt"
のようにエイリアス f
を付けた場合、f
はローカルな識別子であり、fmt
パッケージの「識別子」とは異なります。この場合、「インポートされたパッケージ識別子」という表現は、エイリアス f
を指すのか、それとも fmt
パッケージそのものを指すのか、という点で混乱を招く可能性がありました。
このコミットでは、この曖昧さを解消するために、imported package identifier
を the package name of an imported package
に変更しました。
変更後の記述: <li>The scope of the package name of an imported package is the file block of the file containing the import declaration.</li>
この変更により、以下の点が明確になります。
- 「パッケージ名」の強調: Go言語では、インポートされたパッケージは「パッケージ名」によって参照されるという概念が強調されます。これは、
fmt.Println
のfmt
がパッケージ名であることを示唆しています。 - エイリアスとの区別: エイリアス(例:
f
inimport f "fmt"
) は、あくまでそのファイル内でのみ有効なローカルな識別子であり、インポートされたパッケージそのものの「識別子」とは異なるというニュアンスが強まります。エイリアスは、インポートされたパッケージの「パッケージ名」にアクセスするための手段として機能します。 - スコープの明確化: インポートされたパッケージの「パッケージ名」のスコープが、その
import
宣言を含むファイル全体(ファイルブロック)であることを明確にしています。これは、そのファイル内でそのパッケージ名を使って識別子にアクセスできることを意味します。
この修正は、Go言語の設計思想、特にパッケージの命名と参照のメカニズムに関する理解を深める上で重要な、細かではあるが本質的な改善と言えます。仕様書の正確性を高めることで、開発者がGo言語の挙動をより正確に理解し、誤解を避けることに貢献します。
コアとなるコードの変更箇所
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,6 +1,6 @@
<!--{
"Title": "The Go Programming Language Specification",
-\t"Subtitle": "Version of November 17, 2012",
+\t"Subtitle": "Version of November 21, 2012",
"Path": "/ref/spec"
}-->
@@ -1529,7 +1529,7 @@ Go is lexically scoped using blocks:
or function (but not method) declared at top level (outside any
function) is the package block.</li>
-\t<li>The scope of an imported package identifier is the file block
+\t<li>The scope of the package name of an imported package is the file block
\t of the file containing the import declaration.</li>
\t<li>The scope of an identifier denoting a function parameter or
コアとなるコードの解説
このコミットにおける主要な変更は、doc/go_spec.html
ファイル内の以下の行です。
変更前:
<li>The scope of an imported package identifier is the file block
of the file containing the import declaration.</li>
変更後:
<li>The scope of the package name of an imported package is the file block
of the file containing the import declaration.</li>
この変更は、Go言語の仕様書における「スコープ」のセクション、特にインポートされたパッケージに関する記述を修正しています。
Subtitle
の変更: まず、ファイルの冒頭にある仕様書のバージョン日付が「November 17, 2012」から「November 21, 2012」に更新されています。これは、このコミットが仕様書の内容を更新したことを示しています。- 主要な変更点: 1532行目のリスト項目が修正されています。
- 元の記述では「
imported package identifier
(インポートされたパッケージ識別子)」という表現が使われていました。 - これが「
the package name of an imported package
(インポートされたパッケージのパッケージ名)」という表現に修正されました。
- 元の記述では「
この修正の意図は、前述の「変更の背景」と「技術的詳細」で述べた通り、Go言語におけるパッケージの参照方法とスコープに関する用語の厳密性を高めることにあります。Goでは、インポートされたパッケージは、その「パッケージ名」を通じてアクセスされるのが一般的であり、エイリアスを使用しない限り、そのパッケージ名がそのファイル内での参照点となります。この変更により、仕様書がより正確にGo言語のセマンティクスを反映するようになりました。
関連リンク
- Go CL (Code Review) 6858049: https://golang.org/cl/6858049
参考にした情報源リンク
- Go Programming Language Specification: https://go.dev/ref/spec (現在の最新版)
- Go Modules Reference: https://go.dev/ref/mod
- Go言語のパッケージとモジュールについて (一般的な解説): https://go.dev/doc/code (Go公式ドキュメントのCode organizationセクションなど)
- Go言語のスコープと宣言について (一般的な解説): https://go.dev/doc/effective_go#declarations_and_scope (Effective GoのDeclarations and scopeセクションなど)
- Go言語の import 宣言について (一般的な解説): https://go.dev/ref/spec#Import_declarations (Go言語仕様のImport declarationsセクション)
- Go言語の識別子について (一般的な解説): https://go.dev/ref/spec#Identifiers (Go言語仕様のIdentifiersセクション)
- Go言語のブロックとスコープについて (一般的な解説): https://go.dev/ref/spec#Blocks (Go言語仕様のBlocksセクション)
- Go言語のパッケージ名とインポートパスに関する議論 (Stack Overflowなど): https://stackoverflow.com/questions/tagged/go-packages (一般的な情報源として)
- Go言語の仕様書変更履歴 (GitHubリポジトリ): https://github.com/golang/go/commits/master/doc/go_spec.html (コミット履歴を追うための情報源として)