Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make the type checking at compile time?

In TraversableOnce, there is a sum method that is only usable if the contained type is Numeric (else it won't compile). I wonder if this is usable for other case (to avoid runtime check).

In particular the case where we have two traits A and B. We want to have a method f that can be used only if the object inherits both A and B. But not if it extends only one of them. I don't want to make another trait AB extends A with B. I just want to be unable to use f if not both traits are inherited.

package com.example

trait Base
trait Foo extends Base {
  def g = println("foo bar " + toString)
}
trait Bar extends Base {
  /* If this is both Foo and Bar, I can do more */
  def f = {
    if (!this.isInstanceOf[Foo]) error("this is not an instance of Foo")
    this.asInstanceOf[Foo].g
  }
}
object Test {
  def main(args: Array[String]): Unit = {
    object ab extends Foo with Bar
    object ba extends Bar with Foo
    object b extends Bar
    ab.f
    ba.f
    // I don't want next line to compile:
    try { b.f } catch { case e: RuntimeException => println(e) }
  }
}

EDIT: solution, thanks to @Aaron Novstrup

trait Bar extends Base { self =>
  def f(implicit ev: self.type <:< Foo) = {
    //self.asInstanceOf[Foo].g // [1]
    ev(this).g // [2]
  }
}

Now in main, b.f doesn't compile. Nice

EDIT 2: changed line [1] to [2] reflect changes in answer by @Aaron Novstrup

EDIT 3: without using self reflect changes in answer by @Aaron Novstrup

trait Bar extends Base {
  /* If this is both Foo and Bar, I can do more */
  def f(implicit ev: this.type <:< Foo) = {
    ev(this).g
  }
}
like image 258
shellholic Avatar asked Dec 22 '22 20:12

shellholic


1 Answers

Yes, you can:

trait A {
   def bar = println("I'm an A!")
}

trait B { 
   def foo(implicit ev: this.type <:< A) = { 
      ev(this).bar
      println("and a B!")
   }
}

The compiler will only be able to supply the evidence parameter if the object's static type (at the call site) extends A.

like image 183
Aaron Novstrup Avatar answered Feb 09 '23 16:02

Aaron Novstrup