How to do type checking at compile time?

There is a sum method in TraversableOnce that can only be used if the contained type is Numeric (otherwise it won’t compile). I wonder if this can be used for another case (to avoid checking the runtime).

In particular, the case when 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 this applies only to one of them. I do not want to do another trait AB extends A with B I just want to be unable to use f if not both properties 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 { bf } 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 , bf does not compile. Nice

EDIT 2: modified line [1] - [2] reflects changes in @Aaron Novstrup's answer

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

 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 } } 
+4
source share
2 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 be able to specify the evidence parameter if the static type of the object (on the call site) extends A

+8
source

Knowing the signature of the sum

 def sum [B >: A] (implicit num: Numeric[B]) : B 

You seem to think that numeric types extend Numeric , this is not true. In fact, they are implicitly converted to numeric, in the case of Int, implicitly uses scala.math.Numeric.IntIsIntegral, which define operations such as plus and times.

Thus, the restriction on which types of AA TraversableOnce [A] .sum is allowed is achieved by the presence of implicit confirmation of the necessary operations.

This is just a brief explanation of the general operation of the Numeric and type classes. For a greater check of the sources of mathematics .Numeric.XisY, mathematics. Integral and mathematics. A fragment and how type classes work: implicit-tricks-type-class-pattern and type-class-pattern-example .

+3
source

All Articles