次世代言語9[Haskell Rust Kotlin TypeScript Dart]
■ このスレッドは過去ログ倉庫に格納されています
スレタイ以外の言語もok
前スレ
次世代言語Part8[Haskell Rust Kotlin TypeScript]
http://mevius.5ch.net/test/read.cgi/tech/1512137301/ >>114
それはもう、今の定義されたinterfaceで充分だとなってしまうのでは? せめてパターンマッチくらいは入らんかなあ
型判定のためにifをダラダラ並べるようなコードなんて誰も嬉しく無いよ
:=もあるんだし構文糖衣まで全て拒否してる訳でも無いだろうに >>118
まぁ例えばだから。もっとぴったり来る例を示せればよかったんだけどね。
関数のオーバーロードも合わせて欲しいな。関数名考えるのがしんどい >>110
ドキュメントが常に最新の状態であることを静的に
保証する方法がない限りは静的型付けの型情報の方が信頼できる
腐ったドキュメントほど有害なものはない
腐らせるヤツが悪いとか言われそうだが
腐らせるのは自分ではなく同じチーム内の誰かだ
他人よりコンパイラの方が信頼できる interface{}を他の言語のobjectみたいなほんとに雑な受け方と一緒にしないでくれよ…。
実際に書いたら、結構使う場面が限られて来ることもわかるだろ…。
>>121
オーバーロードの禁止ははまあ必要悪だと思う。
型同士に階層が無いので、2種類のinterfaceを受ける関数があったとき、その2つともを実装している型に対して関数が定まらんのでは? >>125
してねえよ
コンパイル時の型制約を足したいって話で、機能的にinterface{}への switch t.(type) で十分なのは承知の上
ifが並ぶっていってる奴はたぶんswitchで型判定できるの知らない気がする 仮にGoにジェネリクスを実装するとしたらどこまで必要になるんだろ
共変性と反変性は必要?
部分適用は必要?
C++のメンバ型みたいなのは必要? >>127
そんな難しいのはいらねーから宣言的に書かせろ >>125
object型と同じだと思ってたわ。具体的な違いとメリットを頼む。_φ(・_・ >>129
渡されたものをどう解釈するかの余地が他の言語と結構違う
たとえば、
type xxx struct {}
func (x xxx) foo(){}
func (x xxx) bar(){}
type Ixxx interface {
foo()
}
func (ix Ixxx) bar(){}
があったときに、interface{}で受けたものをアサーションでxxxとすると、xxxのbarが、
アサーションでIxxxとすると、Ixxxのbarが呼ばれる。
あくまで、すべての構造体はinterface{}を満たしているだけで、実際には型を持ってるし、
interface{}とIxxx{}も満たす範囲が違うだけで上位下位ではないし、構造体の型とも違うのでレシーバは別になる。
interface{}から派生したものではないって感じ。 もしかしてswitchに型チェック機能追加したやつが戦犯かな
ただのVisitorパターンならジェネリクス対応は難しくなかった 型チェックでswitchとジェネリクスは全く関係ない。
オーバーロードと同じく、何として処理するかと、その型が何か、に関して曖昧性を排除してるから。
暗黙のキャストも無いでしょ。
戦犯呼ばわりはどうかと思う。他の言語に毒されすぎ。 Goにオーバーロード無いの批判される事あるけど
HaskellやRustだって型クラスやトレイトを使わないとオーバーロードできないし
TypeScriptも型が多重定義できるだけで実体は一つだし
むしろ最近の言語はC++みたいな単純なオーバーロード付けないのがトレンドな気がする >>124
ドキュメントよりコンパイラのが信用できるかも知れんが
それ以上にテストコードの実際の動作のが信用できるよ。
c++まともに開発に使ってた奴ならどれほどコンパイラだよりが危ういかわかると思うけどね。 コンパイラが頼れないからC++から離脱したがってるわかで…… >>133
むしろオーバーロードと型推論を共存させたいというのが型クラスの最初の動機だったのでは >>135
そりゃテストコードが全てのコードに対して書かれていたらの話で
実際にはテストカバレッジ100%なんてあまり現実的な数値じゃない
GUIの場合はテストを書くこと自体がなかなか難しいし、他にも仕様が変わりやすいような
部分は変わるたびにテストも書き直すんじゃ、コストが割に合わないこともある
それらを考慮して、あえてテストを書かないという選択をすることも充分あり得る
静的型付けならテストが書かれていない部分でも型情報からある程度ならチェックが出来る
動的型付けはテストがなければ何もチェックできない
テストを書かない奴はバカみたいな言い分はあまり好きじゃない
テストカバレッジ100%を目指す奴のほうがよっぽどバカだと思う C++の型安全とHaskellの型安全って随分違うでしょ
理論がしっかりしてて型システムが豊かな方が型安全で提供される品質は高い
Haskellは「コンパイルが通れば大体想定通りに動く」って言われる程度には型を信じれるよ
これが行き過ぎるとIdrisやCoqみたいに「実行できれば仕様を満たしている」みたいな開発もできる
ハードル高いし実用できるほど簡単じゃないからまだ何個かブレークスルーが要るがね >>130
残念ながら他言語のobject型とinterface{}の違いがこの説明ではよくわからん。
あんさんは他の言語のobject型を雑な受け方と評したんだぜ。具体的にこの説明では、
なるほど他の言語のobject型で値を受け取るのは雑な受け方だった。って納得しない。
どのへんが雑じゃなくなってるわけ? >>138
qiitaの記事でだいたいカバレッジが85%位が理想値でそれを超えるとしんどくなるだけで意味ないってのは見たな。 >>135
C++のコンパイラに頼るのは危ないってのはテンプレートがダックタイピングだからじゃないの?
だとしたら、それは単にC++のテンプレートの仕様がクソってだけの話で
C++のコンパイラがクソって言うのは筋違いだと思うんだけど…
それとも他に理由があるの? 書いた後で思ったけど、
C++のテンプレートってダックタイピングって言われてるけど
きちんとコンパイルエラーになったような…?
使ってたの3年以上前だから忘れた。どうだったっけ? たぶん135は、コンパイラがバグってて出力される機械語が怪しいという話をしてる
別にC++に限った話ではないんだけど昔は結構多かった >>140
うーん。なんにでもなれるスーパークラスで受けてるんじゃなくて、何もかもを満たすインターフェイスで受けてる。
クラスというか構造体同士に階層も無いし、
インターフェイス同士にも無いから。
だから、他の言語でObjectからキャストし直すときに、キャスト先の階層構造を考えなくてもいいし、
むしろどうキャストするか(何がほしいか)で、それに合わせたレシーバを呼んだりできる。 >>139
なのになぜライブラリのバグがちょいちょい発覚するの? 普通は型の階層を利用したキャストの方が丁寧で
Goのような要件さえ満たせばなんでもキャストできる方が雑なんだけどな
雑なGoに丁寧なジェネリクスは似合わないって話の方がしっくりくる 動的型は丁寧なコードも雑なコードも書けるよ
静的型のキャストは雑なコードだけを集めて濃縮したような存在 型の階層ってのからまず脱却した方が良いところだと思うけどね。
型の階層の横紙破りとしてインターフェイスを作ってさらにインターフェイスも階層を持つとか、goやり始めてから悪手な気がしてきた。
他の言語もmixinとかtraitなんかで色々やってるけど、そういう方向で対応すべきもんなんだと思うよ。俺は。
rubyのようにobjectの親を作る羽目になったり、どのみち破綻する。
型の継承による、と言うが、型の継承に頼ったキャストとしか言いようが無いんでは? >>145
>だから、他の言語でObjectからキャストし直すときに、キャスト先の階層構造を考えなくてもいいし、
どういうこと?Object型は大抵すべてのインスタンスの親のはずでは?
一度Object型の変数に突っ込んだなら、それってもう実質、動的言語的扱いになるから人間側が元の型を意識しなきゃいけない。
これはGoでもおんなじでしょ?
あと以下は正直どうでもいい話なんだけど敢えて突っ込む。
Goのインターフェースは階層構造を持たないって言ってるけど
も結局用語の違いってだけで実質階層構造みたいなのはあるでしょ。
Io.ReadWriter は io.Writerを内包している
io.Writerはからインターフェースを内包している
Io.ReadWriter => io.Writer => interface{}
他の言語は階層構造を明示しているけどGoの場合はそれがコンパイラによって自動化されているってだけでは?
もちろん自動化されているってのはありがたいけどね。 >>143
静的ダックタイピングって言われてる
本質は変わらない >>148
動的型のキャストと静的型のキャストに違いがあるとは思えないけどなぁ。
俺の考え方はこう。
動的型: 人間側で型の追跡を頑張る
静的型: コンバイラ側に型の追跡を任せる。ただしobject型とかに渡すことで人間側で頑張ることもできる。
動的型は基本雑なコードだらけ。人間側が型を決め打ちしてメソッドを実行しないとやってられない。
だって毎回instanceof とかで型をチェックしてからメソッドの実行とかしてないでしょ? >>152
説明されてわかるような奴が>>148を書くと思うか? >>150
そんなことないよ。例えばtoStringみたいな、親から生えてるメソッドは、objectのまま呼べて、しかもインスタンスのメソッドが呼べるでしょ。
goはそうはなってないの。インターフェイスをレシーバとする関数が呼ばれる。
内包してないよ。
ReaderはReadを
WriterはWriteを
ReaderWriterはReadとWriteを実装しているインターフェイスなだけ。別のインターフェイス。そこに上位下位は無い。
階層構造が暗黙に決まってるんではなくて、そもそも階層構造を持ってない。 なんでもできる c++ で書くなら
なんのメンバーも持たない class interface の直接の
派生型として色んなインタフェースがあるようなもんか
COM に似てるな、というか COM のインタフェースの概念の焼き直しか。 ダックタイピングとnominalな階層型の違いを言葉を変えて繰り返しているだけで
問題のinterface{}がobjectより良いという説明にはなってないな >>138
別に全部のコードにテスト書けとは思わんが
それでもそこまで引数の型がどうなのか気になるインターフェイスなら
テストコード書けよ。
てかそこまで作業が圧迫してるなら型をガッチガチにやる言語のが
調整する手間考えた場合割に合わんだろ。 >>157
どの程度なら「気になる」のかってところに認識の違いがありそうだな
静的型派の人間は全てコードの型情報が気になっちゃうんじゃない?
少なくとも俺は全ての引数の型が気になってしまうタイプの人間だよ >>152
動的型のコードは二種類に分けられる
静的型で丁寧に書いてから型を省略したようなコードと
静的型で雑に書いてから型を省略したようなコードだ 「階層を持つから安全にキャストできる」と「安全にキャストできるから階層を持つ」がごっちゃになってる人がいる >>158
まあ極論すれば感覚的な話だしね。
感覚として型を気にして助かることなんて 5 % くらいじゃないかと思ってる。
対してテストがある場合は 40~50%くらい助かる。
準備するコストとして型が 10~20 としたらテストは 30~40 といった印象。
なんで個人的にはそこまで型を整備するよりかはテストに時間使った方がいいと考えてる。
まあ抽象論一発で済めば嬉しいって気持ちはわかるんだが
実際そうはならんからね。。 >>156
端的に言えば、スーパークラス(と言う概念もないが)にキャストしてして渡してない、as-isで渡してると言うところが違うし大きい。
良いとも言ってないぞ。
違うし混同するなと言ってる。
Objectに相当するものが無いので、良いも何も比較対象ではない。 スーパークラスにキャストねえ。
どの言語でもその場合は as-is で渡るだろう 暗黙的にでも、ね。
Objectで受ける、Ienumerableで受けるを含めて。 as-isで渡るは確かに語弊があったな。
別の型のオブジェクトやインターフェイスとして渡されてるんじゃなくて、って感じ。 >>162
>>125でobjectを雑と評したからには当然interface{}の方が良いという主張と思ってたんだが
実際の詳細は別にしてあなたの説明では聞けば聞くほど同じとしか思えない
俺じゃないが>>155なんかCOM的な構造で代替可能という理解をしてるし とはいえ言いたいことはわかる
オブジェクトに似ているがオブジェクトを渡しているわけではない、
オブジェクトとそれの持つインタフェースは1対多
COM のインタフェースや多重継承を用いた場合のC++に似ている
特に前者とはほぼ完全に同じものだ
インタフェース抽象って奴だね
この場合実行モデルとしてはインタフェースに階層関係は要らなくなる
複数のインタフェースを持つことから(派生による差分宣言、差分実装ではなく)
ミックスインが基本となるから。 as-is型に実装を合わせるテンプレート
as-is実装に型を合わせるキャスト
これが次世代の争い
動的型は次世代ではないから政治的中立 >>166
同じではないでしょ。
COM的な構造で代替可能ってのは、>>166自身は理解してるの?理解してたらそのレスにはならんと思うけど。
そもそもが思い込みで人の発言に「良い」を勝手に補完してなんでそんなにしつこく食いついてくるかわからん。
理解が足りなくて同じだとしか思えないなら開き直らないでほしいわ。 >>154
だから階層構造がないのはわかってるつーの。実際的な違いがないっていってるの。
実質Object型 とinterface{} はおんなじ扱いにしかならない。
Object型にはtoStringがあるけどinterface{}にはない? 別にそんなのはどうでもいい話。
interface{} に値を突っ込むと人間側が型を意識する必要がある。
動的言語的な扱いになっちゃう。
この点においてObject側と一緒だよね。
ここが最大の肝であり、「Object型でうけるのは雑」っていってるのはこの部分に差があると期待して質問したのに、
そこに関しては違いを見出していない。
なら雑な理由って何よ。 今気が付いたが>>145の言ってることは根本的に間違ってる
>>130みたいなインターフェイスのレシーバはそもそもコンパイル通らない
つまりどの型にキャストしても同じレシーバが呼ばれることが保証されてる
そこがGoの型は階層を持たないという根拠になってたはず
エアプは黙ってろ >>169
IUnknownが便利に使われてるのと
QueryInterfaceの実装次第でメンバーに飛ばすこともできるのが似てるって話だろ
COMは実装側が応答する型(GUID)を決めないといけなくてダックタイピングにはならんから
俺は必ずしも似てるとは言わんけど、あなたの説明はそう思われてもしょうがないってことだ classの多重継承ができる言語ならinterfaceはclassの構文糖ということにできた
多重継承を制限したことでinterfaceとclassの互換性が非自明になった >>171
これは例が悪かったか。
スマホで書いたからすまん。
ある型にアサーションした場合、アサーション先の型のレシーバが呼ばれるよ。
もとのレシーバではない。 >>170
おんなじ扱いをすれば同じになるだろうな。
扱い方の余地の問題なんだが。
人間側が型を意識する必要がある、この点に於いてObjectと同じと言うのは雑すぎる。
動的言語的扱い方と言うか、jsonのUnmarshalなんか見た方が多分わかりやすいと思う。俺が言ってることは。 interface{}で受ける関数を呼ぶときは、
とりあえず、スーパークラスのObjectに(暗黙的に)キャストして渡してるのではなくて、あるインターフェイスを実装している型として渡してる。
全クラスがIfooをimplementsしている状態で、Ifooを受けているだけ。
そこにキャストは発生してないし、だから、キャストではなくアサーションで型を判定するだけで(キャスト無しで)中身の型が分かる。
その時に、もとの構造体ではなく、あるインターフェイスとしてアサーションする事ももちろんできる。
そこだけでも伝わってほしい。 しかし、また「エアプ」かw
好きなんだな、その言葉。 キャストは雑
アサーションは丁寧
という説が伝わってきた >>175
それって結局reflectバッケージを見ろってこと?
>>177
型キャストが雑ってこと?
型アサーションだと型が合わないとerrorを返すから雑じゃないってこと? 雑なほうがいいんだよ。that's rightって言うだろ? >>180
アサーションが丁寧というのは語弊があるが、インターフェイスからのアサーションはそもそも本来の型自体も持ってるのでキャストしているわけではなく、assert、言明し直してるだけで、別の型として一度も扱わない。 >>174
アサーションでもレシーバが変わることはない
自分で試したことないから分からないんだろ
>>177のキャスト無しで渡してるってのも間違いで実際はキャストされてる
キャスト無しで渡してたらそれはジェネリクスだ
たぶん>>177はポインタや参照を理解してなくてキャストの意味をはき違えてる
objectにキャストしたら静的オブジェクトが動的オブジェクトに変換されると思い込んでるようにしか見えない >>183
あることあるから、レシーバが変わる事知ってるんだよ。
そうじゃない。履き違えてないよ。
ジェネリクスはもっとちがう。コンパイル時に関数自体が型ごとに分かれるのが俺が言うジェネリクスとオーバーロード。
オブジェクト指向脳でわけわからん事言わないで。 >>184
が、言いたいことを整理すると
Go言語のinterface{}は他言語のObject型とは違う。
なぜならGo言語のinterface{}型は内部的には型情報を保持しており
reflectバッケージを使うことでいつでも元の型情報を取得できるから
ってことでOK?
これって逆に言うと他言語のObject型は内部的に元の型情報を保持しないの? 本来のデータポインタはそのままで実行時型情報をペアにしてinterface{}(fat pointer)にしているのを
キャストしているしていない言い張ってるだけかな。まあ言葉はどっちでもいいが
ちなJavaタイプのnominalなinterfaceや多重継承はデータポインタに特定のオフセットを加減算する(ポインタの値が変わる)
場合がほとんどだが、fat pointer方式の実装も無いわけではない >>185
いや保持してるよ
RTTIってやつだね エアプ呼ばわりされて過剰反応するのが真のエアプ
エアプでないことを示すのが普通の人 >>185
内部的に持ってるが、クラス構造が階層型であるが故にObject型という型で扱われた上で、サブクラスにダウンキャストするじゃん?で、またアップキャストするかもしれん。
だからジェネリクスやオーバーロードだと共変なのか反変なのか、あるいは非変なのかが問題になるし、Javaなんかはジェネリクスは非変だけど、配列は共変みたいな事になってるし、c#なんかだと最近変性注釈できるようになったり、まだゴタゴタしてる。
ちなみに、interfaceへのアサーションはreflectとは違って、interface自体が型を持ってるので、reflectで型を判定したりメソッド呼ぶのとは結構な差がある。
古いけどこのへんか。
https://research.swtch.com/interfaces エアプなんか使ったって、レッテル貼るだけで議論ができないようにしか見えないんだからやめときなって それが楽しいんだろ、いつもその言葉使うところ見たら。 例えば
func ToString(any interface{}) string {
if v, ok := any.(Stringer); ok {
return v.String()
}
switch v := any.(type) {
case int:
return strconv.Itoa(v)
case float:
return strconv.Ftoa(v, 'g', -1)
}
return "???"
}
上記コードはこうできるようにして欲しい
func ToString(any (Stringer | int | float)) string {
if v, ok := any.(Stringer); ok {
return v.String()
}
switch v := any.(type) {
case int:
return strconv.Itoa(v)
case float:
return strconv.Ftoa(v, 'g', -1)
}
}
引数にinterface{} があるのはやっぱりJavaとかで引数にObject型が来るのと同義だと思うわ。 結局Objectの方がinterface{}より保証されてるものが多いから、雑なのはinterface{}の方じゃーん >>105
これ最高に型無しクソペチパー指向的レス >>197
保証されてるものが多いんじゃないよ。
保証されるべきでない関連性を持ってないものも、関連性を持っているかのごとく扱われるんだよ。 自分が知らないものをたったひとつソースから「言い間違えなのか?」と言うのはどうかしてると思うわ。 >>195
ToStringなんて関数をinterface{}で受けて中で適当に処理するってこと自体だと思う。
そんな事するぐらいなら、使いたいintとfloatを名前つけてちゃんと型定義して、Stringer実装するほうがまともでは?
ライブラリならまだわかるが、ユーザコードでinterface{}を使うのはもっと「interface{}でなければいけない時」であって、基本的にはなんでも受け取りたいから使うための型ではない。
普通のオブジェクト指向言語でもそうだろ。
後半のコード例に至ってはコンパイル時に検出したいだけだろ。
オーバーロードさせろってんならまだわかるが。
コンパイル後に消えるようなもの書いて喜ぶ事こそ馬鹿らしいわ。 >>201
>後半のコード例に至ってはコンパイル時に検出したいだけだろ。
それこそキモだろ。静的言語を使う理由って。
これが嫌なら動的言語使ってなよPHPとか >>201
>ユーザコードでinterface{}を使うのはもっと「interface{}でなければいけない時」
現状のGoでそういう理由でinterface{}を使ってる状況ってどんだけあるんだよ。
それじゃすまないからジェネリクスを欲しがってるんでしょうが。 >>202
ホントだな。これは俺が少数派らしい。
高飛車に言ってすまん。 >>203
キモではないよね。
それは単なる横着のコンパイラへの責任転嫁であって。
void*みたいな無茶苦茶な型があるのも静的言語だが、別に型チェックしてほしくてコンパイルしてるわけじゃないぞ。 >>204
結構あると思うけど。
それで済むから、頑なに「未だ早い」と本家が言い続けてるんでしょ。
済まないならもっと早く導入されてるわ。
そんなに変化ねえじゃんと思いがちだが、ホントに要るなって機能はちゃんと入ってきてるよ。ライブラリの出力しかり、ベンダリングしかり、次はモジュール予定されてたり。 早くPHP歴4000年秘伝のソースにウンコを継ぎ足す作業に戻れよ
工数の無駄だぞ このスレ見てたら俺はC++とPythonでいいやって思えてくる こんなスレに影響されんなよ……
因みに俺はCとPythonとFortranとMathematicaでいいと思う 非変、はScalaあたりから来てるのかな。記憶が曖昧。 CとPythonの二刀流ずるい
C++むずい
だからJavaとかGoとかの支持率は下がらない >>207
あとCみたいな旧世代な言語を静的言語代表にされても。
あと横着はプログラマの美徳だよ。
>>208
現在進行形で議論中だよ。安易に入れたくないだけで必要性は明らかだろ。
https://github.com/golang/go/issues/15292
というか他のジェネリクスがある言語を使ってるとわかると思うんだけどな。このイライラ感。
まぁ関数のインターフェースにinterface{}型があっても気にしない人間もいるという事実があることは勉強になったわ。
そういう人間もいるんだ。 >>199は自爆というかむしろダックタイピングの方だよね? 反変共変とかすぐに数学用語を取り込んで違う意味にする >>214を斜め読みしたけど、既存のinterface{}なやつと互換を取るためJavaのgenerics同様にするか
それとは別に問題を捨て去るためD言語やMLみたいな名前空間単位のやつを入れるかで議論してるな
genericsなんて大物は後から入れてもJavaのようにしかならんとは思っていたが
(失礼ながら)goのような保守的な言語に今までのスタイルを捨てさせるような変更を入れられるのかは気になった >>217
GoBlogでGo2はGo1と下位互換性を保つと宣言してるから破壊的変更をせずに導入するだろうね。
どうやるか全く想像がつかない >>161
やっぱり認識の違いが激しいな。これじゃ話が合わんわけだわ
おれの感覚を書くと型情報を書くことで助かることは10~20%くらい
対してテストがある場合は50~60%(約3.5倍)くらい
準備するコストとして型が10~20ならテストは60~70(約4.25倍)の印象
さらに、後からコードを読むときの理解するまでにかかる時間が
静的型が10~20なら動的型は30~40(約2.25倍)の印象。
そして、俺の場合はコードは書くことより読むことの方が多いと思っているので
読むときにかかるコストの違いに良し悪しの重点を置く傾向がある。
というわけで、俺の感覚ではもちろん静的型に軍配が上がる ■ このスレッドは過去ログ倉庫に格納されています