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

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

このコミットは、Go言語の公式FAQドキュメント doc/go_faq.html の内容を更新するものです。具体的には、Goの型システムに関する記述において、「ダックタイピング」という表現を「構造的型付け」に修正しています。

コミット

faq: go does not have duck typing

R=golang-dev, 0xjnml, iant, adonovan, aram
CC=golang-dev
https://golang.org/cl/6500092

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

https://github.com/golang/go/commit/4be9b83eb6006d8fbda438f1508315fe48f21fc7

元コミット内容

commit 4be9b83eb6006d8fbda438f1508315fe48f21fc7
Author: Rob Pike <r@golang.org>
Date:   Fri Sep 7 14:01:02 2012 -0700

    faq: go does not have duck typing
    
    R=golang-dev, 0xjnml, iant, adonovan, aram
    CC=golang-dev
    https://golang.org/cl/6500092
--
 doc/go_faq.html | 2 +-| 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/go_faq.html b/doc/go_faq.html
index 64acd96a2d..b7fdb7b568 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -541,7 +541,7 @@ Why doesn't Go have "implements" declarations?</h3>
 <p>
 A Go type satisfies an interface by implementing the methods of that interface,
 nothing more.  This property allows interfaces to be defined and used without
-having to modify existing code.  It enables a kind of "duck typing" that
+having to modify existing code.  It enables a kind of structural typing that
 promotes separation of concerns and improves code re-use, and makes it easier
 to build on patterns that emerge as the code develops.
 The semantics of interfaces is one of the main reasons for Go's nimble,

変更の背景

このコミットの背景には、Go言語のインターフェースがどのように型を満足させるかについての、より正確な表現へのニーズがあります。Goのインターフェースは、明示的な implements 宣言なしに、型がインターフェースのすべてのメソッドを実装していれば、そのインターフェースを自動的に満たすという特徴を持っています。この特性は、Pythonなどの動的型付け言語における「ダックタイピング」と表面上は似ているため、初期のドキュメントではそのように表現されていました。

しかし、Goは静的型付け言語であり、コンパイル時に型チェックが行われます。ダックタイピングが実行時まで型の適合性をチェックしないのに対し、Goのインターフェースはコンパイル時に厳密にチェックされます。この重要な違いを明確にするため、より適切な「構造的型付け」という用語に修正されました。これは、Goの型システムが、型の構造(つまり、持っているメソッドのシグネチャ)に基づいて適合性を判断するという本質を正確に反映しています。

前提知識の解説

ダックタイピング (Duck Typing)

ダックタイピングは、主にPythonやRubyなどの動的型付け言語で用いられるプログラミングスタイルです。「もしそれがアヒルのように鳴き、アヒルのように歩くなら、それはアヒルである」という格言に由来します。これは、オブジェクトの型が、そのオブジェクトが持つメソッドやプロパティによって決定されるという考え方です。

  • 特徴:
    • 明示的なインターフェース宣言や継承は不要。
    • 実行時にメソッドの存在がチェックされる。
    • 柔軟性が高いが、実行時エラーのリスクがある。
  • :
    class Duck:
        def quack(self):
            print("Quack!")
        def walk(self):
            print("Waddle, waddle")
    
    class Person:
        def quack(self):
            print("I can quack like a duck!")
        def walk(self):
            print("I walk like a human.")
    
    def make_it_quack_and_walk(animal):
        animal.quack()
        animal.walk()
    
    duck = Duck()
    person = Person()
    
    make_it_quack_and_walk(duck)
    make_it_quack_and_walk(person) # Personもquackとwalkを持つので動作する
    

構造的型付け (Structural Typing)

構造的型付けは、型の互換性がその構造(メンバー、メソッド、プロパティの集合)に基づいて決定される型システムです。Go言語のインターフェースがこれに該当します。型が特定のインターフェースのすべてのメソッドシグネチャ(メソッド名、引数、戻り値の型)と一致するメソッドを持っている場合、その型はそのインターフェースを自動的に満たします。明示的な implements キーワードは必要ありません。

  • 特徴:
    • 静的型付け言語で採用されることが多い。
    • コンパイル時に型の適合性がチェックされる。
    • インターフェースと実装が疎結合になる。
    • 既存の型を修正せずに新しいインターフェースに適合させることができる(「暗黙的なインターフェースの実装」)。
  • 例 (Go言語):
    package main
    
    import "fmt"
    
    // Mover インターフェースを定義
    type Mover interface {
        Move()
    }
    
    // Dog 型を定義
    type Dog struct {
        Name string
    }
    
    // Dog 型が Move() メソッドを実装
    func (d Dog) Move() {
        fmt.Printf("%s is moving.\n", d.Name)
    }
    
    // Car 型を定義
    type Car struct {
        Brand string
    }
    
    // Car 型が Move() メソッドを実装
    func (c Car) Move() {
        fmt.Printf("%s car is driving.\n", c.Brand)
    }
    
    func main() {
        var m Mover // Mover インターフェース型の変数を宣言
    
        dog := Dog{Name: "Buddy"}
        car := Car{Brand: "Toyota"}
    
        m = dog // Dog は Move() を持つので Mover インターフェースを満たす
        m.Move()
    
        m = car // Car も Move() を持つので Mover インターフェースを満たす
        m.Move()
    }
    
    この例では、DogCar はどちらも明示的に Mover インターフェースを実装すると宣言していませんが、Move() メソッドを持っているため、自動的に Mover インターフェースを満たします。この適合性はコンパイル時に確認されます。

技術的詳細

Go言語のインターフェースは、その設計思想において非常にユニークであり、Goの柔軟性と堅牢性を両立させる重要な要素です。このコミットは、その本質をより正確に伝えるためのものです。

Goのインターフェースは、メソッドの集合を定義します。ある具象型がそのインターフェースで定義されたすべてのメソッドを、そのシグネチャ(メソッド名、引数の型、戻り値の型)が完全に一致するように実装していれば、その具象型はそのインターフェースを「満たす」と見なされます。この適合性はコンパイル時に静的にチェックされます。

ダックタイピングと構造的型付けの主な違いは、型チェックが行われるタイミング厳密さにあります。

  • ダックタイピング: 実行時にメソッドの存在を確認します。メソッドが存在しない場合、実行時エラー(例: Pythonの AttributeError)が発生します。これは動的型付けの特性です。
  • 構造的型付け (Goのインターフェース): コンパイル時にメソッドの存在とシグネチャの適合性を確認します。もし型がインターフェースのメソッドを一つでも実装していなかったり、シグネチャが一致しなかったりすれば、コンパイルエラーが発生します。これにより、実行時エラーのリスクが大幅に減少します。

Goのインターフェースが「ダックタイピング」と誤解されがちなのは、implements キーワードのような明示的な宣言が不要である点です。しかし、この「暗黙的な実装」は、あくまでコンパイル時の静的な構造チェックに基づいています。この特性は、既存のコードベースに影響を与えることなく新しいインターフェースを導入できるという強力な利点をもたらします。例えば、サードパーティライブラリの型に対して、そのソースコードを変更することなく、独自のインターフェースを定義して適合させることが可能です。

このコミットは、Goの型システムが持つこの重要なニュアンスを、公式ドキュメントで正確に表現することの重要性を示しています。Goは、動的型付け言語の柔軟性と、静的型付け言語の安全性とパフォーマンスを組み合わせることを目指しており、構造的型付けはその実現に不可欠な要素です。

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

--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -541,7 +541,7 @@ Why doesn't Go have "implements" declarations?</h3>
 <p>
 A Go type satisfies an interface by implementing the methods of that interface,
 nothing more.  This property allows interfaces to be defined and used without
-having to modify existing code.  It enables a kind of "duck typing" that
+having to modify existing code.  It enables a kind of structural typing that
 promotes separation of concerns and improves code re-use, and makes it easier
 to build on patterns that emerge as the code develops.
 The semantics of interfaces is one of the main reasons for Go's nimble,

コアとなるコードの解説

変更は doc/go_faq.html ファイルの544行目で行われています。

  • 変更前: It enables a kind of "duck typing" that
  • 変更後: It enables a kind of structural typing that

この一行の変更は、Go言語のインターフェースの動作原理に関する公式な説明を、より正確なものに修正するものです。

元の記述では、Goのインターフェースが「一種のダックタイピング」を可能にすると説明されていました。これは、明示的な implements 宣言なしに型がインターフェースを満たすというGoの特性が、動的型付け言語のダックタイピングと表面上似ているためです。

しかし、Goは静的型付け言語であり、インターフェースの適合性はコンパイル時に厳密にチェックされます。このため、「ダックタイピング」という表現は、Goの型システムの静的な性質を誤解させる可能性がありました。

新しい記述では、「構造的型付け」という用語が使用されています。これは、Goのインターフェースが、型の「構造」(つまり、その型が持つメソッドのシグネチャ)に基づいて適合性を判断するという事実を正確に反映しています。この変更により、Goのインターフェースが持つ静的な性質と、コンパイル時の安全性という重要な側面が明確に伝わるようになりました。

この修正は、Go言語の設計思想と型システムに関する公式ドキュメントの正確性を高める上で非常に重要です。

関連リンク

参考にした情報源リンク