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

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

このコミットは、Go言語の初期開発段階における実験的な変更を記録しています。具体的には、Goのコードを整形(pretty print)する際に、funcconsttypeといったキーワードの代わりに、実験的に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で開発が始まり、その初期段階では言語仕様やキーワードの選定が活発に行われていました。このコミットは、その過程でfuncconsttypeといった宣言キーワードの代替案としてdefというキーワードが検討されていた可能性を示唆しています。

当時のGo言語の設計目標の一つに、既存の言語(C++、Javaなど)の複雑さを避け、シンプルで読みやすい構文を目指すというものがありました。defというキーワードは、Pythonなどの他の言語で関数定義に使われることがあり、より汎用的な「定義」を意味するキーワードとして検討されたのかもしれません。

しかし、最終的にGo言語ではfuncconsttypeが採用され、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言語のコード整形ロジックに条件分岐を追加することで、特定のキーワードの出力方法を切り替えるものです。

  1. フラグの追加: flag.Bool("def", false, "print 'def' instead of 'const', 'type', 'func' - experimental") Goのflagパッケージは、コマンドライン引数を解析してプログラムの動作を制御するための標準的な方法を提供します。ここで-defというブーリアン型のフラグが追加され、デフォルト値はfalse(無効)に設定されています。このフラグがtrueに設定されると、実験的な動作が有効になります。

  2. Declaration関数の変更: Declaration関数は、GoのAST(Abstract Syntax Tree:抽象構文木)における宣言ノード(関数、定数、型など)を処理し、対応するキーワードを出力する役割を担っています。

    変更前は、単純にP.Token(d.Pos, d.Tok)を呼び出して、宣言の種類に応じたトークン(例: Scanner.FUNCScanner.CONSTScanner.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フラグが有効でない場合」または「宣言がimportvarである場合」に真となります。これらのケースでは、従来通りP.Token(d.Pos, d.Tok)が実行され、元のキーワード(func, const, type, import, varなど)が出力されます。

    一方、上記の条件が偽となる場合、つまり「-defフラグが有効であり」かつ「宣言がimportでもvarでもない場合」にelseブロックが実行されます。このとき、P.String(d.Pos, "def")が呼び出され、defという文字列が強制的に出力されます。これにより、funcconsttypeといったキーワードがdefに置き換えられることになります。

    このロジックから、importvardefに置き換えの対象外であったことがわかります。これは、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という文字列が強制的に出力されます。これは、funcconsttypeといった宣言が対象となることを意味します。

この変更は、Go言語の初期の設計段階において、キーワードの選択肢を試行錯誤していた様子を明確に示しています。

関連リンク

参考にした情報源リンク