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