[インデックス 1602] ファイルの概要
このコミットは、Go言語の初期開発段階における実験的な変更を記録しています。具体的には、Goのコードを整形(pretty print)する際に、func
、const
、type
といったキーワードの代わりに、実験的にdef
という文字列を出力するためのフラグ-def
を追加するものです。これは、Go言語の構文がまだ流動的であった時期に、キーワードの選択肢を模索していた痕跡と考えられます。
コミット
commit b67603dfef4bd4f0c8e66af41fb461a502bbaebb
Author: Robert Griesemer <gri@golang.org>
Date: Mon Feb 2 11:51:07 2009 -0800
- added experimental flag '-def': will print (not parse!)
'def' instead of 'func', 'const', or 'type'
R=r
OCL=24092
CL=24094
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b67603dfef4bd4f0c8e66af41fb461a502bbaebb
元コミット内容
このコミットは、Go言語のコード整形ツール(pretty/printer.go
)に実験的なフラグ-def
を追加します。このフラグが有効な場合、func
(関数)、const
(定数)、type
(型)の宣言キーワードの代わりに、def
という文字列が出力されるようになります。ただし、これはあくまで出力(整形)時の表示変更であり、Goコンパイラがdef
をキーワードとして解析するわけではありません。
変更の背景
Go言語は2009年にGoogleで開発が始まり、その初期段階では言語仕様やキーワードの選定が活発に行われていました。このコミットは、その過程でfunc
、const
、type
といった宣言キーワードの代替案としてdef
というキーワードが検討されていた可能性を示唆しています。
当時のGo言語の設計目標の一つに、既存の言語(C++、Javaなど)の複雑さを避け、シンプルで読みやすい構文を目指すというものがありました。def
というキーワードは、Pythonなどの他の言語で関数定義に使われることがあり、より汎用的な「定義」を意味するキーワードとして検討されたのかもしれません。
しかし、最終的にGo言語ではfunc
、const
、type
が採用され、def
は言語仕様には含まれませんでした。このコミットは、その検討過程の一端を垣間見ることができる貴重な記録と言えます。
前提知識の解説
Go言語の初期開発と設計思想
Go言語は、GoogleのRobert Griesemer、Rob Pike、Ken Thompsonによって設計されました。彼らは、当時のソフトウェア開発における課題(コンパイル時間の長さ、依存関係の管理の複雑さ、並行処理の難しさなど)を解決するために、新しいプログラミング言語の必要性を感じていました。
Goの設計目標には以下のようなものがありました。
- 高速なコンパイル: 大規模なプロジェクトでも迅速にビルドできること。
- シンプルな構文: 読みやすく、書きやすいコードを促進すること。
- 強力な並行処理: ゴルーチンとチャネルによる組み込みの並行処理サポート。
- メモリ安全性と型安全性: 堅牢なソフトウェア開発を支援すること。
- 効率的な実行: C/C++に近いパフォーマンスを提供すること。
このコミットが行われた2009年2月は、Go言語がまだ一般に公開される前の、まさにこれらの設計目標が議論され、実装が試行錯誤されていた時期にあたります。
Go言語の宣言キーワード
現在のGo言語では、主要な宣言キーワードとして以下が使われます。
func
: 関数の定義var
: 変数の宣言const
: 定数の宣言type
: 型の定義(構造体、インターフェース、エイリアスなど)package
: パッケージの宣言import
: パッケージのインポート
これらのキーワードは、コードの可読性と明確性を高めるために慎重に選ばれました。
コード整形ツール (Pretty Printer)
プログラミング言語のコード整形ツール(Pretty Printer)は、ソースコードを読みやすく、一貫性のあるスタイルに自動的にフォーマットするソフトウェアです。Go言語にはgofmt
という公式の整形ツールがあり、Goコミュニティ全体でコードスタイルの一貫性を保つ上で重要な役割を果たしています。
このコミットで変更されているusr/gri/pretty/printer.go
は、gofmt
の原型、あるいはそれに類する初期のコード整形ロジックの一部であったと考えられます。コード整形ツールは、言語の構文要素(キーワード、識別子、演算子など)を認識し、それらを特定のルールに従って出力します。
技術的詳細
この変更は、Go言語のコード整形ロジックに条件分岐を追加することで、特定のキーワードの出力方法を切り替えるものです。
-
フラグの追加:
flag.Bool("def", false, "print 'def' instead of 'const', 'type', 'func' - experimental")
Goのflag
パッケージは、コマンドライン引数を解析してプログラムの動作を制御するための標準的な方法を提供します。ここで-def
というブーリアン型のフラグが追加され、デフォルト値はfalse
(無効)に設定されています。このフラグがtrue
に設定されると、実験的な動作が有効になります。 -
Declaration
関数の変更:Declaration
関数は、GoのAST(Abstract Syntax Tree:抽象構文木)における宣言ノード(関数、定数、型など)を処理し、対応するキーワードを出力する役割を担っています。変更前は、単純に
P.Token(d.Pos, d.Tok)
を呼び出して、宣言の種類に応じたトークン(例:Scanner.FUNC
、Scanner.CONST
、Scanner.TYPE
)をそのまま出力していました。変更後は、以下の条件分岐が追加されました。
if !*def || d.Tok == Scanner.IMPORT || d.Tok == Scanner.VAR { P.Token(d.Pos, d.Tok); } else { P.String(d.Pos, "def"); }
!*def
:-def
フラグが有効でない場合(つまり、false
の場合)。d.Tok == Scanner.IMPORT || d.Tok == Scanner.VAR
: 現在処理している宣言がimport
またはvar
である場合。
この条件式は、「
-def
フラグが有効でない場合」または「宣言がimport
かvar
である場合」に真となります。これらのケースでは、従来通りP.Token(d.Pos, d.Tok)
が実行され、元のキーワード(func
,const
,type
,import
,var
など)が出力されます。一方、上記の条件が偽となる場合、つまり「
-def
フラグが有効であり」かつ「宣言がimport
でもvar
でもない場合」にelse
ブロックが実行されます。このとき、P.String(d.Pos, "def")
が呼び出され、def
という文字列が強制的に出力されます。これにより、func
、const
、type
といったキーワードがdef
に置き換えられることになります。このロジックから、
import
とvar
はdef
に置き換えの対象外であったことがわかります。これは、import
はファイルの先頭に記述される特殊な宣言であり、var
は変数宣言として非常に一般的であるため、実験の対象から外されたか、あるいはdef
というキーワードが「定義」を意味する際に、関数、定数、型の「定義」に焦点を当てていたためと考えられます。
コアとなるコードの変更箇所
変更はusr/gri/pretty/printer.go
ファイルに集中しています。
--- a/usr/gri/pretty/printer.go
+++ b/usr/gri/pretty/printer.go
@@ -18,6 +18,7 @@ import (
var (
debug = flag.Bool("debug", false, "print debugging information");
+ def = flag.Bool("def", false, "print 'def' instead of 'const', 'type', 'func' - experimental");
// layout control
tabwidth = flag.Int("tabwidth", 8, "tab width");
@@ -803,7 +804,11 @@ func (P *Printer) Stat(s *AST.Stat) {
func (P *Printer) Declaration(d *AST.Decl, parenthesized bool) {
if !parenthesized {
-\t\tP.Token(d.Pos, d.Tok);
+\t\tif !*def || d.Tok == Scanner.IMPORT || d.Tok == Scanner.VAR {
+\t\t\tP.Token(d.Pos, d.Tok);
+\t\t} else {
+\t\t\tP.String(d.Pos, "def");
+\t\t}\
\t\tP.separator = blank;
\t}\
コアとなるコードの解説
-
var
ブロックへのdef
フラグの追加:var (
...)
ブロック内に、def = flag.Bool(...)
という行が追加されています。これにより、プログラム起動時に-def
コマンドライン引数を処理するための設定が行われます。 -
Declaration
関数の変更: この関数は、Goのソースコードから読み込まれた宣言(func
,const
,type
,var
,import
など)の抽象構文木ノードを受け取り、それを整形して出力する役割を担っています。 変更の核心は、P.Token(d.Pos, d.Tok)
の呼び出しを条件分岐でラップした点です。!*def
:def
フラグがfalse
の場合。つまり、実験的な機能が有効になっていない場合。d.Tok == Scanner.IMPORT || d.Tok == Scanner.VAR
: 宣言のトークンがimport
またはvar
の場合。 これらの条件のいずれかが真であれば、元のキーワード(d.Tok
)がそのまま出力されます。 そうでなければ(つまり、def
フラグがtrue
で、かつ宣言がimport
でもvar
でもない場合)、P.String(d.Pos, "def")
が実行され、def
という文字列が強制的に出力されます。これは、func
、const
、type
といった宣言が対象となることを意味します。
この変更は、Go言語の初期の設計段階において、キーワードの選択肢を試行錯誤していた様子を明確に示しています。
関連リンク
- Go言語の公式ウェブサイト: https://go.dev/
- Go言語の歴史: https://go.dev/doc/history
- Go言語の
flag
パッケージ: https://pkg.go.dev/flag
参考にした情報源リンク
- Go言語の
def
キーワードに関するWeb検索結果 (Go言語にはdef
キーワードは存在せず、func
が使用されること、defer
とは異なること、実験的なdef
構文の提案は現在ないことなどを確認するために利用)