Scala3/tracked
! Experimental feature at 3.6.4: import scala.language.experimental.modularity Scala is dependently typed for functions, but unfortunately not for classes.
tracked修飾子
依存型的な振る舞いの一貫性を、クラスにも持たせるために導入された機能
クラスで使うと、フィールドがoverrideされても型を維持するようになる
前提: Scalaは抽象的な型定義をクラスやトレイトに置くことができる:
code:scala
trait F:
type A <: Int
val f: A
「FにはA型があり、Intのサブタイプであればなんでもよい。具象化するときに適当に埋まる」
前提: これを具象化するときは
code:scala
val instance = new F:
type A = 42
val f = 42
前提: 関数で抽象型を返すような処理を呼び出すと:
code:scala
def getF(x: F): x.A = x.f
val res1 = getF(instance) //=> res1: Int = 42
型が分かっている
定義タイミングでは返り値の型は分からないが、instanceという値に依存して型を決めてくれ、とgetFは定義しており、実際その通りになっている
instanceという具体的な値が型を最終的に決定する鍵になっている
ところが: クラスのメソッドとして同じことをすると:
code:scala
class G(val instance: F):
def getF: instance.A = instance.f
val res2 = G(instance).getF
// => val res2: G#instance.A = 42
型わかんないよ〜
これだとモジュールに分けて処理を分けるのに都合が悪い
パーツごとに処理を分割するのが困難になる
Scala 3.6.4で、experimental扱いの機能として使える
code:scala
import scala.language.experimental.modularity
trait H:
type A <: Int
tracked val f: A // add tracked to val
val instance2 = new H:
type A = 42
val f = 42
class I(val instance: H):
def getF: instance.A = instance.f
val res3 = I(instance2)
res3
Scala 3.7.2からはクラスコンストラクタ引数に直にtrackedを書けるようになった
code:scala
class J(tracked val x: Any)
val res = J(42)
res.x // => 42: Int