Path にまつわる型推論
型推論クイズ - PS とはかけ離れたかもしれない怪しいレポート。
準備
以下の記事は、Scala 2.11.4 および Scala言語仕様 (pdf) (以下、SLS) の June 11, 2014 版を使用しています。また、scala.Singleton - PS に誤りがあり訂正しているので合わせてご覧ください。
問題
object M { val p: String = "Happy new year" val q1 = p: p.type val q2 = identity(M) }
において、省略されているq1
やq2
の型はどのように推論される(べき)か。
以下、上記のコードを参照します。
Path
大雑把にいうと、path [SLS 3.1] とはobject
やval
の名前が.
でつながった式である。例えば
M
M.p
M.q1
M.q2
this
は全て path である。
Entity type
Value definition [SLS.4.1] や function definition [SLS 4.6] などで定義したモノを entity 、その定義時に指定された型を entity type と勝手に呼ぶことにする。
Entity type inference
定義時に型が省略された場合、その型を推論することを entity type inference と勝手に呼ぶことにする。
SLS はこの推論を local type inference と呼んでいないのでやむを得ず一時的にこう呼びます。
Module
- 特に
object
を使って定義した entity を module と言う。[SLS 5.4]- module の entity type は unspecified である(とするのがたぶん正しい)。
- module の entity type は、それが
extends
する型に conform [SLS 3.5.2] する。[SLS 5.4]
Module path
特に module を参照する path を module path と呼ぶことにする。
Path の型付け
- ある path
p
には、expect [SLS 6.1] に応じて、次の二通りに型が付けられる。[SLS 6.4] *1-
p
が参照する entity の entity type -
p.type
つまりp
の singleton type- 「2.」は「1.」および
scala.Singleton
に conform する。[SLS 3.5.2] - 特に
p
が module path の場合は必ず「2.」が expect される。[SLS 6.4]
- 「2.」は「1.」および
-
「1.」は path 以外の式にも適用されるフツーの型付けである。一方、typed expression [SLS 6.13]:
M.p: scala.Singleton
における部分式としての pathM.p
の型は「2.」が expect されているためM.p.type
となる。
Local type inference
- polymorphic method [SLS 3.3.2] に渡す type argument を推論することを local type inference という。[SLS 6.26.4]
慣習上は entity type inference も含めて local type inference と呼んでますが、それで問題ない、というのが次です。
Singleton type に対する型推論
次のような規則の元に推論されると思われる。
- local type inference が singleton type を推論することはない。[SLS 6.26.4]
- entity type inference においても同様(と教えてもらう)。[SI-9023]
- ただし、例外として module path の型*2は推論する。[SI-1208]
- 将来的には
scala.Singleton
を利用して singleton type を推論できるようになるかも。[SI-5103]
「2.」は 現在の SLS の記述:
val x: T = e
においてT
が省略された場合は、e
の型が代わりに採用される。[SLS 4.1]def f psig: T = e
においても同様。[SLS 4.6]
と異なると思います。「3.」は広く知られた振る舞いですが SLS には見当たりませんでした。
問題の答え
Scala 設計者の意図としては
object M { val p: String = "Happy new year" val q1: String = p: p.type val q2: M.type = identity(M) }
が答えになると思われますが、q1
については SLS と異なり、q2
については SLS に無い(かも)、という怖い結果になりました。
一方、現在の実装ではq1
は SLS の記述どおり
val q1: p.type = p: p.type
と推論されるのでご注意ください。[SI-5210]