go言語1.9で追加予定の新機能 型エイリアス

  • 16
    いいね
  • 0
    コメント

型エイリアス

go言語に1.9から型エイリアス(type alias)が追加されるようです。
ちょうど去年の今頃に提案された機能です。
この機能はどちらかと言うと実験的というか、反対票が賛成を4倍で上回るような
今回で確定するには難しい話なので、今後の議論のために実際に扱っていくという目論見もあるようです。

//type構文
type Gopher oldpkg.TheGopher
//alias構文
type AliasGopher = oldpkg.TheGopher

上記のような構文でtypeと違い=演算子が間に入ります。
あくまでtypeキーワードは別の型の宣言であり、aliasは他の言語のaliasと同様、そのtypeそのものを参照します。
なのでそのtypeのメソッドを使用でき、aliasに対してメソッドを追加したりすることは不可能です。

主な用途、動機

珍しいことにリファクタリングを主な動機とした構文であり、現状の大規模開発での型の変更の難しさから提案されました。
パッケージの整理のための分割、単により良い名前への変更、依存関係の軽減など、型を変更する理由は少なくありません。
しかし型は関数のようにラップすることも定数、変数のように代入することもできないので一度での修正が必要になります。
特にGoogleはモノリシックレポジトリでの運用です。
これは大まかにいうとすべてのプロジェクトを一つのレポジトリに突っ込んでそこにコミットしまくります。
なのですべてのコードが最新に保たれますが言い換えれば変更の影響範囲すべてにその時のコミットで対処しなければいけません。
ライブラリが変更されればそのときにそのライブラリの全ての呼び出し元を修正する必要があります。
これを緩和するために、古いtypeと新しいtypeを共存可能にすることで移行をスケールして行うことが可能になります。

なぜtypeのみか

typeのみなのは変数、定数、関数はすべて現状の仕様で行えるためです。
go言語にとってどうしても解決したい問題はtypeの移行でした。
一応、aliasをvar,const,func にも行えるより一般的なaliasとして扱う案もありましたが
=の構文ではvar Something = pkg.Somethingとなります。
これは既存の、通常の代入であり、別の意味合いになるため不可能でした。
aliasはあくまで本体の参照であり、コピーである代入ではいくつか意味合いが異なってしまいます。
演算子を=>などに変える案もありましたがやはり直感的な構文は=であり最大の目的はtypeだったので現在の使用で行われるようです。

ついでの便利効果

  • 嫌われ者のドットインポートを削除できます。
  • ローカルエイリアスでグラフィック処理でのMath.SinなどをSinにすることで可読性を上げることが可能になります。

過去に問題となった事例

io.ByteReader->bytes.Readerの時は初期だったので数十ファイルで済んだようでしたが
os.Error->errorへのエピソードは強烈でした。
現在errorは組み込み型ですがかつて、os.Errorでした。
errorになれた我々からすると違和感もあると思いますがとにかくそうでした。
当然errorを扱うためにos.Fileだとかに依存する必要性は全く無く、errorsパッケージができるのは必然でした。
しかし段階的に移行する手段はありませんでした。
ログを見るとわかりますがGoTeamが取った手段はなんと

"コンパイラにハックを追加して一時的にコードをos.Errorとして解釈するようにさせる"

でした。オシャンティの欠片もありませんがそこがまたハードボイルドでいいですね。濡れました。
こんな話を聞かされれば二度とこんな悲劇を繰り返させないようにエイリアスに賛成したくなると思いましたが
世の中には血も涙も無い反対派もいます。

現状の反対意見

提案で出ていた反対意見
1. してはいけないことが出来てしまう,乱用するとローカルでもないのにローカルみたいに見えたり同じものを複数作れる
2. そもそもモノレポ運用のGoogleしか問題にならないのでは
3. 初心者に教えるのにリファクタリング云々とかいう魔法機能はややこしい

反対意見に対する反論
1. その手のことは今でも出来てしまう。それにappendとかのキーワードに値を入れることもできるけどそんなことする人がいないように
  出来るだけではそれほどの問題にはならない。仮に出来てもツールで検出するようにも出来る。
2. 大規模開発ならどうしても起こる。
3. 初心者向けの機能ではない。
などなど色々ありました。

まとまっていてシンプルでオシャンティなgoの機能ばかりに目を取られていて
言語仕様としてリファクタリング目的というのは当初違和感はありましたが
go言語のフォーマットツールやgodocなど、言語仕様だけでなくプログラマの開発環境を重点を置き、
実情としてどうするべきか、エコシステムを視野に入れ考えていくgoならではの機能追加な気がしました。
エイリアスのエイリアスを作れるようにするべきかなど、色々どちらが正解ともいえない細部も多く
今回の実装によってどんな意見が出てくるのか楽しみです。
手首のスナップを鍛えていこうと思います。

エイリアスが要るようなリファクタリングしっかりした大規模開発と出くわすことがある人にはいい機能かもしれません。

参考

エイリアスの提案
https://github.com/golang/proposal/blob/master/design/18130-type-alias.md
エイリアスの議論
https://github.com/golang/go/issues/16339
リファクタリングについて語る
https://talks.golang.org/2016/refactor.article