PS

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) 
    }

において、省略されているq1q2の型はどのように推論される(べき)か。

以下、上記のコードを参照します。

Path

大雑把にいうと、path [SLS 3.1] とはobjectvalの名前が.でつながった式である。例えば

  • 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 の型付け

  • ある pathpには、expect [SLS 6.1] に応じて、次の二通りに型が付けられる。[SLS 6.4] *1
    1. pが参照する entity の entity type
    2. p.typeつまりpの singleton type
      • 「2.」は「1.」およびscala.Singletonに conform する。[SLS 3.5.2]
      • 特にpが module path の場合は必ず「2.」が expect される。[SLS 6.4]

「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 に対する型推論

次のような規則の元に推論されると思われる。

  1. local type inference が singleton type を推論することはない。[SLS 6.26.4]
  2. entity type inference においても同様(と教えてもらう)。[SI-9023]
  3. ただし、例外として module path の型*2は推論する。[SI-1208]
  4. 将来的には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]

参考文献

*1:つまり polymorphic

*2:それに equivalent [SLS 3.5.1] な型も含む