by shigemk2

当面は技術的なことしか書かない

getOrElseについてGitterで質問してみる。

getOrElseについて。

scala> val a = Some("hoge")
a: Some[String] = Some(hoge)

scala> a.getOrElse(Some("fuga"))
res3: java.io.Serializable = hoge

scala> a.getOrElse("fuga")
res4: String = hoge

で、結果の型がStringではなくSerializableになるのがよくわからんかったので、Gitterに質問してみました。

gitter.im

scala> a.getOrElse(Some("fuga"))
res3: java.io.Serializable = hoge

よしださんからの回答。

def getOrElse(default: => A): A じゃなく def getOrElse[B >: A](default: => B): B と定義されてるからですね
https://github.com/scala/scala/blob/v2.11.7/src/library/scala/Option.scala#L120
どちらで定義するべきかはトレードオフなのでなんとも言えないですが、scalazの場合はその上記のSerializableになるミス(?)を避けるため、違う定義になってます
https://github.com/scalaz/scalaz/blob/v7.1.4/core/src/main/scala/scalaz/Maybe.scala#L31

がくぞさんからの回答。

String と Option[String] の共通の型が Serializable だからじゃないでしょうか
必用なのは getOrElse じゃなくて orElse なのでは? https://github.com/scala/scala/blob/v2.11.7/src/library/scala/Option.scala#L288

ということで、

  • def getOrElseB >: A: B なので、defaultの型はB(Aの継承元)
  • StringとOption[String]の継承元はSerializable

むろん、getOrElseで使われるOptionの中の値は何でもよくて、還元するとこうなる。

scala> class A;class B extends A;class C extends A; Option(new B).getOrElse(new C)
defined class A
defined class B
defined class C
res0: A = B@5474c6c

よしださん、がくぞさん、いつもありがとうございます。

(Gitterの発言ってブログに埋め込めないのかな)

追記

www.shigemk2.com

Scalaのソースコードを読むってところでいうと、やっぱり上限境界、下限境界などの知識が必要で、昔の勉強会でちょっと話があったことを思い出しました。