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
}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With