[インデックス 1037] ファイルの概要
このコミットは、Go言語の初期段階(2008年11月)におけるシンボル命名規則の大幅な変更を示しています。Russ Cox氏により実装されたこの変更では、従来のアンダースコア(_)ベースの命名規則から、Unicode文字のセンタードット(·)を使用した新しい命名規則への移行が行われました。
コミット
コミットハッシュ: c249a8de32cf5d2ceb0e896868699195b0820109
作成者: Russ Cox rsc@golang.org
日付: 2008年11月3日 15:36:08 -0800
メッセージ: "rename various magic names."
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/c249a8de32cf5d2ceb0e896868699195b0820109
元コミット内容
このコミットでは、以下の主要な変更が行われました:
-
sigi(シグナル・インターフェース)とsigt(シグナル・タイプ)の命名変更:
sys·sigi_inter
→sigi·inter
sys·sigt_int
→sigt·int
Package·sigt_Type
→sigt·Package.Type
-
ローカル型の命名規則変更:
- ファイル
x.go
内のローカル型T
:T_x
→T·x
- 重複する場合の命名:
T_x_1
→T·x·1
- ファイル
-
メソッド名の命名規則変更:
- 型
T
のメソッドM
:T_M
→T·M
- 型
-
埋め込み型の適切な処理の実装
-
init関数のみがアンダースコアを使用する規則の確立
変更の背景
このコミットは、Go言語の開発初期段階における重要な設計決定の一つです。2008年当時、Go言語はまだ公開前の状態であり、言語設計者らは最適な命名規則を模索していました。
主な背景要因:
-
パーサーの競合回避: ピリオド(.)とスラッシュ(/)がアセンブラパーサーで句読点として扱われるため、階層的な名前の明確な表現が必要でした。
-
Plan 9の影響: Go言語のツールチェーンはPlan 9のCコンパイラから派生しており、Plan 9では識別子でのUnicode文字の使用が積極的に採用されていました。
-
名前空間の明確化: パッケージパスと関数名を視覚的かつ機能的に分離する必要がありました。
前提知識の解説
センタードット(·)文字について
Unicode値: U+00B7(16進)
文字名: Middle Dot
ブロック: Latin-1 Supplement
この文字は、Go言語の内部実装において特別な意味を持ちます:
- アセンブリでの名前空間分離:
fmt·Printf
のような形式で使用 - オブジェクトファイルでの変換: センタードットは通常のドット(.)に変換される
- 内部リンカによる解釈: 名前空間分離文字として処理される
Go言語の初期開発タイムライン
- 2007年9月21日: Robert Griesemer、Rob Pike、Ken Thompsonが設計目標を策定開始
- 2008年1月: Ken Thompsonがコンパイラ作業を開始(C言語出力)
- 2008年中期: 本格的なプロダクションコンパイラの開発開始
- 2008年11月: 本コミットの実装(命名規則の大幅変更)
- 2009年11月: Go言語の正式発表
技術的詳細
シンボル生成の変更
このコミットでは、methodsym
関数の導入により、メソッドシンボルの生成方法が統一されました。
変更前の実装:
snprint(namebuf, sizeof(namebuf), "%s_%s",
f->sym->name, b->name);
変更後の実装:
p->to.sym = methodsym(lookup(b->name), f->type);
型情報の扱い
構造体Type
からxsym
フィールドが削除され、代わりにvargen
フィールドが追加されました。これにより、型の一意性の管理方法が改善されました。
埋め込み型の処理
埋め込み型の処理において、センタードットを含む名前から基本名を抽出する機能が追加されました:
enum { CenterDot = 0xB7 };
name = s->name;
if(utfrune(s->name, CenterDot)) {
name = strdup(s->name);
*utfrune(name, CenterDot) = 0;
}
コアとなるコードの変更箇所
1. methodsym関数の実装(src/cmd/gc/dcl.c)
Sym*
methodsym(Sym *nsym, Type *t)
{
Sym *s;
char buf[NSYMB];
s = t->sym;
if(s == S || isptr[t->etype] && s == t->type->sym)
s = t->type->sym;
if(s == S)
goto bad;
snprint(buf, sizeof(buf), "%#hT·%s", t, nsym->name);
return pkglookup(buf, s->opackage);
bad:
yyerror("illegal <this> type: %T", t);
return S;
}
2. 型の表示形式変更(src/cmd/gc/subr.c)
if(exporting) {
if(fp->flags & FmtShort)
fmtprint(fp, "%hS", s);
else
fmtprint(fp, "%lS", s);
if(strcmp(s->opackage, package) == 0)
if(s->otype != t || !s->export) {
fmtprint(fp, "·%s", filename);
if(t->vargen)
fmtprint(fp, "·%d", t->vargen);
}
return 0;
}
3. ランタイム定義の変更(src/runtime/iface.c)
// 変更前
Sigi sys·sigi_inter[2] = { (byte*)"interface {}", 0, 0, nil, 0, 0 };
// 変更後
Sigi sigi·inter[2] = { (byte*)"interface {}", 0, 0, nil, 0, 0 };
コアとなるコードの解説
methodsym関数の動作原理
methodsym
関数は、メソッドのシンボル名を生成する中核的な機能です:
- 型情報の取得: 引数の型
t
からシンボルs
を取得 - ポインタ型の処理: ポインタ型の場合、指し示される型のシンボルを使用
- 文字列フォーマット:
%#hT·%s
形式でシンボル名を構築 - パッケージ情報の保持:
pkglookup
を使用してパッケージ情報を維持
型表示の新フォーマット
新しい型表示システムでは:
- 短縮形式:
%hS
フラグを使用 - 完全形式:
%lS
フラグを使用 - ローカル型の識別: ファイル名とvargenを使用した一意性の確保
エラーハンドリングの改善
従来の実装では、不正な型に対するエラーハンドリングが不十分でしたが、新しい実装ではyyerror
を使用した適切なエラー報告が実装されています。