Getting Scala type bound error: not found: type <%<
Asked Answered
P

3

7

So I've been trying to learn Scala through the twitter Scala school. But I'm currently stuck at one of their type bound examples.

In particular, it's the one where the type is bound to be viewable as a certain type, using the <%< type-relation operator.

When I execute the following code in my Scala console:

scala> class Container[A](value: A) { def addIt(implicit evidence: A <%< Int) = 123 + value }

... I get the following errors:

<console>:7: error: not found: type <%<
       class Container[A](value: A) { def addIt(implicit evidence: A <%< Int) = 123 + value }
                                                                     ^
<console>:7: error: overloaded method value + with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int <and>
  (x: String)String
 cannot be applied to (A)
       class Container[A](value: A) { def addIt(implicit evidence: A <%< Int) = 123 + value }

My question is, why is the Scala interpreter complaining?

I've been trying to look through the Scala documentation but I haven't been able to find information that operator anywhere. I can see that the Scala school was created on the basis of Scala 2.8.0, and I'm running Scala 2.10.0 - so maybe this have been removed? If this is the case, why is this as it seems like a useful operator?

Polygon answered 20/2, 2013 at 15:31 Comment(3)
Looks like this isn't there in Scala 2.10, though I'm not sure exactly why - github.com/scala/scala/blob/v2.10.0/src/library/scala/…Venge
Was deprecated in github.com/scala/scala/commit/…Henriettahenriette
Well found! Looks like precisely the reason I guessed at below.Venge
V
8

The constraint A <%< B in Scala 2.8 is defined as

  sealed abstract class <%<[-From, +To] extends (From => To)
  object <%< {
    implicit def conformsOrViewsAs[A <% B, B]: A <%< B = new (A <%< B) {def apply(x: A) = x}
  }

So you can always bring it back that way. However, I'm guessing that the reason it's deprecated is that a view bound is just asking for an implicit function from A to B, and there's a perfectly good way to express that particular constraint in a generalised way already:

class Container[A](value: A) { def addIt(implicit evidence: A => Int) = 123 + value }

As an aside, it's worth noting that is isn't an operator, but a class in infix position as you can see from the definition. The same is true for =>, which is just another way of referencing the Function1 type constructor.

Venge answered 20/2, 2013 at 15:43 Comment(1)
I've been searching a bit for an official reasoning behind the removal of the class, but without any luck. Your guess is as good as anyone's and enough to satisfy my curiosity, thanks! :)Polygon
A
2

On this site, it says that A <%< B got deprecated in Scala 2.9. I don't know why, and I agree it seems a bit odd as it to me also looks like a pretty useful operator.

Adaline answered 20/2, 2013 at 15:38 Comment(1)
As described on the GitHub change at github.com/scala/scala/commit/…, A => B is to be used in place of A <%< B since they have the same semantics.Gudgeon
F
-1

The correct usage seems to be

class Container[A](value: A) { def addIt[A <% Int] = 123 + value }

As for the overloaded values, scala is choosing not to resolve the ambiguity; in which case, you have to decide.

  • you can try debugging with: -Xprint:typer

  • or you can decide that A is indeed Int by either using class Container[A](value: A) { def addIt = 123 + value.asInstanceOf[Int] } or the already suggested class Container[A](value: A) { def addIt(implicit evidence: A => Int) = 123 + value }. They are equivalent. But here you are saying that A is a type of Int; as opposed to A can be viewed as Int which is what <% does.

That second option is not trivial. Consider the following

scala> class Container[A](value: A) { def printIt[A <% Int] = println( 123+" could be " + value) }
defined class Container

scala> val x = new Container("Love")
x: Container[String] = Container@21ebfd82

scala> x.printIt
123 could be Love

Clearly "love" is not a type of Int because it is String, yet it's perfectly fine in this context: which is why you should be careful about using A => Int.

Finnish answered 20/2, 2013 at 16:39 Comment(3)
The snippet at the top is most definitely not the correct usage! The type parameter A on the 'addIt' method is shadowing the parameter A on the class, so adds nothing to this situation.Venge
Your second example works only because of a global implicit any2stringAdd which lets any type be converted to a string for the purposes of concatenating it - which is entirely co-incidental to this question. Also, it's not true to say that { def addIt = 123 + value.asInstanceOf[Int] } and { def addIt(implicit evidence: A => Int) = 123 + value } are equivalent. One is an unsafe cast which will blow up at compile time for anything not a subtype of Int. The other is type-safe, relying on an implicit conversion being in scope.Venge
Sorry, blow up at run time, not compile time.Venge

© 2022 - 2024 — McMap. All rights reserved.