Rust なのか Go なのか..

ひとりごと。色々、漁ってると、こんな雰囲気。


並行処理で
もっと高速に書きたい
→ Go

シングルマシンで
もっと高速に書きたい
→ Rust

◯ 用途

Rustと競合? - Goへの誤解について
似てるのは例外機構を捨てたこととバイナリがポータブルなことぐらい。得意な用途は全く異なります。...

Go は非同期処理をシンプルに書きつつマルチコア性能を引き出すのが強みです。

Rust は徹底してオーバーヘッドを排除してシングルコアの限界性能を引き出せるのが強みです。... これらの強みが関係ない分野だけが競合しています(CLIツールなど)。


Rust が非同期サポートを標準から切り離した流れが書かれている。

Rustは昨年に非同期サポートを標準から切り離しました。事実上システム記述用途に特化していく模様です。
Rustと競合? - Goへの誤解について


  • 2018 年にもなって非同期 IO で疲弊している
  • Rust は 2006 年に開発が始まった
  • node.js も go も 2009 年には存在していた
  • 今まで Rust は何をやっていたのか?
    Rust と非同期 IO の歴史 - Qiita



Go は非同期処理を強く意識しているみたい...

Goの場合、アプリケーションは普通の同期プログラミングをするだけで、 非同期プログラミングのメリットを享受することができます。
Go が他の多くの言語での非同期プログラミングよりも優れている理由 - Qiita

◯ Go が採用された例

隠れマルコフモデルという統計機械翻訳アルゴリズムを使ってC++で実装されていた機械翻訳エンジンを、パフォーマンスを上げるために並列処理が得意なGo言語に書き換えるという仕事をいただきました。
サンフランシスコで創業したスタートアップを解散した話 - note

◯ 速度

速度は Rust の方が出るみたい

The Computer Language Benchmarks Game
There really isn’t any argument: Rust is faster than Go. In the benchmarks above, Rust was faster, and in some cases, an order of magnitude faster.
Should I Rust, or Should I Go


と思ったら、非同期が苦手だからマルチコアも苦手なのかなって理解は間違ってるようです... Rust は、どういうアプローチをとっているんだろう...。













あるいは
Python, Ruby, Perl, PHP
もっと高速に書きたい
→ Go

C/C++
もっと安全に書きたい
→ Rust

◯ 用途

システムプログラミング言語 - saneyuki_s log
Go は Compiled Pythonともいうべき立ち位置な気がする。PythonとかPerlとかRubyとかシェルスクリプトとか以上C未満な箇所を、JavaScalaよりももっとスマートに置き換える、そういう意味での「システム」開発言語。

対する?Rust は、カーネルとかブラウザエンジンとかゲームエンジンとか、ハードウェアに近いエリアの計算機資源をがしがしと叩きまくるための言語。C/C++の面倒くさい因習やエクストリームな部分をうまく隠蔽しつつ、時々必要になったらunsafeブロックで例外的に許容する。その安全性の担保として、コンパイラを使った静的チェックをCPUとメモリにものを言わせてブイブイとかけまくり、機械さまに網羅的にチェックしてもらう。これはこれで「システム」言語。

と考えると、一部の急進派Pythonista(RubyPerlの人も含む)やGo信奉者がなぜRustをdisったり揶揄するのかよくわからない。上手く住み分けできそうなものではあるけど。

◯ Go が採用された例

もともと Python で書いていたものを Go で書き直す。

今年の初め、我々は Stream の主要言語を Python から Go に切り替えました。
Why we switched from Python to Go

◯ Rust が採用された例

もともと C で書かれていたものを Rust で書き直す。

少し調べてみると、私はすぐに納得しましたが、BINDの一番大きな問題は「Cで書かれていること」というのが明らかとなりました。
Rust と DNS の1年 - POSTD


この著者が Go よりも Rust が素晴らしいと感じたのは、著者が扱っていたものがどちらかというと C とか Rust が取り扱うものに近しいからかなと思ったりもします。

私は何かを書くたびに古くて濁ったプログラミング知識の膜が自分の目からキレイに拭き取られていくのを感じました。その光を見てしまったらこの約束の地に降り立ってしまったらもう引き返すことはできません。
Rust と DNS の1年 - POSTD





◯ 用途

Go と Rsut は全く用途が違うそうです。なので、自分の用途に合わせて選ぶことになるかなと思いますが...

Rust と Go は競合しない
Go は、アプリケーションの厳格なシンプルさを通して、規模の大きなチームが効率的にプログラミングできるようにすることを目標にしています。 ー Go は、シンプルでないもの、あるいは 非直交性 を招く恐れがあるアイディアを採用しません。

Rust は、安全でないメモリ参照やランタイムオーバヘッドを許容せずにプログラミングできるようにすることを目標にしています(Go もまた安全でないメモリ参照を許容していません、新しいメモリ不安全な言語に需要があるとは思えません)。ー Rust は安全でない、あるいはオーバーヘッドが生じるようなアイディアを採用しないか、少なくともそのようなアイディアを言語の中心部に据えるようなことはしません。

Rust and Go are not competitors
Go is focused on making large teams of programmers efficient, though rigid application of simplicity — ideas which are not simple or lead to non orthogonal corner cases are rejected.

Rust is focused on a class of programs which cannot tolerate unsafe memory access (neither can Go, I don’t think there is any appetite for a new unsafe programming languages) or runtime overhead — ideas which are unsafe, or come with overhead, are rejected or at least pushed out of the core language.

RedMonkプログラミング言語ランキング
そういったなかには、バックエンドシステム言語として急上昇していたGoがほぼ横ばいになっていることも含まれている。 Goは2015年6月期のランキングから15位を保っていたが、今回TypeScriptが躍進した結果、初めて順位を落として16位となった。 O'Grady氏はGoがバックエンドの言語としての役割を超え、例えば Java のような言語ほど多くの用途に使われるようになるとは考えていない。

Go はランタイムを肥大化させるデザインをとってしまったので、 C, C++, Rustに比べて wasm では根本的に不利。 確実に負債になるといわれていた Go の欠点が wasm ではっきりと表面化しているので、 あまり期待しないほうがよいです。 (どういうデザインなんだろう...)
"Go言語がWebAssemblyをサポートへ " に対する megumin1 氏のコメント




そもそも、用途が違うので、比較すること自体あまり意味がないかもしれません。正直、あまり非同期処理を意識して書いたことがないので、もう少し違いを探ってみたいと思います。

Google トレンド

技術的なトレンドとかはよくわからない。Go は登場してから Rust に比べれば急激に人気を増やしたような気配がある。後発の Rust はじっくり、じんわりな感じだ。

Go が一気に Rust を突き放して駆逐しそうに見えるけど、ここ1年に限定すれば Rust と Go は横ばい。数字だけ見ると、このまま安定してお互い共存しそうな気配がある。

◯ 文法

Go は色々機能を削って作られた言語らしい。Google はサービスの機能を意図的に削除したりする傾向にある。GAE は JOIN を削ったし、Chrome は綺麗さっぱりいろんなボタンをブラウザから削った、検索サイトのトップ画面も Yahoo! やら msn とは違う、検索欄だけのページを設計したりした。*1

リファクタリングしていて関数やらコードを削れたときは、結構気持ちいいものだし、誰が書いても同じようなコードになるというもちろんそれはすごく惹かれる..

けど、やや辛い時がどうしても生じてくる気がする.. GAE みたいに。Python から Go に書き直すみたいに、ある程度先が、開発するものの全体像が見えていれば採用もできるかもしれないけど。

Go はいろんな機能が削られているので、たまに "物凄い" 貶され方をしたりするのを、たまに見かける。


  • Goは何も新しいことをしない。
  • Goは全てにおいてうまく設計されているとは言えない。
  • Goは他のプログラミング言語から退化したものである。

Go言語がダメな理由 -POSTD


こんな "物凄い" 貶され方をする理由は、 その人たちのアイデンティティを挑発してるからっていうのは、面白かった。

それって、Goのシンプルな言語哲学が、ML系言語好きのアイデンティティを挑発しちゃってるからじゃないの?
[翻訳]なんでGoってみんなに嫌われてるの? - Qiita


ただ、高機能で抽象化して簡潔にできることは、必ずしもいいことだけではない。 色々な書き方ができてしまうと言うのは、それなりに弊害もあったりする。

コードが理解しづらい
  4. コメントなしに低レベルの最適化が施されている
  5. コードが賢すぎる
コードが追いかけづらい
  4. 全てが抽象化されすぎている
まずコードの可読性を最適化しよう


例えば Python は、「インデントを強制して誰が書いても同じような」と主張されてるよりは、意外といろんな書き方ができる。もちろん、どんな言語だって書こうと思えばいろんな書き方ができる。「同じような」なんて言うこと自体若干怪しい。

ただ、意外といろんな書き方ができる一つの要因としては Python が高機能であることが挙げられると思う。これらの機能を使うことで、抽象化を上げて、より簡潔な記述で記載することができる。反面、その機能を使うか使わないかで、書き方に幅が出てくる。

実直に and で全部書き上げてしまのかとか、それとも all 関数で条件文を書くのか。 実直に 関数で処理するのか、それともメソッドで処理するのか。

"""矩形の等号 == を表現する書き方について考える."""


def sample_code():
    # 書き方1 実直に..
    assert eq(Rectangle(1, 1, 2, 2), Rectangle(1, 1, 2, 2))
    
    # 書き方2 Python の機能をフルに使って..
    assert Rectangle(1, 1, 2, 2) == Rectangle(1, 1, 2, 2)


# こんな矩形のクラス
class Rectangle(object):
    def __init__(self, x1, y1, x2, y2):
        self.x1 = x1
        self.y1 = y1
        self.x2 = x2
        self.y2 = y2


#
# 書き方1 実直に..
#
def eq(rectangle_a, rectangle_b):
    return \
        rectangle_a.x1 == rectangle_b.x1 and \
        rectangle_a.y1 == rectangle_b.y1 and \
        rectangle_a.x2 == rectangle_b.x2 and \
        rectangle_a.y2 == rectangle_b.y2


#
# 書き方2 Python の機能をフルに使って..
#     1. 演算子オーバロード __eq__
#         all 関数, zip 関数, ジェネレータ式
#     2. イテレータ __iter__
#         yiled 文
#     3. メソッドの動的な追加
#
def __eq__(rectangle_a, rectangle_b):
    return all(a == b for a, b
                    in zip(rectangle_a, rectangle_b))


def __iter__(rectangle):
    yield rectangle.x1
    yield rectangle.y1
    yield rectangle.x2
    yield rectangle.y2


Rectangle.__eq__ = __eq__
Rectangle.__iter__ = __iter__


#
# Execute the sample code.
#
if __name__ == '__main__':
    sample_code()


書き方2は、本来 iterable 出ないものを無理やり iterable にして抽象化の度合いを上げてるので読み辛い。ここでは可読性は置いておいて、書き方に幅があることだけを考察。適切に抽象化したものは、表現も簡潔になり可読性も上がる。yield 文, generator なんかも、うまく使えばコード数を半分以下にすることができる。
ジェネレータ関数から別のジェネレータ関数を呼び出したい - Python のジェネレータってなに?


狂気の沙汰だけど Python でも実行速度を求め出すと、稀に低レベルに記述したりし出したりする。関数呼び出しのオーバーヘッドを削るためにベタがきするとか。

$ # 関数を使ったコード
$ python -m timeit "max(2, 1)"
1000000 loops, best of 3: 0.209 usec per loop
$
$ # ベタ書きのコード
$ python -m timeit "2 if 2 > 1 else 1"
10000000 loops, best of 3: 0.0395 usec per loop
$ # 関数を使ったコード
$ python -m timeit -s "import math" "math.floor(4 / 3)"
10000000 loops, best of 3: 0.169 usec per loop
$
$ # ベタ書きのコード
$ python -m timeit "4 // 3"
100000000 loops, best of 3: 0.0132 usec per loop
$ # 書き方1 実直に..
$ python -m timeit -s "from rectangle import Rectangle,eq" "eq(Rectangle(1, 1, 2, 2),Rectangle(1, 1, 2, 2))"
1000000 loops, best of 3: 1.94 usec per loop
$
$ # 書き方2 Python の機能をフルに使って..
$ python -m timeit -s "from rectangle import Rectangle,eq" "Rectangle(1, 1, 2, 2)==Rectangle(1, 1, 2, 2)"
100000 loops, best of 3: 4.33 usec per loop
$

Python を高速化したい。


処理を速くしようとして、こんなこととか、 for 文で書こうかなとか while 文で書こうかなとか、そんなことを気にしだしたらいっそ思いっきり Java などの静的言語に切り替えを検討する時だと思う、あるいは Rust か Go か。

なぜなら、抽象化の一貫性を犠牲にしてまで工夫しても、部分的に見れば何倍も速くできるけど、全体から見れば高が知れていて数%も速くできるかどうか..。でも、言語を切り替えれば何倍も速くなる。

Python は、適切に抽象化具合をあげて短く書くことを前提にしている。何故なら、Python がそういった機能を提供しているし、PEP 8 - Style Guide for Python Code でも 1 行最大 79 文字とごく短く制限されているから。
Python で 1 行を最大 79 文字以内に抑える方法とその理由

低レベルに書き込むことは、PEP 20 - The Zen of Python の言う、たったひとつだけあるはずのストレートなやり方ではないと思う。

何かをやるには、ストレートなやり方がひとつ、
たったひとつだけあるはず
There should be one-- and preferably only one --obvious way to do it.
Python にまつわるアイデア: PEP 20 | Life with Python


Rust がネックになるのは、抽象化の一貫性にばらつきが生じてしまう可能性があること。Go がネックになるのは、どうしても可読性に欠けてしまうこと。それに耐えられなくなるったある日、突然 Rust の光を浴びてしまうのかもしれない。

ただ、学習するっていう意味で言えば、Go と Python という組み合わせは、両極にあっていいのかもしれない..。Go と Python で切り替えて気分転換しながらみたいな。人間、抽象具合をあげて簡潔に書きたい時もあれば、ガリガリ低レベルに書きたい時もある。



でも、もっと Go と対極にあるのは Ruby だと思う..。

昔、PythonRuby を比較して Ruby は、自由に書けるから遊びやって just for fun や見たいな感じで YouTube でディスってる人がいて、炎上してる動画を見たことがある。

でも、楽しいってすごく大事だと思う。もし気の合う人とだけで少人数でプログラミングができるなら、きっと Ruby は楽しい言語だと思う。Rails が出てきて Web サービス組むことに対して Python に比して1日の長が得られたのもそういった所にあるのかなと思う。

Python の framework を探してたときに、ほんの少しだけ CakePHP をかじってたから、当然、インデントを強制して誰が書いても同じようにと歌っている Python の framework も当然、設定より規約的なものだろうと思っていたけど、現実はそうではなかった。

Django は大きすぎて触ってて違和感があって。色々と自由に作れるように、ちゃんと設定してねっていう感じ。でも、そこまで作り込むなら Java なりなんなりに逃げると思うし。別にそんなに大きいもの作らなくていいから、程よく小さいものが作れるのが欲しかった。

だから Rails どうなんだろうって思ってコード見たときは、Rails の光が差し込んできて慌ててドアを閉めた記憶がある。自分の人間的な余裕がなくて Ruby を触れないから..

でも、面白いのは Ruby は自由にプログラミンを楽しもうって言ってたのに、出てきた framework は設定より規約で、反対に Python はそうではない。Django がデカすぎるからって出てきた flask とかは、今度は小さすぎて、自分で好きなものをツギハギして自由に書いてねって感じになっていて、そうじゃないって思った。

お互い歩み寄ってるような感じがして、心地よくプログラミングができるって言うのは、単純にこっちがいいとは言えず、繊細さがあるのかもしれない。極端に規約とかに縛られるのが好きな自分は、やっぱりキチガイなのかもしれない。

プログラミング言語に限らず、自然言語も楽しさとかを元に変化したりする。例えば黒人英語とかはその最たるものだと思う。文法の一貫性よりも音感の良さを取り入れて変化してる。*2
言語変化
黒人英語

さらに言えば人は使う言語によって、思考に影響を受けたりもするらしい。難しくてよくわからない。
言語的相対論
使う言語が「世界の見え方」を決めている:研究結果
言語は思考にも影響を及ぼす、だからRuby開発を選んだ
あんな姉と妹の区別もつかない劣等言語でエロゲができるか

日本語も主語とか目的語を省略したりするから、黒人英語が音感を大事にするのとは違うけど、相手とのなんとなくのフィーリングを共有する、会話そのものを楽しむ言語だと思う。そう言う意味ではプログラミングそのものを楽しむって言う Ruby は、どこか日本語的な言語だなと思ったりする...

結局 Rust か Go かと言うのは、そう言った個人の繊細さの問題なのかもしれない。抽象化して簡潔に書きたいなら Rust だし、低レベルにガリガリ書きたいなら Go みたいな。 (2018/05/18: 削除)

Go

Goはオブジェクト指向言語だろうか?
実装継承ってあかんのやな..
Go(golang)についての雑感 | Qiita
Java 使いが Go言語を一日使って思ったこと | Qiita
オブジェクト指向言語としてGolangをやろうとするとハマること | Qiita

ポジティブな記事

Why we switched from Python to Go
または私は如何にして例外するのを止めて golang を愛するようになったか
(go report) Goが本当はすごかったので, 謝罪する

ネガティブな記事

Go言語がダメな理由

Rust

Rustとは何か。どんな言語か。- κeenのHappy Hacκing Blog
Rustは何が新しいのか(基本的な言語機能の紹介)
立ち位置とか

ポジティブな記事

RustとDNSの1年

ネガティブな記事

見当たらない





*1:SNS系のシステムについては、余分な機能を削り必須の機能に絞ることが、必ずしもいい結果をもたらすとは限らない。蛇足と思われる機能を付け加えたり(mixi の足跡)、あるいは本来必要なはずの機能を削ったりして(Twitter の文字数の制限, 増田の匿名)、コミュニケーションの活性化を測ることができる。SNS では、何をコミュニケーションするかよりも、どうコミュニケーションをするかの方が重要なのかもしれない。Google が何故か SNS 系のサービスだと苦戦する傾向があるのは (Blogger, Google+)、こういったところにあるのかなと思ったりする。

*2:全然話は違うけど中国語の動詞には過去形がなかったりする(時制, テンス)。中国 4,000 年の歴史とは一体何だったのか。かわりに、昨日(昨天)とか時間を表す単語で過去を表現したりする。でも、過去形ではないけど、完了形(了) は存在する(相, アスペクト)。単純に動詞に活用がない孤立語だからという話でもあるけれど。相があるなら時制だって補語、助動詞として存在していいはずだと思うけど。同じ孤立語でも、チベット語タイ語には、それに近いものがあるらしい。それが無いということは、中国の人たちは、いまという歴史の中に生きているのかなと思ったりする。