Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Hope the following somewhat contrived example will clarify the whole matter a bit.</p> <p>Consider this code (which corresponds to your current one):</p> <pre><code>object Main { def main(args: Array[String]) { implicit val intIntable = new Intable[Int] { def toInt(obj: Int) = obj } println(squareAndDouble(10: Int)) } // Corresponds to your register[T] function def squareAndDouble[T](obj: T) = { val d = double[T](obj) d*d } // Corresponds to your extractEntity[T] function def double[T: Intable](obj: T) = { implicitly[Intable[T]].toInt(obj)*2 } } trait Intable[T] { def toInt(obj: T): Int } </code></pre> <p>This code does not compile with the following error:</p> <pre><code>test.scala:11: error: could not find implicit value for evidence parameter of type Intable[T] val d = double[T](obj) </code></pre> <p>Now let's rewrite it using implicit parameters (that's what the compiler do for us when it sees context bound):</p> <pre><code>object Main { def main(args: Array[String]) { implicit val intIntable = new Intable[Int] { def toInt(obj: Int) = obj } println(squareAndDouble(10: Int)) } def squareAndDouble[T](obj: T) = { val d = double[T](obj) d*d } def double[T](obj: T)(implicit intable: Intable[T]) = { intable.toInt(obj)*2 } } trait Intable[T] { def toInt(obj: T): Int } </code></pre> <p>This program does not compile as well:</p> <pre><code>test.scala:11: error: could not find implicit value for parameter intable: Intable[T] val d = double[T](obj) </code></pre> <p>And now it should be more obvious why it does not compile. It fails simply because there is no implicit value ('evidence') for <code>T</code> type parameter inside <code>squareAndDouble</code> function which is required by <code>square</code> function. Since <code>double</code> function need an evidence for its type parameter (which can be anything) the only way for this evidence to appear in scope inside <code>squareAndDouble</code> is from an implicit parameter again, but now in <code>squareAndDouble</code> function.</p> <p>Basically, that means that you have to 'pass through' the evidence for your generic parameter in order to use the typeclass.</p> <p>Let's fix it:</p> <pre><code>object Main { def main(args: Array[String]) { implicit val intIntable = new Intable[Int] { def toInt(obj: Int) = obj } println(squareAndDouble(10: Int)) } // Added context bound here def squareAndDouble[T: Intable](obj: T) = { val d = double[T](obj) d*d } def double[T: Intable](obj: T) = { implicitly[Intable[T]].toInt(obj)*2 } } trait Intable[T] { def toInt(obj: T): Int } </code></pre> <p>Now it compiles and runs successfully:</p> <pre><code>% scalac test.scala % scala Main 400 </code></pre> <p>Another (may be more simple) way to understand the problem is as follows. Our <code>squareAndDouble[T]</code> function accepts unbounded type parameter <code>T</code>, but then it tries to call another function, <code>double[T: Intable]</code>, whose type parameter is bounded. This is not allowed: if it was legal, then it would be possible to call <code>squareAndDouble[T]</code> with any type, even with that which does not have <code>Intable</code> typeclass instance, and this would consequently break <code>double</code> function. Hence we have to add <code>Intable</code> boundary to <code>squareAndDouble</code> function too in order for it to compile: <code>squareAndDouble[T: Intable]</code>, and then it works perfectly.<br> This is in fact very similar to upper/lower bounds which work with class inheritance instead of implicit values.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload