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

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

このコミットは、Go言語の初期の仕様書である doc/go_spec.html ファイルに対する変更です。このファイルは、Go言語の文法、型システム、ランタイムの振る舞いなどを定義する公式ドキュメントとして機能していました。このコミットの目的は、特に「完全型 (complete types)」の概念に関する記述を明確化し、仕様の曖昧さを解消することにありました。

コミット

  • コミットハッシュ: cdbf619750850936c88e79238050c8fd8f2bdf6f
  • 作者: Rob Pike r@golang.org
  • 日付: 2009年2月24日火曜日 17:47:45 -0800

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

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

元コミット内容

complete types

R=gri
DELTA=29  (0 added, 12 deleted, 17 changed)
OCL=25388
CL=25391

変更の背景

このコミットは、Go言語がまだ開発の初期段階にあった2009年に行われました。当時のGo言語の仕様書はまだ流動的であり、言語の設計思想や振る舞いを正確に記述するための試行錯誤が続けられていました。

「完全型 (complete type)」と「不完全型 (incomplete type)」の概念は、コンパイラがメモリを割り当てたり、型のサイズを計算したりするために非常に重要です。特に、構造体(struct)や配列(array)のような複合型の場合、そのサイズは内部の要素の型が完全に定義されているかどうかに依存します。

このコミット以前の仕様書には、この「完全型」に関する記述に曖昧さや未解決の「TODO」コメントが散見されました。例えば、ポインタ型が指す先の型が不完全であってもポインタ型自体は完全であること、構造体が前方宣言された場合に不完全型となること、変数宣言における型の完全性の要件などが、より明確に定義される必要がありました。

この変更の背景には、Go言語の型システムをより厳密に定義し、コンパイラの実装者が混乱なく言語仕様を解釈できるようにするという意図がありました。また、仕様書内の「TODO」コメントを解消し、ドキュメントの完成度を高める目的もありました。

前提知識の解説

Go言語の初期開発

Go言語は、Googleによって2007年に設計が開始され、2009年にオープンソースとして公開されました。このコミットは、Go言語が一般に公開される直前、あるいは公開されたばかりの非常に初期の段階で行われたものであり、言語仕様がまだ活発に議論され、洗練されていた時期のものです。当時のGoは、現在のGoとは異なる部分も多く、仕様書も頻繁に更新されていました。

型システム

プログラミング言語における型システムは、プログラム内で使用されるデータの種類を定義し、それらのデータに対してどのような操作が許されるかを規定するものです。型システムは、プログラムの安全性(例えば、整数と文字列を誤って加算するようなエラーを防ぐ)を高め、コードの可読性を向上させ、コンパイラが効率的なコードを生成するのを助けます。

完全型 (Complete Type) と不完全型 (Incomplete Type)

「完全型」と「不完全型」の概念は、主にC言語のような低レベル言語でよく見られますが、Go言語の初期の仕様にも同様の概念が存在しました。

  • 完全型 (Complete Type): コンパイル時にその型のサイズ(メモリ上で占めるバイト数)が完全に決定できる型を指します。例えば、intfloat64bool などのプリミティブ型は常に完全型です。また、要素の型とサイズが確定している配列や、すべてのフィールドの型が確定している構造体も完全型です。コンパイラは完全型に対してメモリを割り当てたり、ポインタ演算を行ったりすることができます。
  • 不完全型 (Incomplete Type): コンパイル時にその型のサイズがまだ決定できない型を指します。典型的な例としては、前方宣言された構造体や、まだフィールドが完全に定義されていない構造体があります。不完全型は、その型のサイズが不明なため、直接変数を宣言したり、その型の値を操作したりすることはできません。しかし、その型へのポインタを宣言することは可能です。なぜなら、ポインタ自体のサイズは、それが指す先の型が何であれ、常に一定だからです。

この概念は、特に再帰的なデータ構造(例:リンクリストのノードが自分自身へのポインタを持つ場合)や、相互参照するデータ構造を定義する際に重要になります。

前方宣言 (Forward Declaration)

前方宣言とは、プログラム中で型や関数が実際に定義される前に、その存在を宣言することです。これにより、相互に依存する型や関数を定義する際に、コンパイラがそれらの存在を認識できるようになります。例えば、構造体Aが構造体Bへのポインタを持ち、構造体Bが構造体Aへのポインタを持つような場合、どちらかの構造体を先に前方宣言しておく必要があります。Go言語では、C言語のような明示的な前方宣言の構文は通常必要ありませんが、型定義の順序によって「不完全型」として扱われる場合があります。

技術的詳細

このコミットは、doc/go_spec.html 内の「完全型」に関する記述をより正確かつ簡潔にするための複数の変更を含んでいます。

  1. 「完全型」と「不完全型」の定義の明確化:

    • 変更前は、「ほとんどの型は常に完全だが、ポインタの基底型のようにその構成要素が不完全な場合がある」といった記述でした。また、「構造体とインターフェース型は前方宣言された場合に不完全となる」とされていました。
    • 変更後は、「不完全型とは、そのサイズがまだ不明な型であり、例えばフィールドがまだ完全に定義されていない構造体や前方宣言された型などである」と明確に定義されました。さらに、「ほとんどの型は常に完全であり、例えばポインタ型は、それが不完全な型を指していても常に完全である。なぜなら、ポインタ自体のサイズは常に既知だからである」と、ポインタ型が常に完全型である理由が明確に説明されました。これは、コンパイラがメモリを割り当てる際に、ポインタ変数のサイズさえ分かれば十分であるという事実に基づいています。
  2. 文字列リテラルの連結の記述の簡素化:

    • 変更前は、「空文字列、空白、またはコメントのみで区切られた文字列リテラルは、単一の文字列リテラルに連結される」という、やや冗長な記述でした。
    • 変更後は、「文字列リテラルのシーケンスは単一の文字列に連結される」と簡潔に表現されました。これは、Goのコンパイラが隣接する文字列リテラルを自動的に連結するという振る舞いをより一般的に記述したものです。
  3. 文法定義の整形:

    • StringLitArrayType の文法定義において、= の前後の空白が調整され、より一貫性のあるフォーマットになりました。これは、ドキュメントの可読性と統一性を向上させるための軽微な変更です。
  4. 構造体タグの記述の修正:

    • 構造体の例におけるコメントで、「タグ文字列はプロトコルバッファのフィールド番号を含む (contain)」という記述が、「タグ文字列はプロトコルバッファのフィールド番号を定義する (define)」に変更されました。これは、タグが単に情報を持つだけでなく、その情報を「定義する」という、より能動的な役割を強調するものです。
  5. ポインタの基底型に関する記述の簡素化:

    • 変更前は、「再帰的および相互再帰的な型を構築するために、ポインタの基底型は前方宣言された不完全な型(§Forward declarations)の型名で示されることがある」という、やや複雑な記述でした。
    • 変更後は、「ポインタの基底型は不完全型(§Types)であってもよい」と簡潔に表現されました。これは、ポインタが不完全型を指すことができるという本質的な点をより直接的に述べています。
  6. インターフェースの埋め込みに関する記述の明確化:

    • インターフェースが別のインターフェース型を埋め込む際の要件として、「Tは別の完全な(かつ前方宣言されていない)インターフェース型を示さなければならない」という記述がありました。
    • 変更後は、「Tは別の完全なインターフェース型を示さなければならない」と修正され、「前方宣言されていない」という条件が削除されました。これは、インターフェースの埋め込みに関する制約をより正確に反映したものです。
  7. チャネル型と変数宣言における「TODO」コメントの削除:

    • チャネル型が完全型でなければならないという記述の横にあった「(TODO could it be incomplete?)」というコメントが削除されました。これは、チャネル型が常に完全型であるべきという設計上の決定が固まったことを示唆しています。
    • 変数宣言における型の完全性に関する記述の横にあった「TODO in another round of editing: complete/incomplete types」というコメントも削除されました。これは、「完全型」に関する議論がこのコミットによって解決され、独立したセクションを設ける必要がなくなったことを意味します。
  8. Sizeof 関数の引数型の明確化:

    • Sizeof 関数が「任意の型の変数」を受け取るとされていた記述が、「任意の**(完全な)**型の変数」を受け取ると修正されました。これは、Sizeof が型のサイズを計算するためには、その型が完全型である必要があるという暗黙の前提を明示化したものです。

これらの変更は、Go言語の型システム、特に「完全型」の概念に関する仕様をより厳密にし、曖昧さを排除することを目的としていました。

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

このコミットは、doc/go_spec.html ファイル内の以下のセクションに影響を与えています。

  1. 「complete」と「incomplete」型の定義部分:

    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -555,22 +555,14 @@ including arrays, structs, pointers, functions, interfaces, slices, maps, and
     channels.
     </p>
    
    -<p>
    -TODO: not sure the rest of this section this is needed; it\'s all covered or should be covered in the sections
    -that follow.
    -</p>
     <p>
      At any point in the source code, a type may be <i>complete</i> or
    -<i>incomplete</i>.  Most types are always complete, although their
    -components, such as the base type of a pointer type, may be incomplete.
    -Struct and interface types are incomplete when forward declared
    -(§Forward declarations) and become complete once they are fully
    -declared.  (TODO: You had array here - why?)\n-The type of a variable must be complete where the variable is declared.\n-(TODO: would be better to say what you CAN do with an interface type,\n-and then drop all the references to complete types in the sections\n-that follow.  What can you do? Use one to declare a pointer variable/field/param.\n-Anything else?)\n+<i>incomplete</i>.  An incomplete type is one whose size is not\n+yet known, such as a struct whose fields are not yet fully\n+defined or a forward declared type (§Forward declarations).\n+Most types are always complete; for instance, a pointer\n+type is always complete even if it points to an incomplete type\n+because the size of the pointer itself is always known.\n     </p>
    
  2. 文字列リテラルの連結に関する記述:

    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -669,11 +661,10 @@ can be computed by the function <code>len(s1)</code>.\n     </p>
    
     <p>
    -String literals separated only by the empty string, white\n-space, or comments are concatenated into a single string literal.\n+A sequence of string literals is concatenated into a single string.\n     </p>
     <pre class=\"grammar\">\n    -StringLit              = string_lit { string_lit } .\n    +StringLit   = string_lit { string_lit } .\n     </pre>
    
  3. 配列型の文法定義:

    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -686,7 +677,7 @@ negative.\n     </p>\n\n     <pre class=\"grammar\">\n    -ArrayType = \"[\" ArrayLength \"]\" ElementType .\n    +ArrayType   = \"[\" ArrayLength \"]\" ElementType .\n     ArrayLength = Expression .\n     ElementType = CompleteType .\n     </pre>
    
  4. 構造体タグのコメント:

    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -783,7 +774,7 @@ but are otherwise ignored.\n\n     <pre>\n     // A struct corresponding to the EventIdMessage protocol buffer.\n    -// The tag strings contain the protocol buffer field numbers.\n    +// The tag strings define the protocol buffer field numbers.\n     struct {\n     	time_usec uint64 \"field 1\";\n     	server_ip uint32 \"field 2\";
    
  5. ポインタの基底型に関する記述:

    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -810,9 +801,7 @@ map[string] chan\n     </pre>\n\n     <p>\n    -To permit construction of recursive and mutually recursive types,\n    -the pointer base type may be denoted by the type name of a\n    -forward-declared, incomplete type (§Forward declarations).\n    +The pointer base type may be an incomplete type (§Types).\n     </p>
    
  6. インターフェースの埋め込みに関する記述:

    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -919,7 +908,7 @@ func (p T) Unlock() { ... }\n     they implement the Lock interface as well as the File interface.\n     <p>\n     An interface may contain a type name T in place of a method specification.\n    -T must denote another, complete (and not forward-declared) interface type.\n    +T must denote another, complete interface type.\n     Using this notation is equivalent to enumerating the methods of T explicitly\n     in the interface containing T.\n    ```
    
    
  7. チャネル型と変数宣言、Sizeof 関数に関する記述:

    --- a/doc/go_spec.html
    +++ b/doc/go_spec.html
    @@ -1087,7 +1076,7 @@ of the map.\n\n     A channel provides a mechanism for two concurrently executing functions\n     to synchronize execution and exchange values of a specified type. This\n    -type must be a complete type (§Types). <font color=red>(TODO could it be incomplete?)</font>\n    +type must be a complete type (§Types).\n\n     <pre class=\"grammar\">\n     ChannelType = Channel | SendChannel | RecvChannel .\n    @@ -1249,7 +1238,6 @@ TODO in another round of editing:\n     It may make sense to have a special section in this doc containing these rule\n     sets for:\n\n    -complete/incomplete types\n     equality of types\n     identity of types\n     comparisons\n    @@ -1593,7 +1581,7 @@ type Comparable interface {\n     <p>\n     A variable declaration creates a variable, binds an identifier to it and\n     gives it a type and optionally an initial value.\n    -The variable type must be a complete type (§Types).\n    +The type must be complete (§Types).\n     </p>\n     <pre class=\"grammar\">\n     VarDecl     = \"var\" ( VarSpec | \"(\" [ VarSpecList ] \")\" ) .\n    @@ -3776,7 +3764,7 @@ a <code>Pointer</code> and vice versa.\n     </p>\n     <p>\n     The function <code>Sizeof</code> takes an expression denoting a\n    -variable of any type and returns the size of the variable in bytes.\n    +variable of any (complete) type and returns the size of the variable in bytes.\n     </p>
    

コアとなるコードの解説

このコミットの主要な変更は、Go言語の型システムにおける「完全型」の定義と、それに関連する制約の明確化にあります。

  1. 「完全型」の定義の厳密化:

    • 最も重要な変更は、不完全型を「サイズがまだ不明な型」と明確に定義し、ポインタ型が指す先の型が不完全であってもポインタ型自体は常に完全であるという点を強調したことです。これは、コンパイラがメモリを割り当てる際に、ポインタ変数のサイズ(通常は固定)さえ分かれば、それが指す先のオブジェクトのサイズが不明でも問題ないという、基本的なコンパイラの動作原理に基づいています。この明確化により、Goの型システムがどのようにメモリ管理と連携するかがより理解しやすくなりました。
  2. 仕様書の簡潔化と「TODO」の解消:

    • 複数の「TODO」コメントが削除されたことは、Go言語の設計チームが「完全型」に関する議論を終え、その概念が仕様として固まったことを示しています。特に、チャネル型が完全型であるべきかどうかの疑問や、完全型/不完全型に関する独立したセクションの必要性に関する疑問が解消されたことが分かります。これにより、仕様書全体の完成度と一貫性が向上しました。
  3. 文法と記述の統一性:

    • 文字列リテラルの連結に関する記述の簡素化や、文法定義の整形は、仕様書全体の品質向上に貢献しています。特に、文字列リテラルの連結はGo言語の便利な機能の一つであり、その記述がより簡潔になったことで、読者が理解しやすくなりました。
  4. 構造体タグと関数の引数型の明確化:

    • 構造体タグが「定義する」という表現になったことや、Sizeof 関数が「完全な」型の変数を引数にとるという明示は、Go言語のセマンティクスをより正確に反映しています。これにより、開発者がGoのコードを書く際に、型の振る舞いや関数の期待する引数について誤解する可能性が低減されます。

全体として、このコミットは、Go言語の初期の仕様書における重要な概念である「完全型」に関する記述を洗練させ、言語の厳密性と明確性を高めることに貢献しました。これは、Go言語が安定した、予測可能な振る舞いを持つ言語として発展していく上で不可欠なステップでした。

関連リンク

参考にした情報源リンク