「安全じゃない」機能が簡単に使えるようになっているのは、どちらかというとJVMの上でScalaが実用言語としてやっていくための必要悪みたいなものであって、Scalaが言語として安全性を重視していないとかいい加減に扱っている、というわけでは無いのだと理解しています
Re: Re: Re: 不満の記録
ヒント: JVM を投げ捨てる
というのは冗談ですが、外部ライブラリを呼びやすいなどという世俗的な理由で型安全性を捨てるのはもったいないなー、と思うんです。
Scala にとっての Java というのは Ruby/OCaml/Haskell にとっての C なわけで、Java ライブラリを呼ぶためには明示的なキャスト程度の泥臭さはあってもいいのに。Java アプレットなんか作ったので、めちゃくちゃ恩恵にあずかってるわけですが。
そもそも抜け道的な機能をユーザからどの程度容易に使えるようにするかは、言語自体の型安全性(あるいは堅牢性)とは、あまり関係ない話ではないかと。たとえば、OCamlのObj.magicだって黒魔術扱いされてはいるものの、ユーザから普通に使えないかというとそういうことは無いわけであって、じゃあOCamlは堅牢ではないとか型安全ではないとかというとそうじゃないだろうと思うわけです。
パターンマッチみたいな言語のコアに黒魔術が残ってるのを気にしてます。
Any#asInstanceOf は (組み込みではあるけど) ただのメソッドなので、なんか許容範囲です。magic とか unsafePerformIO みたいにもっと黒魔術っぽい名前にするとなおよいと思いますが、asInstanceOf でもやばそうな香りはわかりました。
型にマッチするパターンの問題は、「T[A] な型のパターンは T[Any] しか許さない」という感じの制約を入れるだけで簡単に解決できますよね (勘違い?) 。マッチ後に Any を asInstanceOf[A] する必要がありますが、その程度の利便性と型安全性とのトレードオフなら、型安全性を選べばいいのになあ、と思うのでした。
追記
あ、勘違いだ。
Any でいいのは co-variant な場合だけ。contra-variant なら Nothing かな。non-variant なら静的に型チェックできそうだし、実際今でもやってるっぽい? existential type とか structural type とかは知らない。
scala> val f = (x:Int) => x + 1 f: (Int) => Int = <function> scala> (f:(Nothing)=>Any)(42) <console>:6: error: type mismatch; found : Int(42) required: Nothing (f:(Nothing)=>Any)(42) ^ scala> f match { case g:((Nothing)=>Any) => g(42) } warning: there were unchecked warnings; re-run with -unchecked for details res1: Int = 43
ううーん、なぜこれが型チェックを通る?
scala> f match { case g:((Nothing)=>Any) => g("foo") } <console>:6: error: type mismatch; found : java.lang.String("foo") required: Int f match { case g:((Nothing)=>Any) => g("foo") } ^
これは通らないのか。
scala> List(1) match { case l:List[String] => l.head ++ "foo" } <console>:5: warning: match is not exhaustive! missing combination $colon$colon List(1) match { case l:List[String] => l.head ++ "foo" } ^ warning: there were unchecked warnings; re-run with -unchecked for details java.lang.ClassCastException: java.lang.Integer (snip)
こっちは通るのか。混乱してきた。
scala> f match { case g:((Nothing)=>String) => g } warning: there were unchecked warnings; re-run with -unchecked for details res2: (Int) => Int with (Nothing) => String = <function>
そうか、trait なんてものもあったなあ。ここは (Nothing)=>Any というパターンしか書けないようにすれば問題は起きない気はするけど、まだいろいろ見落としてそう。
さらに追記
あああ、non-variant がぜんぜんダメだ。
scala> (Array(1, 2, 3):AnyRef) match { case ary:Array[String] => ary(0) = "foo" } scala.MatchError: [I@ac2d3c (snip)
実用性を落とさずにこれをふさぐのは無理そうだ。ということでやっぱりぼくの勘違いでした。すみません。