Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 1487] ファイルの概要

このコミットは、Go言語のコンパイラ(gc)において、識別子のエクスポートに関する警告メカニズムを改善するものです。具体的には、小文字で始まる識別子が誤ってエクスポートされようとした場合に警告を発するように変更が加えられています。これにより、Go言語の「エクスポートされる識別子は大文字で始まる」という慣習(慣例ではなく言語仕様の一部)がより厳密に適用され、開発者が意図しないエクスポートを防ぐ手助けとなります。

コミット

commit 3decb42e6f519ff324383033777d84e3e097b42f
Author: Russ Cox <rsc@golang.org>
Date:   Thu Jan 15 16:20:21 2009 -0800

    add warning for export of lowercase too.
    
    R=ken
    OCL=22887
    CL=22887

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/3decb42e6f519ff324383033777d84e3e097b42f

元コミット内容

add warning for export of lowercase too.

R=ken
OCL=22887
CL=22887

変更の背景

Go言語では、パッケージ外に公開(エクスポート)される識別子(変数、関数、型など)は、その名前が大文字で始まるという明確なルールがあります。これはGo言語の設計思想の一部であり、コードの可読性と保守性を高めるための重要な慣習です。

このコミットが作成された2009年1月は、Go言語がまだ一般に公開される前の初期開発段階でした。当時のコンパイラは、大文字で始まるべき識別子が小文字で定義されているにもかかわらず、exportsym(シンボルをエクスポート済みとしてマークする関数)が呼び出された場合に、その不整合を警告する機能が不足していた可能性があります。

この変更の背景には、Go言語の設計原則である「明示的なエクスポートルール」をコンパイラレベルでより厳密に強制し、開発者が誤って小文字の識別子をエクスポートしようとした際に、早期にその間違いを検出できるようにするという目的があります。これにより、Go言語のコードベース全体で一貫したエクスポートルールが維持され、将来的な互換性の問題や混乱を防ぐことができます。

前提知識の解説

Go言語のエクスポートルール

Go言語において、識別子(変数名、関数名、型名、メソッド名、フィールド名など)がパッケージ外に公開される(エクスポートされる)かどうかは、その識別子の名前の最初の文字が大文字であるか小文字であるかによって決まります。

  • 大文字で始まる識別子: パッケージ外からアクセス可能です。つまり、エクスポートされます。
  • 小文字で始まる識別子: その識別子が定義されているパッケージ内でのみアクセス可能です。つまり、エクスポートされません。

このルールは非常にシンプルでありながら強力で、Go言語のモジュール性とカプセル化を保証する上で重要な役割を果たします。他の言語でよく見られるpublic, private, protectedといったキーワードはGoには存在せず、この命名規則がその役割を担っています。

gc (Go Compiler)

gcは、Go言語の公式コンパイラの一つであり、Go言語のソースコードを機械語に変換する役割を担っています。Go言語の初期から主要なコンパイラとして開発されてきました。src/cmd/gcディレクトリ以下にそのソースコードが存在し、Go言語の文法解析、型チェック、最適化、コード生成など、コンパイルの全工程を処理します。

export.c

export.cは、gcコンパイラのソースコードの一部であり、シンボルのエクスポートに関する処理を担当しています。具体的には、Go言語のソースコード内で定義されたシンボルが、Goのエクスポートルールに従って正しくエクスポートされるべきか、あるいはパッケージ内部に留まるべきかを判断し、それに応じた処理を行う部分です。このファイルは、コンパイラがシンボルテーブルを構築し、外部に公開されるAPIを決定する上で中心的な役割を果たします。

warn 関数

warn関数は、コンパイラが警告メッセージを出力するために使用される内部関数です。コンパイルエラーではないが、潜在的な問題やGo言語の慣習に反する記述があった場合に、開発者に注意を促すために利用されます。

exportsympackagesym

  • exportsym(s): シンボルsをエクスポート済みとしてマークする関数です。これは、シンボルがGoのエクスポートルール(大文字で始まる)に従って外部に公開されるべき場合に呼び出されます。
  • packagesym(s): シンボルsをパッケージ内部でのみ使用可能としてマークする関数です。これは、シンボルが小文字で始まり、パッケージ内部に留まるべき場合に呼び出されます。

これらの関数は、コンパイラがシンボルの可視性を管理するための重要な内部APIです。

技術的詳細

このコミットは、src/cmd/gc/export.cファイル内のautoexport関数に修正を加えています。autoexport関数は、Goのソースコード内で定義されたシンボルが自動的にエクスポートされるべきかどうかを判断し、適切な処理を行うためのロジックを含んでいます。

変更前のコードでは、シンボルsがエクスポートされるべき(s->name[0] >= 'A' && s->name[0] <= 'Z'、つまり大文字で始まる)と判断された場合、dcladj != exportsymdcladjはシンボル宣言時の調整関数で、exportsymでない場合)に"uppercase missing export"という警告を出力し、その後exportsym(s)を呼び出してシンボルをエクスポート済みとしてマークしていました。しかし、小文字で始まるシンボルがexportsymによってエクスポートされようとした場合の警告は存在しませんでした。

このコミットでは、elseブロック(つまり、シンボルが小文字で始まる場合)に新たな警告ロジックが追加されています。具体的には、if(dcladj == exportsym)という条件が追加され、もし小文字で始まるシンボルに対してdcladjexportsym(エクスポートを意図する関数)であった場合、"export missing uppercase"という警告を出力するように変更されました。その後、packagesym(s)が呼び出され、シンボルはパッケージ内部でのみ使用可能としてマークされます。

この修正により、コンパイラは以下の2つのケースで警告を発するようになります。

  1. 大文字で始まるべきシンボルがエクスポートされていない場合: 既存のwarn("uppercase missing export")が引き続き機能します。
  2. 小文字で始まるシンボルが誤ってエクスポートされようとしている場合: 新たに追加されたwarn("export missing uppercase")が機能します。

これにより、Go言語のエクスポートルールに対するコンパイラのチェックがより堅牢になり、開発者が意図しないエクスポートや命名規則違反を早期に発見できるようになります。

コアとなるコードの変更箇所

--- a/src/cmd/gc/export.c
+++ b/src/cmd/gc/export.c
@@ -75,8 +75,11 @@ autoexport(Sym *s)
 		if(dcladj != exportsym)
 			warn("uppercase missing export");
 		exportsym(s);
-	} else
+	} else {
+		if(dcladj == exportsym)
+			warn("export missing uppercase");
 		packagesym(s);
+	}
 }
 
 void

コアとなるコードの解説

変更はsrc/cmd/gc/export.cファイルのautoexport関数内で行われています。

元のコード:

	} else
		packagesym(s);

この部分では、シンボルsの名前が小文字で始まる場合(ifブロックの条件が偽の場合)、無条件にpackagesym(s)が呼び出され、そのシンボルはパッケージ内部でのみ使用可能として扱われていました。

変更後のコード:

	} else {
		if(dcladj == exportsym)
			warn("export missing uppercase");
		packagesym(s);
	}

この変更により、小文字で始まるシンボルが処理されるelseブロックが波括弧{}で囲まれ、その内部に新たな条件分岐が追加されました。

  • if(dcladj == exportsym): この条件は、現在のシンボルsが宣言された際に、コンパイラがそのシンボルをエクスポートしようとしていたかどうかをチェックします。dcladjはシンボル宣言時の調整関数へのポインタであり、もしそれがexportsym(エクスポートを意図する関数)と等しい場合、それは小文字のシンボルが誤ってエクスポートされようとしている状況を示します。
  • warn("export missing uppercase");: 上記の条件が真であった場合、つまり小文字のシンボルがエクスポートされようとしていた場合に、"export missing uppercase"という警告メッセージがコンパイラによって出力されます。この警告は、開発者に対して「このシンボルは小文字で始まっているためエクスポートされませんが、エクスポートしようとしているように見えます。もしエクスポートしたいのであれば、大文字で始めてください」という意図を伝えます。
  • packagesym(s);: 警告が出力された後も、最終的にはpackagesym(s)が呼び出され、シンボルはGoのエクスポートルールに従ってパッケージ内部でのみ使用可能としてマークされます。これは、警告は出すものの、言語仕様としてのエクスポートルールは厳密に適用されることを意味します。

この修正は、Go言語のコンパイラが、開発者の意図とGoのエクスポートルールの間の不一致をより積極的に検出し、警告することで、コード品質と一貫性を向上させるためのものです。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • GitHubのGo言語リポジトリのコミット履歴
  • Go言語のコンパイラ(gc)のソースコード
  • Go言語のエクスポートルールに関する一般的な情報源(ブログ記事、チュートリアルなど)