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

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

このコミットは、Go言語の初期開発段階における重要な変更を記録しています。主に、言語仕様書(doc/go_lang.txt)の更新、if文とswitch文の構文規則の厳密化、およびそれに関連するテストケースの修正と追加が含まれています。また、関数の戻り値の命名規則に関するテストの修正も行われています。

コミット

commit e92b7538102ed9ea1402fb8ce4d948da27ffd456
Author: Robert Griesemer <gri@golang.org>
Date:   Fri Jun 6 15:53:14 2008 -0700

    - fixed a few tests and added 3 incorrectly succeeding tests
    - updated go_lang.txt to be more uniform and match the implementation
    - made makehtml work on Mac
    - fixed a couple of bugs in go.atg
    
    SVN=121520

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

https://github.com/golang/go/commit/e92b7538102ed9ea1402fb8ce4d948da27ffd456

元コミット内容

  • いくつかのテストを修正し、誤って成功していた3つのテストを追加しました。
  • go_lang.txt をより統一的で実装に合致するように更新しました。
  • makehtml がMacで動作するようにしました。
  • go.atg のいくつかのバグを修正しました。

変更の背景

このコミットは、Go言語がまだ活発に設計・開発されていた2008年6月に行われました。当時のGo言語は、その構文やセマンティクスが固まりつつある段階であり、言語仕様書(go_lang.txt)と実際のコンパイラ実装との間に乖離が生じることがありました。

このコミットの主な背景は以下の点にあります。

  1. 言語仕様の明確化と厳密化: if文やswitch文のような基本的な制御フロー構造について、その構文規則をより明確にし、曖昧さを排除する必要がありました。特に、条件式が省略された場合の挙動や、初期化ステートメントと条件式の関係性が焦点となりました。
  2. 実装との整合性の確保: 仕様書に記述された内容と、コンパイラが実際に受け入れるコードとの間に一貫性を持たせる必要がありました。これにより、開発者が仕様書を信頼し、予測可能なコードを書けるようになります。
  3. テストカバレッジの向上: 既存のテストが言語の意図しない挙動を許容してしまっている("incorrectly succeeding tests")状況を是正し、より堅牢なテストスイートを構築することが目的でした。これにより、将来的な変更が意図しない副作用を引き起こさないようにします。
  4. 開発環境の改善: makehtmlツールのMac対応やgo.atgのバグ修正は、開発者の生産性向上と開発プロセスの円滑化に寄与します。

Go言語の設計哲学の一つに「シンプルさと明瞭さ」があります。このコミットは、その哲学に基づき、言語の基本的な構文要素をよりシンプルで明確なものにするための初期の取り組みの一環と言えます。

前提知識の解説

このコミットの変更内容を理解するためには、以下のGo言語の基本的な概念と、当時のGo言語開発の状況に関する知識が役立ちます。

  1. Go言語の制御フロー:
    • if: Go言語のif文は、条件式の括弧が不要であること、そして初期化ステートメントをオプションで含めることができる点が特徴です。初期化ステートメントで宣言された変数のスコープはif文のブロック内に限定されます。
    • switch: Go言語のswitch文は、C言語系の言語とは異なり、caseの後にbreakを明示的に書く必要がありません(自動的にbreakされる)。また、式を省略したswitch文(switch { ... })は、switch true { ... } と同等に扱われ、複数のcaseがブール式として評価されます。
  2. Go言語の関数と戻り値:
    • Go言語の関数は複数の戻り値を返すことができます。
    • 戻り値には名前を付けることができ、名前付き戻り値は関数の先頭でゼロ値で初期化され、returnステートメントで明示的に値を指定せずに戻すことができます(naked return)。
    • このコミットの時点では、戻り値に名前を付ける際の規則(特にパラメータ名との重複)がまだ厳密に定義されていなかった可能性があります。
  3. Go言語の初期開発:
    • Go言語は2007年末に設計が始まり、2009年にオープンソースとして公開されました。このコミットは2008年に行われており、まさに言語のコア部分が形成されていた時期にあたります。
    • 当時のGo言語は、現在の安定版とは異なる構文やセマンティクスを持つ部分がありました。言語仕様書(go_lang.txt)は、その時点での言語の「ドラフト」仕様として機能していました。
    • SVN=121520という記述は、当時のバージョン管理システムがSubversionであったことを示しています。Go言語は後にGitに移行しました。
  4. テスト駆動開発の初期段階:
    • "incorrectly succeeding tests"という表現は、テストが本来検出するべきバグを見逃していた、あるいは言語の変更によってテストの期待値が変わったことを示唆しています。これは、言語の進化に伴いテストスイートも継続的に更新される必要があることを意味します。

これらの背景知識を持つことで、このコミットがGo言語の安定性と堅牢性を高めるための初期の重要なステップであったことが理解できます。

技術的詳細

このコミットにおける技術的な変更は、主にGo言語の構文解析とセマンティクス、特に制御フロー文と関数の定義に関するものです。

  1. if文の構文変更と厳密化:
    • doc/go_lang.txtIfStatの定義がIfStat = "if" [ SimpleStat ";" ] Expression Block [ "else" Statement ] .からIfStat = "if" [ [ SimpleStat ";" ] Expression ] Block [ "else" Statement ] .に変更されました。
    • これは、if文の条件式が省略可能であることを明示しています。省略された場合、条件はtrueとみなされます。
    • しかし、同時に「if文に初期化ステートメント(SimpleStat)がある場合、条件式は省略できない」という制約が追加されました。これは、if one := 1; { ... }のようなコードが不正となることを意味します。このような場合、if one := 1; true { ... }のように明示的にtrueを書く必要があります。
    • test/if.goif one := 1; {if one := 1; true {に修正されたのはこのためです。
    • test/if1.goが新規追加され、if one := 1; {という不正な構文がコンパイルエラーとなることをテストしています。
  2. switch文の構文変更と厳密化:
    • switch文についても同様に、初期化ステートメントがある場合に条件式(true)を明示的に書く必要があるという規則が適用されました。
    • test/switch.goswitch x := 5; {switch x := 5; true {に修正されました。
    • test/switch1.goが新規追加され、switch x := 5; {という不正な構文がコンパイルエラーとなることをテストしています。
  3. 関数の戻り値の命名規則:
    • test/func.goでは、f7f8関数の戻り値の型に名前が付けられました(例: (int, float)から(x int, y float)へ)。これは、名前付き戻り値の導入またはその使用法の明確化に関連している可能性があります。
    • test/func1.goが新規追加され、以下の不正な関数宣言をテストしています。
      • func f1(a int) (int, float): 複数の戻り値がある場合、名前を付ける必要があるという規則(当時のGoの仕様)に違反していることをテスト。
      • func f2(a int) (a int, b float): 戻り値の名前がパラメータ名と重複していることをテスト。これは、名前の衝突を避けるための規則が導入されたことを示唆しています。
  4. test/golden.outの更新:
    • このファイルは、テストの期待される出力や、既知のバグ("BUG: known to fail incorrectly" や "BUG: known to succeed incorrectly")を記録する役割を果たしています。
    • func1.go, if1.go, switch1.goが「誤って成功していたバグ」として追加されたことは、これらのテストが以前はコンパイルエラーにならなかったが、今回の変更によって正しくコンパイルエラーになるようになったことを示しています。これは、コンパイラが言語仕様に厳密に準拠するようになった証拠です。
  5. makehtmlgo.atgの修正:
    • makehtmlはGo言語のドキュメントを生成するためのツールである可能性が高いです。Macでの動作修正は、クロスプラットフォーム対応の一環です。
    • go.atgは、Go言語の文法定義ファイル(おそらくANTLRなどのパーサジェネレータで使用される形式)であると推測されます。ここでのバグ修正は、言語の構文解析器の正確性を向上させるためのものです。

これらの変更は、Go言語の初期段階において、言語の構文とセマンティクスをより厳密に定義し、コンパイラの実装をそれに合わせて調整するプロセスが活発に行われていたことを示しています。特に、ifswitchのような基本的な制御フローの挙動を明確にすることは、言語の安定性と学習しやすさにとって非常に重要です。

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

このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。

  1. doc/go_lang.txt:

    • IfStatの構文定義が変更され、条件式の省略に関する記述が追加されました。
    • 初期化ステートメントがある場合の条件式の必須化に関する制約が追記されました。
    • 日付がMay 14, 2008からJune 6, 2008に更新されています。
    --- a/doc/go_lang.txt
    +++ b/doc/go_lang.txt
    @@ -4,7 +4,7 @@ The Go Programming Language (DRAFT)
     Robert Griesemer, Rob Pike, Ken Thompson
     
     ----
    -(May 14, 2008)
    +(June 6, 2008)
     
     This document is a semi-informal specification/proposal for a new
     systems programming language.  The document is under active
    @@ -1563,17 +1563,19 @@ If statements
     
     If statements have the traditional form except that the
     condition need not be parenthesized and the "then" statement
    -must be in brace brackets.
    +must be in brace brackets. The condition may be omitted in which
    +case it is assumed to have the value "true".
     
    -  IfStat = "if" [ SimpleStat ";" ] Expression Block [ "else" Statement ] .
    +  IfStat = "if" [ [ SimpleStat ";" ] Expression ] Block [ "else" Statement ] .
     
       if x > 0 {
         return true;
       }
    -  
    -An if statement may include the declaration of a single temporary variable.
    +
    +An "if" statement may include the declaration of a single temporary variable.
     The scope of the declared variable extends to the end of the if statement, and
    -the variable is initialized once before the statement is entered. 
    +the variable is initialized once before the statement is entered. If a variable
    +is declared, the condition cannot be omitted.
     
       if x := f(); x < y {
         return x;
    
  2. test/func.go:

    • f7f8関数の戻り値に名前が追加されました。
    --- a/test/func.go
    +++ b/test/func.go
    @@ -36,12 +36,12 @@ func f6(a int) (r int) {
     	return 6;
     }
     
    -func f7(a int) (int, float) {
    +func f7(a int) (x int, y float) {
     	return 7, 7.0;
     }
     
     
    -func f8(a int) (a int, b float) {
    +func f8(a int) (x int, y float) {
     	return 8, 8.0;
     }
    
  3. test/func1.go (新規追加):

    • 複数の戻り値に名前がない場合と、戻り値の名前がパラメータ名と重複している場合のコンパイルエラーをテストします。
    // errchk $G $F.go
    
    // Copyright 2009 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package main
    
    func f1(a int) (int, float) {  // BUG multiple return values must have names
    	return 7, 7.0;
    }
    
    
    func f2(a int) (a int, b float) {  // BUG return value names must be different from parameter names
    	return 8, 8.0;
    }
    
  4. test/if.go:

    • if文の初期化ステートメントがある場合に、条件式を明示的にtrueとするように修正されました。
    --- a/test/if.go
    +++ b/test/if.go
    @@ -50,7 +50,7 @@ func main() {
     	assertequal(count, 1, "if empty");
     
     	count = 0;
    -	if one := 1; {
    +	if one := 1; true {
     		count = count + one;	
     	}
     	assertequal(count, 1, "if empty one");
    
  5. test/if1.go (新規追加):

    • 初期化ステートメントがあるif文で条件式が省略されている場合のコンパイルエラーをテストします。
    // $G $F.go && $L $F.$A && ./$A.out
    
    // Copyright 2009 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package main
    
    func main() {
    	count := 0;
    	if one := 1; {  // BUG if there is a simple stat, the condition must be present
    		count = count + one;	
    	}
    }
    
  6. test/switch.go:

    • switch文の初期化ステートメントがある場合に、条件式を明示的にtrueとするように修正されました。
    --- a/test/switch.go
    +++ b/test/switch.go
    @@ -35,7 +35,7 @@ func main() {
     	case i5 > x: assert(false, ">");
     	}\
     
    -	switch x := 5; {  // BUG?: true should not be necessary but now made mandatory in go_lang.txt
    +	switch x := 5; true {
     	case i5 < x: assert(false, "<");
     	case i5 == x: assert(true, "!");
     	case i5 > x: assert(false, ">");
    
  7. test/switch1.go (新規追加):

    • 初期化ステートメントがあるswitch文で条件式が省略されている場合のコンパイルエラーをテストします。
    // $G $F.go && $L $F.$A && ./$A.out
    
    // Copyright 2009 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package main
    
    func main() {
      i := 0;
    	switch x := 5; {  // BUG if there is a simple stat, the condition must be present
    	case i < x:
    	case i == x:
    	case i > x:
    	}
    }
    
  8. test/golden.out:

    • 新規追加されたfunc1.go, if1.go, switch1.goが「誤って成功していたバグ」としてリストに追加されました。
    --- a/test/golden.out
    +++ b/test/golden.out
    @@ -23,6 +23,9 @@ main_f4: doasm: notfound from=75 to=10 (24)    IDIVL   $2,AX
     main_f4: doasm: notfound from=75 to=10 (24)    IDIVL   $2,AX
     BUG: known to fail incorrectly
     
    +=========== ./func1.go
    +BUG: known to succeed incorrectly
    +
     =========== ./hashmap.go
     hashmap.go:46: fatal error: optoas: no entry LSH-<uint32>UINT32
     BUG: known to fail incorrectly
    @@ -32,6 +35,9 @@ hello, world
     
     =========== ./if.go
     
    +=========== ./if1.go
    +BUG: known to succeed incorrectly
    +
     =========== ./int_lit.go
     int_lit.go:5: syntax error
     BUG: known to fail incorrectly
    @@ -52,6 +58,9 @@ BUG: known to fail incorrectly
     
     =========== ./switch.go
     
    +=========== ./switch1.go
    +BUG: known to succeed incorrectly
    +
     =========== ./test0.go
     test0.go:23: addtyp: renaming Point/<Point>{<x><int32>INT32;<y><int32>INT32;} to Point2/<Point2>FORW
     test0.go:48: illegal types for operand
    

コアとなるコードの解説

このコミットの核心は、Go言語の初期の言語仕様とコンパイラ実装の間の整合性を高めることにあります。

  1. if文とswitch文の条件式に関する厳密化:

    • Go言語のif文とswitch文は、初期化ステートメント(例: x := 5;)を伴うことができます。このコミット以前は、初期化ステートメントが存在する場合でも、条件式を省略してif x := 1; { ... }のように書くことが許容されていた可能性があります。
    • しかし、このコミットにより、言語仕様(go_lang.txt)が更新され、初期化ステートメントが存在する場合は、条件式を明示的に記述することが必須となりました。条件が常に真である場合は、trueと明示的に書く必要があります(例: if one := 1; true { ... })。
    • この変更の意図は、コードの意図をより明確にし、曖昧さを排除することにあります。条件式が省略された場合にそれがtrueを意味するのか、それとも単なる構文エラーなのかを明確に区別できるようにするためです。
    • これに伴い、既存のテストファイル(test/if.go, test/switch.go)が修正され、新しい規則に準拠するようにtrueが追加されました。また、新しい規則に違反するコードが正しくコンパイルエラーとなることを確認するためのテストファイル(test/if1.go, test/switch1.go)が追加されました。これらのテストは、以前は「誤って成功していた」状態から、今回の変更によって「正しく失敗する」状態になったことをtest/golden.outで記録しています。
  2. 関数の戻り値の命名規則の明確化:

    • test/func.goにおける関数の戻り値の命名は、Go言語における名前付き戻り値の概念が導入されつつあった、あるいはその使用法が明確化されつつあったことを示唆しています。名前付き戻り値は、コードの可読性を向上させ、特に複数の戻り値がある場合にどの値が何を意味するのかを明確にするのに役立ちます。
    • test/func1.goの追加は、戻り値の命名に関する特定の規則(例: 複数の戻り値には名前が必要、パラメータ名と戻り値の名前の重複は不可)が導入されたことを示しています。これは、言語の設計者が、コードの明確性とエラーの早期検出を重視していたことを反映しています。

これらの変更は、Go言語がその初期段階で、堅牢で一貫性のある言語仕様を確立するために、細部にわたる調整と厳密化が行われていたことを明確に示しています。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Go言語のGitHubリポジトリのコミット履歴
  • Go言語の初期のメーリングリストや設計に関する議論(公開されている場合)
  • Go言語のif文とswitch文に関する一般的な解説記事
  • Go言語の名前付き戻り値に関する解説記事