Javaとの比較において、Goのメリットとデメリットについて私的な感想を列挙します。
◆ Goのメリット
〇 命名規則がシンプル
これは、文法ではなく慣習的なものですが、Goでは位置文字変数で会ったり、名前空間であるパッケージ名に使われる言葉を変数名・関数名に使わないようになっています。
また、パッケージ名についてもできるだけアンダースコアで区切らず、一つの単語で表現されることが慣習化しています。(これは、Pythonでも同様なことが見られます。)
命名規則をシンプルにしようと思うと、パッケージの名前空間を細かく分けたり、関数のスコープを短くする必要があり、機能の細分化をおのずとせざるを得なくなります。
これは機能の疎結合を実現し、関数やパッケージの独立化に寄与します。ひいては、テストのしやすいコードになります。
そして、いうまでもなくコード全体が読みやすくなります。
〇 クロスコンパイルと速度
私がGoを開発に選んだ理由は、クロスコンパイルできることが最も大きいです。
最近では、Windows、Mac、Linux、あらゆるプラットフォームで同じプロジェクトについてのドキュメントを作ったりいろいろと作業をすることがあります。
そのときツールがWindowsだけしか使えないとか、Macだけしか使えないでは仕事になりません。
やはり、同一の機能を複数のプラットフォームで実現したいと思います。
クロスプラットフォームでいえば、JavaやQtをつかったC++、AIRなどいろいろ候補はあります。
パフォーマンスとデプロイ・配布を考えた場合、exeなどのバイナリをつくって配布できるという点でGoやQt(C++)は候補に挙がります。
あとは好みや利用されるアプリの性質によりますので、QtかGoかは一概にいえません。単純に、C++よりもGoの方がコーディングをするには楽だというのがあげられます。(Qtを使えばC++のコーディングも楽にはなりますが)
〇 Googleによる開発
GoはGoogleという大きな組織によって開発されているため、たとえ現在、不具合があったとしてもアップデートやその速度についてもある程度信頼を置くことができます。
やはり言語についてはどういった支援のもと開発されているのかというの大きなポイントです。特に、長期的に利用しようとするアプリケーションであればそれは気にして当然だと思います。
〇サードパーティ製のライブラリの豊富さと実績
Goは前述のGoogleが開発しているためか、国内外でも利用されているところも多くあります。(AbemaTV、Docker、DropBoxなどで使われているといわれています。)
2009年に生まれて、年数もそれなりに立っているのでGithubにはGoのパッケージが多数みられ、それを利用できるのもGoのメリットです。
また、これと相まって、Goの情報もネット上には多く見られます。
◆Goのデメリット
Goのデメリットとして、文法上の問題について指摘します。
〇 ソースファイルに名前空間はない
PythonやJavaは、ソースファイル単位でimportをしてソースファイル単位で名前空間を持つことができます。(Javaの場合は、ソース=クラスであり、クラスが名前空間)
Goの場合、パッケージ(ディレクトリ)単位でimportのため、ファイル自体には名前空間はありません。
これは、同一パッケージ内の異なるファイルで、同じグローバル変数名や関数名を作るとエラーになるということです。
つまり、視覚的に見えないところまで命名規則を気にしたり、短い名前にしようと思うと名前空間を作るために、わざわざパッケージを作る必要があります。
同一パッケージ内での名前の冗長化になるか、パッケージの乱立になるかどちらかになる可能性があります。
(短い命名規則をするのならば、ソースファイル単位での名前空間を作るべきだと思います。)
〇 型に厳しいわりにジェネリクスがない
Goは静的型付けを理由に採用されることが多く、実際、型のチェックについては厳しいところがあります。
ですが、ジェネリクスがないため、同じような処理をつくるのにわざわざ、型の異なったものを作ったりする必要がでてきます。
これへの対応としては、「interface{}」のようにVBのバリアント型のように何でも入れられる型を利用する方法があります。ただ、これを使うことは結局、型への厳しさを台無しにしてしまうこういなように思います。
また、ジェネリクスを使わないため、わざわざ抽象的な型をカスタマイズでつくって、型判別をしてswitch文などで処理を振り分けるなど工夫はあるようですが、ジェネリクスを使えばこうした小細工は必要なく、ビルド時にプログラマの手を煩わさずに解決してくれます。
この点は、Java等のジェネリクスが便利だと思います。純粋に、型を抽象化して、逆に型を意識せずに処理のみ記述すればいいので、Goよりもメリットがあります。
〇メソッドの定義時にレシーバ変数を記述する必要がある
Goはクラスがないですが、構造体にメソッドを追加することができます。それをするには、関数名の前に「レシーバ変数」という構造体を型とする引数のようなものを定義します。
Javaなどクラスがある言語の場合、レシーバ変数は不要で、クラスブロック内に、メソッドを定義すればそれで終わりです。
Goの場合は、メソッドがあればメソッドの数だけレシーバ変数を繰り返して各必要があります。
細かいことですし、Goを書いていればなれてきますし、そもそもオブジェクト指向設計ではなく、関数・処理をベースに設計していれば、レシーバ変数もそれほど使わないので気にならないのかもしれません。
これは設計上の問題というよりも、コーディング上の問題で致命的な問題ではありません。
〇標準関数が貧弱
PythonやRubyは標準で便利な関数やメソッドがありますが、Goにはこれらの言語やJavaで当たり前に標準であるような関数やメソッドなどがありません。ですので、自作や他のパッケージを利用することになると思います。
私が面倒だと感じたのは、JavaでいうLinkedHashMapのように順番を保証したmapを作れないということです。それをするにはパッケージなり、自作で作るしかありません。
とにかく、至る所で「こんなのもないのか」と絶句することがあります。
◆オブジェクト指向設計とGo
オブジェクト指向設計との関係でいうと、ステートフルでオブジェクト指向設計の発想で設計してコーディングすると少しめんどくさいです。
これについては、「Goはオブジェクト指向言語ではないから」という分かったような分からないような回答があります。
〇 言語自体の設計思想と言語を使ったアプリの設計思想は異なる
JavaやRubyと比べると、標準関数をみればわかるように、言語としてオブジェクト指向の性質が薄いのは確かです。
ただ、この言語をつかって「オブジェクト指向設計」をしてはならないこととはまた別の話です。(言語自体がオブジェクト指向設計か否かと、言語を使ったアプリをオブジェクト指向設計にするかは別の話題です。)
「オブジェクト指向設計」は、設計の発想であり、それをつかうことはアプリケーションの性質によります。クラスという文法の有無は関係ありません。(クラスがある方が書きやすくはあります。)
ゲームや業務系など値の集合を扱い、ステートフルな場合、オブジェクト思考設計は、クラスがあろうとなかろうと発想として使われるものだと思います。
実際、アプリケーションをつくっていけば、値の集合や、それに紐づく処理(メソッド)を作る方が楽だと思います。
それゆえに、クラスという文法があり、それをつかった「オブジェクト」をつくり、設計をしていくのが「オブジェクト指向設計」です。
Goも構造体とメソッドをつかえば、「オブジェクト指向設計」はできます。ただ、メソッドをつくるのにいちいちレシーバ変数を書くのはめんどくさいと思います。
〇「継承」はそもそもオブジェクト指向設計にもなくていい
あと「継承がない」については、そもそも「オブジェクト指向設計」においもて、「継承」を多用すべきではなく、継承はクラス自体の独立性を阻害し、処理の流れを分かりにくくするものであり、「オブジェクト指向設計」としては、それほど重要なものではありません。
GoやRustは継承がないですが、それは悪しきコードを生まない賢い仕様だと思います。(Java等の分かりにくいコードの原因のいくつかは、きっと継承のせいです。)
オブジェクト指向とは、オブジェクトの協業であるので、クラス自体が独立しておくことが望ましいと思います。処理の抽象化は、インターフェイスで行い、それらを委譲の形でロジックを組めば継承は不要なはずです。
◆ さいごに
以上、Goのメリットとデメリットを私的な見解ゆえに、かなり偏りがあるみかたではありますが、列挙しました。
基本的に言語の機能上デメリットがあるというよりも、コーディング上多少めんどくさい点があるというのが個人的な見解です
コーディングや設計をしていて、Javaよりも優れているかというとそうは思わず、コーディングだけでみれば「Better than C」という感じで、C言語より便利で、C言語のようなメリットがある言語という感じがします。
オブジェクト指向設計をして、アプリの実行環境や速度の問題がそれほどないのであればJavaの方がよいと思います。わざわざGoにする理由はほとんどありません。
ただ、一ついえるのは、Javaそのものではなく、Javaによって作られる冗長で、「似非オブジェクト指向設計(※)」を改善する「コーディングギブス」、「コーディングデトックス」として、Goのシンプルなコーディングスタイルを触れることは意味があるかもしれません。
※)Javaのコードでみられる「似非オブジェクト指向設計」においては、クラスが肥大化してメソッドがやたらに長い名前であり、独立化したオブジェクトが作られていないケースが多くあります。
これは、クラスを独立・細分化した機能ではなく、あくまでもパッケージとしてつかっているに過ぎないのだと思います。
クラスさえつくれば「オブジェクト指向設計」だという認識があるのでしょうか。これは、逆に、クラスのないGoやRustを使うことで、「オブジェクト」とは何かを逆に学ぶ必要があるのではないでしょうか。
(オブジェクトとは純粋に「値と処理」の組であり、ある限られた主題・処理についてつくられた組。そして、この組を積み上げて、現実にある状態をモデル化して、大きなオブジェクトを作り上げるのがオブジェクト指向設計だと思います。そして、処理自体をもオブジェクト(変数)にしてしまうからこそ、オブジェクト「指向」なのだと思います。)