Go言語は良い言語です
というイベントがありました。11月14日に、Google渋谷オフィスでありました。
まずはじめに、Googleさんには場所を提供してもらった上にGoogleの中の人にも参加してもらって結果盛り上がったので本当にありがとうございましたとしか。ありがとうございました。
で、次に、Go言語のマスコットキャラクターの名前は一部の賛同を得て勝手に「たわしくん(TAWASHI-KUN)」という事にしておきました。ダメだと思います。でもなんという名前なんでしょう。
今調べると、ちゃんと名前があったので、駄目です。
(http://japan.cnet.com/special/story/0,2000056049,20403390,00.htm)
取りあえずgoコンパイラ(8g)が落とせたかどうかですけどまぁ落とせませんでした。
どういう方向で攻めたかというと
multi return valuesは、その要素数分受け取り側を準備しないといけなくて頭に来た
というのがあって。
これは簡単な話で
func f() (int , int , int) { return 0 , 1 , 2; //return (0 , 1 , 2);と書きたくてしょうがないんですがコレだとダメなので } func main() { first , _ , _ = f(); //2つ目と3つ目は要らないので //first , _ = f();とかしたい気持ちも少しあります。この後の部分全てに一致させるという事がやりたい。 }
コレはなぁということで、multi return valuesということらしいので、10万マルチintを返す関数を作ってみました。
これも簡単な話で
func f() (int , int , int , int ... これが10万個ある) { return 0 , 0 , 0 , 0 ... これが10万個ある } fun main() { f(); }
結果は
8g(51376) malloc: *** mmap(size=53248) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug 8g(51376) malloc: *** mmap(size=53248) failed (error code=12) *** error: can't allocate region *** set a breakpoint in malloc_error_break to debug 8g(51376) malloc: *** mmap(size=53248) failed (error code=12) *** error: can't allocate region ...
という。この他数で攻める戦略はアロケーションをこけさせるのには色々成功して、基本的にコレは無いよなぁ・・・という感じでした。
1 << 453 は OK , 1 << 454はダメ
herumiさんが見つけたもので、
package main import "fmt" func main(){ const v1 = 1 << 463; const v2 = 1 << 464; fmt.Println(v1);//v1はintへのキャスト(というかなんというかが発生してここでダメだと言われる) fmt.Println(v2); }
これが
code2.go:7: stupid shift: 464
code2.go:9: constant 2381705131771844658952024253687413258170012010700203ここで改行
8199303870846751188192899823151552628349788604516295066307994130118526061826166445047808 overflows int
というそれで。
要参照 : go/src/cmd/gc/go.h と go/src/cmd/gc/mparith2.c
stupid stupid
importしたものは使わないとダメ問題
package main import "fmt" func main(){ }
これは
imported and not used: fmt
と言われてしまって巫山戯るなだし、第一「""」で囲むとかっていうのは悲しいですし。。。
fmtとか書かなくて良いです
package main import . "fmt" func main(){ Println("fmt.Printlnとしなくても良い"); }
コレはイエスって感じで、import aliasもかけて
package main import . "fmt" import _ "os" //これは使わなくても良い func main(){ Println("fmt.Printlnとしなくても良い"); }
じゃあ同一関数を含むパッケージのimportに"."を使うとどうなるかも試してみたのですが
package main import . "./pkg1" //Fが存在する import . "./pkg2" //Fが存在する func main() { //pkg1.F(); //pkg2.F(); F(); }
これは
main.go:4: imported and not used: pkg2
main.go:6: F redeclared during import
previous declaration at
別に嵌っていたのは、関数名はアルファベットの大文字からはじまるもののみ外部から見る事が出来るとかで知らねーよっていうか・・・。
returnが酷過ぎる
package main import "fmt" func f() int { if 1 > 0 { return 0; } else { return 1; } } func main(){ fmt.Println(f()); }
コレが
function ends without a return statement
という。まぁ要するにfの最後がreturn文で終わってないのが何事だとかで、いやこの場合分けでそんな事を求められても・・・とか。
package main import "fmt" func f() (ret int) { if 1 > 0 { ret = 0; } else { ret = 1; } return; } func main(){ fmt.Println(f()); }
これだとOKでまぁこうは私は書きたくない気持ちもあるのですが、それは通用しません。
使わない変数があるとダメ
これがコンパイルエラーになる言語は初めて見た気がします。
Googleのコーディング規約か、作者らの何かなのかなとも思います。もし後者だとすると、コンビネータ言語使えばそんな心配も無いのでSKIGoとかを作る方がオススメされるのではないでしょうか。
const v = 0
これは見たままで
const v = 0
だと良くて
const v := 0
だとダメっていう。constって修飾子だから何だろうなぁ・・・。
evalがへちょい
多分セキュリティとかのソレだと思うんですが、evalの中でpackageだとかimportとか出来なくて酷い。
これで何がやりたかったかというと、...(可変長型)のreflect.Typeofが取りたかったというあるあるでevalの中でtypeしてstrong typeなtypedefを作りたかったというあるあるですよね。
かわいい。
Intarfaceへの代入
これは後で追記してみるとして、どうしてしまったんだろうというものがあって、この辺は惨劇が起こる場所だろうと思ってたのですが、まぁコンパイル落とす事とはあんまり関係が無いあたりです。
ダックタイピング
猛烈にどうでも良いのですが
package main import "fmt" type Nakigoe interface { Nakigoe() string; } type Duck struct { } func (Duck) Nakigoe() string { return "Caw"; } type Cat struct { } func (Cat) Nakigoe() string { return "Mew"; } type Dog struct { } func (Dog) Nakigoe() string { return "Bow"; } type Cow struct { } func (Cow) Nakigoe() string { return "Moo"; } func main(){ var duck Duck; var cat Cat; var dog Dog; var cow Cow; array := []Nakigoe{duck,cat,dog,cow}; for _,b := range array { fmt.Println(b.Nakigoe()); } }
良かったですね。
use of .(type) outside type switch
いやそんな事は知りませんけど...
func hoge(i1 I1) (x Type) { switch x = i1.(type) { } p(x); p(typeOf(x)); p(typeOf(x).Name()); return; }
x = (node TYPESW) used as value
この子はvalueには成れないんだなぁ。
末尾最適化は現在実装されていない?
func sum1(now uint64,end uint64,acc uint64) uint64 { if now > end { return acc; } return sum1(now+1,end,acc + now); }
とかは
//result of 8g -S tail_rec.go
0043 (tail_rec.go:18) CALL ,sum1+0(SB)
0044 (tail_rec.go:18) MOVL 24(SP),AX
0045 (tail_rec.go:18) MOVL 28(SP),DX
0046 (tail_rec.go:18) MOVL AX,.noname+24(FP)
0047 (tail_rec.go:18) MOVL DX,.noname+28(FP)
0048 (tail_rec.go:18) RET ,
0049 (tail_rec.go:18) CALL ,runtime.throwreturn+0(SB)
0050 (tail_rec.go:18) RET ,
しかしその割にはfor-loop使って総和求める関数書いた時と実行時間ではそれほど差は無いですね。
結論
全くConcurrencyな部分には触れなかったんですが、あの辺りはどういう実装になっているのかなぁという気がして気になりまくりです。というより普通にそこが楽しいんだと思います。
それと、個人的にはchannelはどうなってるのか知らないのですが、CleanのDynamicsばりの事はあるべきでむしろそうでないと面倒臭いんじゃないかなぁというか・・・。
知ってる環境同士でチャネル繋いで通信する時は、型は自明なので良いでしょうけどもうちょっとでかく成るとpolyな感じにしたくなるんじゃ、無いでしょうかねぇ。
言う分には簡単なんですが、そういう事やらないとLimboの時と何が変わってるのか分からないという感じでした。
Go言語について思う事
templateが欲しいです。それかGenericsが欲しい。
コンパイル時にほぼ何も出来ないというのは・・・証明させてください。(頑張れば何か出来るんですかね)
return文はもうちょっと頭良く成って欲しいです。
エラーメッセージはエラーの場所じゃなくてエラーの内容も出してください。
Intarfaceだけにしちゃったのは英断なのでは無いかなと。Inheritanceは常にSubtypingでは無いです。
結局deferは何なんでしょうか。
とにもかくにもコレからシステムを書く言語として育って行くんだと思います!!
私は好きです。どことなく古風な所が好き。
飲み会
OCamlはコンパイラとWebフレームワークを書く言語。Haskellにはデフォルト値が欲しい。
来年のICFPCに何で出よう問題。
ちゃんと日本語くさい日本語プログラミング言語が欲しい。推理小説とか食わせると型チェックで物語の整合性とかも何故か調べてくれる。実行するとアニメがはじまる。
AgdaとGoはどっちが何なのか。ConceptGoが欲しいです。
寝ます。