Scala で条件演算子を作ってみる
コップ本を大体読み終わったので、とりあえず Scala の環境を入れてみた。
バージョンは 2.7.7 らしい。
で、Scala で三項演算子。ここでは、他の言語でよくある条件演算子をまねて作ってみた。
条件演算子なら if 式使えよ、って話だけど、まぁ練習ということで。
まず、?: で作ろうとしたんだけど、: は Scala ではいろいろとアレなので却下。
次に考えたのが、?? の組み合わせ。でもこれも入れ子がアレなので却下*1。
で、最終的に落ち着いたのが ?! の組み合わせ。! 以降は条件が成り立たなかった場合、つまり否定された場合に選択されるし、結構いいんじゃないかな。
実装は、単純に this を返さない流れるようなインターフェイスの発想で、
class CondOpA[T](val cond: Boolean, a: => T) { def !(b: => T) = if (cond) a else b } class CondOp(val cond: Boolean) { def ?[T](a: => T) = new CondOpA(cond, a) } implicit def boolWrapper(cond: Boolean) = new CondOp(cond)
こんな感じ。
暗黙の型変換を使って Boolean から CondOp に変換し、CondOp の ? メソッドを呼び出すと CondOpA が返され、CondOpA の ! メソッドを呼び出すと中で if 式が走る、と。
で、名前渡しパラメータを使用しているので、if 式と同じく実際に必要な項しか評価されないようになっている。
たとえば、
def hoge(): String = { println("hoge, world!") return "hoge" } def piyo(): String = { println("piyo, world!") return "piyo" }
な関数を定義して ?! を使ってみると、
scala> true ? hoge() ! piyo() hoge, world! res0: String = hoge scala> false ? hoge() ! piyo() piyo, world! res1: String = piyo
こんな感じ。
ジェネリクス周りはまだ完全に理解してないから両方 T で固定しちゃってるけど、より抽象的な方の型を返す、とかは普通にできそう。
で、ここまではいいんだけど・・・
scala> true ? hoge() ! false ? hoge() ! piyo() <console>:10: error: type mismatch; found : CondOpA[String] required: String true ? hoge() ! false ? hoge() ! piyo()
入れ子にできない!
つまり、(true ? hoge() ! false) をまず実行しようとして、a が String、b が Boolean なため、怒られる、と。
結局、括弧を補ってやる必要がある。
scala> true ? hoge() ! (false ? hoge() ! piyo()) hoge, world! res2: String = hoge
さらに・・・
scala> true ? hoge() res3: CondOpA[String] = CondOpA@15724a0
セミコロンが勝手に補われる!
ので、ここでもやっぱり括弧を使って、
scala> (true ? hoge() | ! piyo()) hoge, world! res4: String = hoge
と記述する必要がある。
さらには、最初
class CondOpA[T](val cond: Boolean, a: => T) { def !(b: => T) = if (cond) a else b } class CondOpB[T](val cond: Boolean, b: => T) { def ?(a: => T) = if (cond) a else b } class CondOp(val cond: Boolean) { def ?[T](a: => T) = new CondOpA(cond, a) def ![T](b: => T) = new CondOpB(cond, b) } implicit def boolWrapper(cond: Boolean) = new CondOp(cond)
なんてものを考えていたんだけど・・・
scala> true ! hoge() ? piyo() <console>:15: error: value ? is not a member of String true ! hoge() ? piyo() ^
演算子の優先順位が邪魔をする!
のでやっぱり括弧 (ry
scala> (true ! hoge()) ? piyo() piyo, world! res6: String = piyo
結論
if 式使え。
*1:実は後で他のものを選んでも関係なかったということが判明。後述