ひしだまの変更履歴

ひしだまHPの更新履歴。
主にTRPGリプレイの元ネタ集、プログラミング技術メモと自作ソフト、好きなゲームや音楽です。

Scalaのへんなとこ?

2011-06-12 04:10:20 | PG(Scala)

kaminamiさんの「ここがヘンだよScala言語」がなかなか興味深いネタを扱っていたので、自分も(Scala勉強中なので詳しくはないけれど)ちょっと意見を書きたくなったw


if式の返り値

自分はScala2.8から勉強を始めたので それより前の事は知らないけれど、以前のバージョンでは「if(true) "a"」がUnitのインスタンスである()を返していたらしい。そりゃ僕も変だと思う^^;(個々人の直感から外れた動作は「変」と表現されてしまうのですな)

「if(false) "a"」の戻り値は()になるので、このif式の戻り値の型は、"a"(String)と()(Unit)の共通の型となる。Scala2.8ではAnyになるが、2.7ではUnitになる仕様だったのだろう。
(あるいは、elseが無いということは式というより文という使い方なので、whileとかに倣ってUnitにしていた?)

そういえば、"a"とか123がUnitに変換される仕組みもよく分からないなー。
「def f():Int = "a"」はコンパイルエラーになるが、「def f():Unit = "a"」は通る。StringからUnitへの暗黙変換がどこかにあるのか?


除外インポート

import java.sql.{ _, Array => _}」ってやつ。Arrayだけ除外できる。
Scalaは何か記号を使う箇所では、「_」を駆使するよね(笑)
じゃあここではどんな記号を使うべきかと問われたら、意外と悩むんじゃないかと思うけど。
そして、構文ごとに使う記号がまちまちになって、複雑とか言われちゃうんだろうなぁ。


typeと別名インポート

確かに、typeだけあれば別名インポート要らないかも?
と思ったけど、「type MMap = scala.collection.mutable.Map」って書けないんだよねぇ。typeでは型パラメーターを指定しないといけないから。
あ、「type MMap[A,B] = scala.collection.mutable.Map[A,B]」ってすればいいだけか(汗)
でもこれだと、Mapのコンパニオンオブジェクトが呼べない…。(「MMap[String,String]()」とか出来ない)


forのネスト

for(i <- 0 to 10; j <-0 to 10; k <- 0 to 10)」がどういうループか?
セミコロン区切りで3つに分かれてるから、C言語みたいに各ブロックとかで特殊な事をしてるのかもしれないし、でもi・j・kって書かれてるから三重ループのような気もするし?
うーん、他の言語で見かけない構文は、その言語の構文を勉強しないと分からないわなぁ。


for内包表記中のifとif式

forの括弧内で「if」を見かけたときにはビックリしたね(笑) 本体部分でifを書けばいいじゃんって思ったし。
「for(i <- 0 to 10 if i % 2 == 0) hoge」→
「for(i <- 0 to 10){ if(i % 2 == 0) hoge}」

for式がforeachとかに変換されると知って、ifがfilterメソッドになるんだったら、for式の構文上も「filter」というキーワードにすれば…とか思ったけど、英語圏の人にとってはifの方が分かりやすいのかもなーとも思う。


forとforEach

自分はJavaは知ってるけど関数型の考え方はさっぱりなので、forの構文無しでいきなりforeach使えって言われたら、敷居は高かっただろうなー。


タプルのインデックス

配列とかリストとかの先頭要素の添字は0なのに、Tupleは1から始まる。「t._1」みたいな。
これは自分も疑問に思った。(JDBCのResultSetも1から始まるのは気に入らない。BASICじゃないんだからさーw)

ただ、関数型言語ではタプルは1から始まるのが一般的らしい?
「ある言語内で(0オリジンに)統一する」のと、「(他言語も含めた)一般的な法則に従う」のと、どちらを採るかという話。


overrideの有無

自分は、抽象メソッドを実装するときにもoverrideを付けるべきだと思う。
「class B extends A { def name = ~ }」というソースを見たとき、nameが親クラスで宣言されているのか、自クラス専用なのか、そのソースだけでは判断できない。
オーバーライドしているのであれば、勝手にメソッド名を変えることは出来ない。
まぁ、抽象メソッドだったとすれば、変えたらコンパイルエラーになるので分かるんだけど…。IDEのリファクタリング機能がまだ期待できないので、簡単に変えられない。JavaでEclipseなら、けっこう気軽に名称変更するんだけど。


インスタンス生成時のnewの有無

最初分からなかったなぁ。newの要るケースと要らないケース。Java脳では、newしない事はありえないしなぁ。
分かってみれば、パターンは単純だけど。
(そういやC++もnewを使わないでインスタンス生成できるなぁ。あれも意味合いがけっこう違うが)


コンストラクター

classのブロック内に記述したコードが直接コンストラクターになるっていうのは、すごいアイデアだと思ったね!(コロンブスの卵的な意味で)
いわば、Javaのインスタンス初期化子の考え方を拡張したもの。コンストラクターが1つしか無いなら、def this()みたいなコードが不要で、すっきりする。(コンストラクター内のローカル変数が定義できないけど^^;)
一方、「どのコンストラクターも全てthisという名前にする」となっていたら、統一が取れているとも言える。


プレースホルダー

関数で各引数を1回しか使わない場合はプレースホルダー「_」が使える。
「_ < _」は「(a,b) => a < b」と同じだけど、引数の使用順序を変えたり2回以上使いたい場合は、どんな記号であれ一種類では表現できないよね。
「_1 < _2」みたいな表記が出来れば順序を変える事も2回以上使うことも可能だけど、数値を入れている時点で、引数の順序に依存してる(苦笑)
つまり、変数名を明示的に付けない限り、順序依存になるのはやむなし?(なるべく順序に依存すべきではない、という考え方には賛成なんだけど)

(しかしメソッド呼び出しなんかも、引数名を指定する形式にしない限り、順序に依存してるな…)


特殊なメソッドの書き方

一部のメソッド名に特別な意味があるのは自分も本当はあまり好きじゃない。それこそ用途毎にアノテーションとか付けるべきじゃないかと思う。
(JavaでRuntimeExceptionの派生クラスはthrowsが不要とか、特定のクラス名が言語仕様に入っているのは変だと思う)

と思ったけど、例えばapplyメソッドの代わりに@applyみたいなアノテーションがあったとして、「@apply apply1()」と「@apply apply2()」の2つが定義されていたら、呼び出し側でメソッド名を省略すると、どちらが呼ばれるべきか分からなくなるな(苦笑)
しかも親クラスで@apply付きのメソッドを定義してたりしたら…。


似ているキーワード

NoneNothingNullnullNilって、字面は似てるのかもしれないけど、全然別物で使い方も違うし、非常に分かりやすい。

それならListの::とかfuture(scala.concurrent.ops.futureとscala.actors.Futures.future)の違いの方がよっぽど分かりづらい。(てかfutureの違いは自分には分からない(汗))


パラメーター境界で右結合

Scalaのメソッドでは、メソッド名の末尾がコロンだと右結合になる。
これを「Scalaのメソッドでは」でなく「Scalaでは」という覚え方をしてしまうと、パラメーター境界の「<:」も気になるかも^^;

ちなみにJavaの言語仕様書の型の説明で初めて「<:」とかを見た気がするが、そのときはさっぱり理解できんかった(爆)


コンパニオンの参照

個々のクラス(インスタンス)から、コンパニオンオブジェクトのインスタンスを取得すること。
これは欲しいかも。
ついでに、Enumerationで、列挙子から列挙クラス(オブジェクト)を取得する方法も欲しいかも。(Enumeration自体、評判悪いようだけど…)


unsignedが無い

Javaにも無いからなぁ。Scalaには、JavaVMから独立してScalaVM作って欲しいな(笑)
(そのときにunsignedが入るかどうかは知らないけど、型消去は無くなるでしょう)


大抵の事は、何かしらそうなっている理由があるわけで。

ただ、その説明を聞いたときに「なるほど!」と思う人と「(理解できん)複雑だ」と思う人と、「分かったけどやっぱり複雑だ」という事柄があるんだろうなぁ。
あと、「説明を聞かないと理解できないようなものは「複雑だ」」とか「説明をじっくり見てる暇が無くて、ぱっと見た感じ複雑」という人もいるかも。

差し当たり、モナドって複雑だよね(爆)



最新の画像もっと見る

コメントを投稿