http://wolfbash.hateblo.jp/entry/2017/10/02/163017
重要部分の引用。
Nim は Python に強い影響を受けていて文法は Python そっくりです。そのためスッキリ書けて非常に見やすいです。Python をブラッシュアップして、秘伝の悪魔のタレをかけたような感じです。
せっかく作るのなら、もっと良いものにして欲しい、そう言う願いも込めてこのエントリーを書きます。
前回 Rust と比較してみましたが、今回はその golang 版です。
golang は言語のシンプルさを追求していて、言語的な便利機能が片っ端からありません。
それは覚えることが少ないことを意味します。学習コストを低く抑える事を根本的なポリシーにしている言語です。
裏を返せば完全に人を小馬鹿にしているんですが、その分ドキュメントなどがかなり充実しています。
構文的には、ほぼ C と同じです。そらそうですね、C言語の開発者のケン・トンプソンが関わっていますから。
一方 Nim は Python に強い影響を受けていて文法は Python そっくりです。そのためスッキリ書けて非常に見やすいです。Python をブラッシュアップして、秘伝の悪魔のタレをかけたような感じです。
面倒くさがり屋たちが作っている言語で、面倒なことを片っ端からシンプルに出来るようにすることをポリシーにしています。
面倒くさいことを簡単にするために、覚えることはかなり増えます。覚えれば覚えるほどやる事が簡単になっていくとも言えます。
ですが、面倒くさがり屋たちが作っているが故にドキュメントが壊滅的に存在しません。
「コードに付いてるテストコードでも読んでりゃ解るだろ、そんなの。」ってなもんです。「人は賢いんだ」と信頼しきっています。
golang はそのシンプルさ故、学んだところで特に新しい発見はありません。
Go is a language stuck in the 70's. (Go言語は 1970年代でぶっ止まった言語だわ)
と揶揄されている程です。
その場しのぎでしょうがないから、と言うあきらめムードで使うのならまぁ良いのでしょうが、決して素晴らしい言語だと思って使わない方が良いです。
golang をやっていると言語的なセンスが現代からズレる事をきちんと認識した上で使いましょう。
ではさっそく golang のどこらあたりがイケてないのかを中心に Nim のどこらあたりがイケているのかを書いていきます。
Exception がない
血反吐を吐くレベルで致命傷です。「お?C かな?」と思うような発狂処理を書いて楽しむことができます。
package main import ( "fmt" "errors" ) func main() { if err := genError(); err != nil { fmt.Println(err) } } func genError() error { return errors.New("ERROR") }
返り値を受け取って null じゃなかったら的な。地獄のエラーハンドリングを楽しめますよ。良かったですね。
errors.New なんて気取っちゃったもん使っていますが「int か string で良いじゃん!」と思いますよね。
Exception みたいに複数のエラーハンドリングしたけりゃこうですよ。
package main import ( "fmt" ) type ERROR int const ( ERROR_NONE ERROR = iota ERROR_AAA ERROR_BBB ) func main() { err := genError() if err != ERROR_NONE { switch err { case ERROR_AAA: fmt.Println("ERROR: AAA") case ERROR_BBB: fmt.Println("ERROR: BBB") default: fmt.Println("Something wrong"); } } } func genError() ERROR { return ERROR_AAA }
列挙型使って、switch 文。いやーー C ですなぁー。これに goto とか使っちゃったりしてますます C 感出しちゃうともっとおしゃれだと思うので是非やってみてください!
Nim はこうです。
type ExceptionAAA = object of Exception ExceptionBBB = object of Exception proc genException(s: string) = if s == "a": raise newException(ExceptionAAA, "AAA") else: raise newException(ExceptionBBB, "BBB") try: genException("a") except ExceptionAAA: echo "ERROR: AAA" except: # 残り全てのException を捕まえる echo "Something wrong" finally: # finally も当然ある echo "FINALLY"
まぁ普通こうですよね。golang がおかしいんです。
ついでに Nim の宣伝も兼ねて Exception のパターンをちょっとだけ書いておきます。
# ExceptionAAA をキャッチしつつそのままそいつを throw try: genException("a") except ExceptionAAA: echo "ERROR: AAA" raise # ExceptionBBB がスローされてきたら catch していないのでそのまま throw される try: genException("b") except ExceptionAAA: echo "ERROR: AAA" try: genException("b") except ExceptionAAA: echo "ERROR: AAA" except: # 残り全てのException を捕まえてそのまま throw echo "Something wrong" raise # Exception のメッセージを取り出したい場合 try: genException("a") except ExceptionAAA as e: echo "ERROR: " & e.msg # こうやっても取れるけどなんだか長い try: genException("a") except: var e = getCurrentException() echo "ERROR: " & e.msg var msg = getCurrentExceptionMsg() echo "ERROR: " & msg
ま、Exception 周りで困ることはなんもないです。凄くシンプルに書けますよ。
main と package を毎度書かされ、Printf も長い
package main import "fmt" func main() { fmt.Println("Hey Golang") }
Java よりはマシですが非常に鬱陶しい感じではあります。
fmt. をイチイチ書かなきゃならんのが非常に面倒です。
ここだけ見ると C の方がマシに見えます。
#include <stdio.h> int main() { printf("Hey C\n"); }
こうあれよ!と言う形、それは Nim にあります。
echo "Hey Nim"
ガミガミうるさく言われる
使っていない変数があるだけで文句を言われコンパイルできません。
使っていない import も同じく文句を言われコンパイルできません。
開発中は、このくだらない縛りのお陰でコメントアウトをしまくる羽目になり超絶イライラさせてくれます。
これだけでこいつを投げ捨てる価値が十分にあります。
「なんのメリットがあるんだよこれ!せめて warning にしろよ!」と誰しも思っていますが golang 開発陣は無視し続けています。
Nim はコンパイル時に Hint として出てくるだけです。こんなもんその程度で良いんです。
書き方もイチイチうるさいです。
この書き方は、コンパイルエラーになります。
if i == 1 { fmt.Println("HOGE") } else if i == 2 { fmt.Println("FUGA") }
こう書かされます。
if i == 1 { fmt.Println("HOGE") } else if i == 2 { fmt.Println("FUGA") }
そこに選択の自由はありません。
コーディング規約が必要無くなるメリットよりもコーディングに不愉快さを持ち込むこう言った思考には昔から賛同しかねます。
そもそもこの書き方嫌いですしね。
条件を削りたい、足したい、順序を入れ替えたい、となった時に鬱陶しいんですわ、この書き方。
先頭と2番目をひっくり返したい時とか「ギィイィィーーーー!」となって結局改行を入れて入れ替えて、それから改行を潰す羽目になります。
ただ単に行を潰したい割にはデメリット多すぎですって、この書き方は。
Nim の場合はもちろん書き方に変な縛りはありませんし、随分と綺麗に書けます。
if i == 1: echo "HOGE" elif i == 2: echo "FUGA"
クリーンでしょ。書きやすいわ見やすいわでノンストレスです。
if i == 1: echo "HOGE" elif i == 2: echo "FUGA"
こんな感じに行を潰すこともできます。パーフェクトです。
immutable 変数がない
何故か無いです。Nim は当然あります。
let n = 10 # immutable var m = 10 # mutable
演算子のオーバーロードがない
あいたたたったたたた。これが無いばかりにクソみたいなコードを書くことになります。
下は構造体を加算するコードです。
package main import ( "fmt" ) type Point struct { x, y int; } func Add(left Point, right Point) (Point) { return Point{ left.x + right.x, left.y + right.y } } func main() { var p1 = Point{ 10, 20 } var p2 = Point{ 30, 40 } var p3 = Point{ 50, 60 } var p4 = Add(Add(p1, p2), p3) // <- zZZzzZzZzzZzzz # X: 90, Y: 120 fmt.Printf("X: %d, Y: %d\n", p4.x, p4.y) }
3つ足すだけでこんなダッサい見た目になります。
他の演算も混じってしまうともう Add(Sub(Add(Sub ともうワケワカメですよ。
type Point = ref object x: int y: int proc `+`(left, right: Point): Point = Point(x: left.x + right.x, y: left.y + right.y) var p1 = Point(x: 10, y: 20) var p2 = Point(x: 30, y: 40) var p3 = Point(x: 50, y: 60) var p4 = p1 + p2 + p3 # <- パーフェクト # X: 90, Y: 120 echo "X: ", p4.x, ", Y: ", p4.y
「Python の生産性を」とか言っている割になんでこんな大事なものを欠落させてくるのかさっぱり意味がわからないです。
golang の FAQ によると
らしいですが、言語なんて「あれば便利」の塊であってこの言い訳をするならもう C だけやってりゃ良いって話になりません?
根底の考え方がおかしいんですわ。
そのシンプルさって、書き手のシンプルさではなくて、コンパイラを作る側として面倒な処理を避けてシンプルにしたいって話でしょうね。
イテレーターがない
ため息しか出ません。痛々しすぎます。いつの言語なんすかマジで。
Nim には当たり前のようにあります。
iterator ite(init: int): int = var res = init while res <= 30: yield res res += 10 # 10 20 30 for i in ite(10): echo i
ジェネリクスがない
はい、致命傷です。ご臨終です。同じようなコードを型毎にガンガン書けますよ。良かったですね。
package main import "fmt" func Add(a, b interface{}) interface{} { switch a.(type) { case int: return a.(int) + b.(int) case float64: return a.(float64) + b.(float64) default: return nil } } func main() { fmt.Println(Add(1, 2)) // 3 fmt.Printf("%f\n", Add(1.0, 2.0)) // 3.000000 }
Nim には当然あるので同じようなコードはガンガン書けません。悲しいですね。
proc add[T](v1, v2: T): T = return v1 + v2 echo add(1, 2) # 3 echo add(1.0, 2.0) # 3.0
C の関数を使おうとすると死ねる
さぁ C の関数を持ってくるぞ!となったらこれがまぁー酷いです。
package main /* #include <stdio.h> #include <stdlib.h> */ import "C" import "unsafe" func main() { str := C.CString("Blah") C.puts(str) C.free(unsafe.Pointer(str)) }
何やらガチャガチャ書かされます。
コメントの部分も必須要素ですからね。include をコメントで書いてやらないといけないんです。コメントに大事なものを書くとか無いでしょ。checkconfig だの insserv 用のスクリプトだの shebang だのはスクリプトを外側から読むからしょうがないにしろ、言語の実装としてこうなったらいかんでしょ。どうにかならんかったんかと。
値も C 用に変換させられます。
そして、悪夢の1行もありますね。
C.free(unsafe.Pointer(str))
はい来た。フリー。golang 開発者たちの責任範囲から無事フリーされ、全責任が書いた本人に降り注いできます。
ウザさ爆発です。
Nim ならこうです。
proc puts*(s: cstring) {.header: "<stdio.h>", importc: "puts".} let str = "Blah" puts str
free も変換もいらないです。
比べ物になんないですね。
Rust 版を見てもらった人は何故 puts? と思ったかもしれません。あっちは printf でしたからね。
可変引数の渡し方がさっぱりわからないのと調べるのが途中でバカバカしくなったので puts にしてます。
可変引数の渡し方がさっぱりわからないのと調べるのが途中でバカバカしくなったので puts にしてます。
継承がない?
golang には継承がない!とか書いていたりしますが、あります。
気持ち悪い書き方が出来てとっちらかっててシンプルから程遠いところにいるとびっきりカオスなやつが。
interface がどこで使われているのか把握するのも一苦労で、一体何がどうなっているのやらわからなく出来る素敵なやつです。
おとなしく extends、impliments と書かせろ、と思う事請け合いの悲壮感漂う代物です。
なんか、こっち系のシンプル屋が大っ嫌いであろう多重継承も不思議と出来ます。
詳しくやるとやたら長くなるので別の記事で書いています。
実行速度は大して早くない、メモリ使用量・ファイルサイズはデカい
いまいちパッとしません。
コンパイル後のファイルサイズは話にならないレベルで比べ物になりませんし。
コンパイル後のファイルサイズは話にならないレベルで比べ物になりませんし。
項目 | Nim | Go |
---|---|---|
実行速度 | 0.33s | 0.59s |
ファイルサイズ | 82K | 2.2M |
メモリ | 356K | 728K |
こんな感じです。
結局どうなの golang
頭が固くて古臭い、今の言語をまるで知らない人が作ったような言語だと思います。
そこは世界中の golang を批判している人々が抱いている嫌悪感と全く同じものを感じます。
数々発展してきた言語の考え方を丸ごと打ち捨て「シンプル」という旗印を掲げているものの、そのシンプルさは「C言語ってシンプルだろぉ!?」と押し付けてくるような強引さに非常によく似ていると思います。
言語機能が欠損している = シンプル
この考え方は非常によろしくないです。
結局は、これまたよく言われるように Google が推進しているから有名になっているだけ、です。
Kotlin に全てを奪われると予想
今は Android の開発言語としての位置づけである Kotlin ですがそのうちサーバサイドでも盛んに使われるようになっていきます。
既に Ktor などの Webフレームワークがあったりしますし。
そうなってくると、アプリ側とサーバ側の言語を統一する事が開発現場や採用の観点から重要視されていきます。
Go Mobile なんて中途半端でよくわからないものは一切流行らないので、この流れを止めることは出来ません。
golang があるにも関わらず Android の開発言語として他社の Kotlin を正式採用するというのは Google 内部に golang は微妙だと思っている人たちが少なからずいると言う証拠でしょう。
言語として
こんな感じですからね。
え?Nim はどうなのですって?
そりゃーこうですよ。
kotlin <<<<<(膜の向こうの別の宇宙)<<<<< Nim
ですが、一切流行っていませんし流行る気配も・・・。別の宇宙に行っちゃってるもんだから多くの人類に見つけてもらえないんでしょう。
まぁ、そこが良いんですけどね。
そもそも全く流行っておらず、全くの無名なので今より下に行くことがなく、上に行くしか無いですから(馬鹿みたいにポジティブ)。
モノは良いんですから。先行投資だと思って習得しておくのは決して間違いではありません。
そして、言語センスとして良いエッセンスを吸収するという意味でも触っておく価値があると思います。
「怠け者とはこうあるべきだ!」と言うとても大事な事を Nim は我々に教えてくれますよ。
神々よ Plan 9 に真剣に取り組んでくれ
言語としての考え方が改めてガッツリ変わらない限り golang は居場所が良くわからない妙ちきりんな存在としてフェードアウトして行くと思います。
0 件のコメント:
コメントを投稿