overload で邪魔な type erasure をなんとかする
型レの話書くの忘れてた…まあいいか。
値を何かしらでラップするみたいなことは、まれによくあります。
trait Nanka { type Rep[T] } trait Add extends Nanka { def add(lhs: Rep[Int], rhs: Rep[Int]) def add(lhs: Rep[Int], rhs: Rep[Double]) ... }
でまあこういうのはコンパイルエラーになる。add メソッドはどれも type erasure された結果、同じシグネチャを持つメソッドになってしまうからですね。全部 Java が悪い。まあ type erasure のおかげで higher order type param とか実現できたりもするしそれはそれで…いやそれはおいといて。
前こういうのに遭遇したときは、仕方がないので implicit parameter で type class 的に解決したのですが、それだと外部からの侵入に弱いとか、なんか書きづらい読みづらいとかでダサい。
そこで implicit parameter をもうちょっと違った使い方をする。
trait Add extends Nanka { class Dummy0 class Dummy1 implicit val dummy0 = new Dummy0 implicit val dummy1 = new Dummy1 def add(lhs: Rep[Int], rhs: Rep[Int])(implicit dummy: Dummy0) def add(lhs: Rep[Int], rhs: Rep[Double])(implicit dummy: Dummy1) ... }
implicit parameter を追加すれば、シグネチャは別になるし、使う側は何もわからないし、書く側も少し煩雑だけれど、まあ type class ぽく書くよりはましだし、外部から侵入されたりもしない…
めでたしめでたし。
Lightweight Modular Staging のスライドで見たテクニックです。implicit object と path dependent type 使えないかなーとか思ったんですがダメでした。