Go Conference 2014 Autumnレポート

Go言語の父と呼ばれるRob Pike氏による基調講演~Go Conference 2014 Autumn基調講演1人目

この記事を読むのに必要な時間:およそ 4 分

正しい言語機能

同氏は,正しい言語機能とは「機能のための機能」ではなく,⁠隙間を埋める機能」であると主張していました。 ⁠隙間を埋める機能」とは,解空間を覆う基底ベクトルのような,予想したとおりに作用する直交する機能で,単純に動作する単純な機能であるそうです。 同氏は,単純さは直交性と予測可能性に依るものであると述べていました。 そして,言語の目的を常に肝に命じて,言語機能を決めるべきだと主張していました。

Go言語の目的

同氏は,Go言語はスケーラブルなクラウドソフトウェアのために設計されたきれいな手続き型言語であると述べていました。そして,以下のような単純で組み立て可能な要素から構成されているとのことでした。

  • 具象データ型
  • 関数とメソッド
  • インターフェース
  • パッケージ
  • 並行性

また,これらに加えて良いツール(go tool)と速いビルドを提供していると述べていました。

同氏は,Go言語のマスコットであるGopherを使って,細かく描写されたGopherと比較することで,単純さの重要性を訴えていました。

写真2 単純なGopher(左)と複雑なGopher(右)

写真2 単純なGopher(左)と複雑なGopher(右)

Go言語が提供する単純さ

Go言語は裏にある複雑さを隠し,利用する人に単純さを提供しているそうです。そして,各機能はお互いにシームレスに調和し,驚きがないように作られているそうです。Go言語では,以下の機能が裏にある複雑さを隠して,単純さを提供しているとのことでした。

  • ガベージコレクション
  • ゴルーチン
  • 定数
  • インターフェース
  • パッケージ

ガベージコレクション

ガベージコレクションは,複雑さを隠す単純さの最たる例であるとのことでした。同氏は,ガベージコレクションをうまく実装するのは難しいが,実装する価値があり,コードが単純に書けるのはガベージコレクションのおかげだと主張していました。そして,ガベージコレクションがあることで,設計に「所有権」を含める必要がなく,freeを使うこともないと述べていました。

ゴルーチン

Go言語では,並行性を提供しています。並行性とは,プログラムを独立して実行している部品のように書ける能力のことだそうです。Go言語の並行性は以下の3つの要素から構成されています。

  • ゴルーチン(実行)
  • チャネル(コミュニケーション)
  • select(調整)

ゴルーチンは,キーワードのgoを使うことで起動できます。

go function(args)

これは通常の関数呼び出しに,余分に3つのキー「g⁠⁠,⁠o⁠⁠,⁠スペース」を押すだけで,非常に単純であると同氏は述べられていました。しかしながら,ガベージコレクションのように,プログラマの心配からくる以下のような考えごとをなくしてくれると主張していました。

  • スタックサイズがない
  • returnや終了ステータスがない
  • 管理する機構がない
  • ゴルーチンのIDがない
特に

これらの機能は,他のシステムでは提供されていますが,Go言語では,最小設計にしているそうです。しかし,その実装は複雑でスタックの管理はガベージコレクションに依存しているそうです。

定数

同氏は,Go言語の定数はただの数で,たとえ強く型付けがされていても同様だと述べていました。これは単純な考えですが,実際にそのように決めるには1年ほどかかったそうです。特に難しかった点は以下だったそうです。

  • 「無限」精度整数型
  • 「無限」精度浮動小数点型(試してみて,有理数で失敗した)
  • 昇格規則i := 2; f := 2.0; g := 1/2; h := 1/2.0
  • シフトのようなコーナーケースfmt.Printf("%T %T", 2.0, 2.0<<0

これらは十分に満たしているというわけではないそうですが,定数を数字のように扱えるようになっているため,Go言語の使いやすさに貢献しているとのことでした。定数については,この記事を見ると良いそうです。

インターフェース

同氏は,Go言語のインターフェースは以下のようにただのメソッドのまとまりで,データではないと述べていました。これは単純な考えのように見えますが,実装は予想以上に複雑であるそうです。

type Reader interface {
    Read([]byte) (int, error)
}

たとえば,インターフェースを言語機能として提供するには,当然インターフェースを型とする変数が必要です。これらの変数は静的型付け言語に動的型付けの要素を追加しているそうです。以下の例では,rxを代入するには明示的に型を指定して,r = x.(Reader)のように代入する必要があり,これは動的に型がチェックされます。

var r Reader = os.Stdin         // 静的にチェックされる
var x interface{} = os.Stdin    // 静的にチェックされる
r = x.(Reader)                  // 動的にチェックされる

このように,インターフェースの代入は実行時チェックするように実装する必要があり,その実装は注意深く設計する必要があるそうです。たとえば,代入が失敗した場合はどうするべきかを考える必要が出てきて,それは型アサーションと「カンマOK」イディオムの話につながるそうです。型アサーションと型スイッチは本来の計画では存在していなかったそうで,さらに複雑な実装になっているそうです。

同氏はインターフェースはGo言語において最も特徴的で強力な機能の1つだと述べていました。インターフェースの存在は,標準ライブラリ設計において非常に大きな効果を見せたそうです。インターフェースは真のコンポーネントアーキテクチャを可能にし,その最たる例がio.Readerio.Writerであると述べていました。これらはUNIX系OSのパイプの考え方を一般化したものだそうです。

パッケージ

パッケージの設計には長い時間がかかったそうで,さらにその実装はガベージコレクションに次いで,見た目以上の複雑さを裏に持っているそうです。パッケージは複雑さを隠す単純さを持っており,コンポーネント化,スケーラビリティ,共有,データの隠蔽と隔離を可能にしています。これは,プログラムの設計,構文,命名,ビルド,リンク,テストなどに影響を与えているそうです。たとえば,パッケージのパス"math/big"など)とパッケージbigなど)を別にしたことにより,go get機構を可能にしたそうです。

著者プロフィール

上田拓也(うえだたくや)

KLab(株)所属。Go Conference 2014 Autumnスタッフ。

業務ではJavaScript,Luaなどを扱っている。

大学時代にGo言語に出会い,それ以来Go言語にのめり込む。

時間があると,Go言語の勉強会に参加している。

Go言語のマスコットのGopherの絵を描くのも好き。

Twitter:@tenntenn