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

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

このコミットは、Go言語の仕様書 doc/go_spec.html に対する変更であり、複合リテラル(composite literals)に関する記述の明確化と、特定の構文解析の曖昧さの解決を目的としています。具体的には、複合リテラルの型制約、式の型互換性、そしてifforswitch文の条件部における複合リテラルの構文解析の曖昧さに対する解決策が追記されています。

コミット

commit 7a5e97ba915bddfcaf018280364b1690d4c88846
Author: Russ Cox <rsc@golang.org>
Date:   Tue Mar 3 15:40:30 2009 -0800

    The final piece of the alternative to my parens proposal
    (i.e., the status quo with braces in composite literals).
    
    DELTA=20  (16 added, 0 deleted, 4 changed)
    OCL=25640
    CL=25646

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

https://github.com/golang/go/commit/7a5e97ba915bddfcaf018280364b1690d4c88846

元コミット内容

The final piece of the alternative to my parens proposal
(i.e., the status quo with braces in composite literals).

DELTA=20  (16 added, 0 deleted, 4 changed)
OCL=25640
CL=25646

変更の背景

このコミットは、Go言語の初期設計段階における複合リテラルの構文に関する議論の最終的な結論の一部です。コミットメッセージにある「parens proposal(括弧提案)」とは、複合リテラルを()で囲むべきか、それとも現在のGo言語のように{}で囲むべきかという初期の言語設計上の選択肢を指しています。最終的に、Go言語は複合リテラルにブレース({})を使用する現在の形式を採用しました。

しかし、ブレースを使用するこの設計には、特定の文脈、特にifforswitch文の条件部で複合リテラルを使用した場合に、構文解析上の曖昧さ(parsing ambiguity)が生じる可能性がありました。これは、複合リテラルのブレースが、ステートメントブロックを導入するブレースと衝突するためです。このコミットは、その曖昧さを解消するための仕様上のルールを明確にし、必要に応じて複合リテラルを括弧で囲むことを義務付けることで、この設計上の選択を完成させるものです。

また、複合リテラルの要素の型チェックに関する記述も修正されており、より正確な「assignment compatible(代入互換性)」という用語が導入されています。これは、単なる「一致(match)」ではなく、より柔軟な型システムを反映しています。

前提知識の解説

複合リテラル (Composite Literals)

Go言語における複合リテラルは、構造体(struct)、配列(array)、スライス(slice)、マップ(map)などの複合型をその場で初期化するための構文です。例えば、Point{X: 1, Y: 2}は構造体の複合リテラル、[]int{1, 2, 3}はスライスの複合リテラルです。これらは、変数を宣言し、値を代入する手間を省き、簡潔に値を表現するために使用されます。

構文解析の曖昧さ (Parsing Ambiguity)

プログラミング言語のコンパイラやインタプリタは、ソースコードを解析してその構造を理解します。このプロセスを構文解析(parsing)と呼びます。構文解析の曖昧さとは、あるコードスニペットが複数の異なる有効な構文ツリーとして解釈されうる状況を指します。これは言語設計上の問題であり、コンパイラがコードの意図を正確に判断できないため、エラーや予期せぬ動作につながる可能性があります。

Go言語の複合リテラルはブレース{}を使用しますが、ifforswitchなどの制御構造もまた、その本体(ブロック)をブレース{}で囲みます。このため、例えばif T{a,b,c} { ... }のようなコードがあった場合、コンパイラはT{a,b,c}を複合リテラルとして解釈すべきか、それともTを型名として、その後に続く{a,b,c}if文のブロックとして解釈すべきか、という曖昧さが生じます。

代入互換性 (Assignment Compatibility)

Go言語の型システムにおける重要な概念の一つです。ある値が別の型に「代入互換」であるとは、その値が追加の型変換なしにその型に代入できることを意味します。これは、厳密な型の一致(exact match)よりも広い概念です。例えば、基底型が同じであれば、異なる型名を持つ型間でも代入互換性がある場合があります。このコミットでは、複合リテラルの要素の型が、対応するフィールドや要素の型と「代入互換」である必要があることを明確にしています。

技術的詳細

このコミットは、Go言語の仕様書 doc/go_spec.html の以下の2つの主要な側面を修正・明確化しています。

  1. 複合リテラルの型制約と式の型互換性:

    • 以前の記述では、「LiteralTypeはstruct, array, slice, or map typeでなければならない」とあり、その後に「TODO: then why doesn't the grammar say that?(なぜ文法がそれを言わないのか?)」というコメントがありました。
    • このコミットでは、このTODOコメントが削除され、代わりに「(The grammar enforces this constraint except when the type is given as a TypeName.)」という補足が追加されました。これは、文法自体がこの制約を強制するが、型がTypeNameとして与えられた場合には例外があることを示唆しています。
    • さらに、「The types of the expressions must match the respective field, element, and key types of the LiteralType; there is no automatic type conversion.」という記述が、「The types of the expressions must be assignment compatible to the respective field, element, and key types of the LiteralType; there is no additional conversion.」に変更されました。これにより、複合リテラルの要素の型が、対応するフィールドや要素の型と厳密に一致する必要はなく、「代入互換」であればよいことが明確にされました。これは、Goの型システムの柔軟性を反映した重要な変更です。
  2. 複合リテラルにおける構文解析の曖昧さの解決:

    • 新たに以下のパラグラフが追加されました。

      A parsing ambiguity arises when a composite literal using the TypeName form of the LiteralType appears in the condition of an "if", "for", or "switch" statement, because the braces surrounding the expressions in the literal are confused with those introducing a block of statements. To resolve the ambiguity in this rare case, the composite literal must appear within parentheses.

    • これは、ifforswitch文の条件部で、TypeName形式の複合リテラル(例: T{a,b,c})が使用された場合に構文解析の曖昧さが発生することを説明しています。複合リテラルのブレースが、ステートメントブロックのブレースと混同されるためです。
    • この曖昧さを解決するために、このような稀なケースでは、複合リテラルを括弧で囲む必要があることが明記されました。
    • 例として、以下のコードスニペットが示されています。
      if x == (T{a,b,c}[i]) { ... }
      if (x == T{a,b,c}[i]) { ... }
      
      これらの例は、複合リテラル全体、または複合リテラルを含む式全体を括弧で囲むことで、構文解析の曖昧さを解消できることを示しています。

この変更は、Go言語の構文解析器がコードを正しく解釈できるようにするための重要な仕様上の調整であり、言語の堅牢性と明確性を高めるものです。

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

変更は doc/go_spec.html ファイルに対して行われています。

--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1875,10 +1875,11 @@ ExprPair      = Expression ":" Expression .
 
 <p>
 The LiteralType must be a struct, array, slice, or map type.
-<font color=red>TODO: then why doesn't the grammar say that?</font>
-The types of the expressions must match the respective field, element, and
-key types of the LiteralType; there is no automatic type conversion.
-Given
+(The grammar enforces this constraint except when the type is given
+as a TypeName.)
+The types of the expressions must be assignment compatible to
+the respective field, element, and key types of the LiteralType;
+there is no additional conversion.
 </p>
 
 <pre>
@@ -1936,6 +1937,21 @@ key-value pairs separated by a colon:
 m := map[string]int{"good": 0, "bad": 1, "indifferent": 7};
 </pre>
 
+<p>
+A parsing ambiguity arises when a composite literal using the
+TypeName form of the LiteralType appears in the condition of an
+"if", "for", or "switch" statement, because the braces surrounding
+the expressions in the literal are confused with those introducing
+a block of statements. To resolve the ambiguity in this rare case,
+the composite literal must appear within
+parentheses.
+</p>
+
+<pre>
+if x == (T{a,b,c}[i]) { ... }
+if (x == T{a,b,c}[i]) { ... }
+</pre>
+
 <h3>Function literals</h3>
 
 <p>

コアとなるコードの解説

このコミットは、Go言語の仕様書の一部であるHTMLドキュメントを更新しています。

  1. 複合リテラルの型制約の明確化:

    • - <font color=red>TODO: then why doesn't the grammar say that?</font> の行が削除されました。これは、Go言語の文法が複合リテラルの型制約(struct, array, slice, map型であること)を強制しているにもかかわらず、その点が仕様書で不明瞭であったためのTODOコメントでした。
    • + (The grammar enforces this constraint except when the type is given as a TypeName.) が追加されました。これは、文法がこの制約を強制するが、型がTypeNameとして与えられた場合には例外があることを補足しています。これにより、文法と仕様の整合性が高まりました。
    • - The types of the expressions must match the respective field, element, and- The types of the expressions must be assignment compatible to に変更されました。これは、複合リテラルの要素の型が、対応するフィールドや要素の型と「厳密に一致」するのではなく、「代入互換」であればよいという、より正確な表現に修正されたものです。これにより、Goの型システムの柔軟性が仕様書に反映されました。
  2. 構文解析の曖昧さの解決策の追加:

    • 新たに<p>タグで始まる段落が追加され、ifforswitch文の条件部で複合リテラルが使用された場合に発生する構文解析の曖昧さについて説明しています。この曖昧さは、複合リテラルのブレースがステートメントブロックのブレースと混同されるために生じます。
    • この曖昧さを解消するために、複合リテラルを括弧で囲む必要があることが明記されました。
    • その後に続く<pre>タグ内のコード例は、実際にどのように括弧を使用して曖昧さを解消するかを示しています。if x == (T{a,b,c}[i]) { ... }if (x == T{a,b,c}[i]) { ... } のように、複合リテラルを含む式全体を括弧で囲むことで、コンパイラが正しく複合リテラルを認識できるようになります。

これらの変更は、Go言語の仕様をより正確で、曖昧さのないものにするための重要なステップであり、コンパイラの実装者や言語のユーザーにとって、複合リテラルの挙動をより明確に理解するための指針となります。

関連リンク

参考にした情報源リンク

  • Go言語の初期の設計に関する議論("parens proposal"など)は、Go言語のメーリングリストや初期の設計ドキュメントに散見されますが、特定の単一のリンクを特定することは困難です。Go言語の進化の歴史を追うことで、これらの議論の背景を理解できます。
  • Go言語のGitHubリポジトリ: https://github.com/golang/go
  • Go言語の複合リテラルに関する公式ドキュメント: https://go.dev/ref/spec#Composite_literals
  • Go言語の代入可能性に関する公式ドキュメント: https://go.dev/ref/spec#Assignability