Scala covariance with lower bound - scala

I am looking at scala in action book and it has this code
sealed abstract class Maybe[+A] {
def isEmpty: Boolean
def get: A
def getOrElse[B >: A](default: B): B = {
if(isEmpty) default else get
}
}
final case class Just[A](value: A) extends Maybe[A] {
def isEmpty = false
def get = value
}
case object Nil extends Maybe[scala.Nothing] {
def isEmpty = true
def get = throw new NoSuchElementException("Nil.get")
}
If the signature of getOrElse is defined as
def getOrElse(default: A): A =
It doesnt compile.
The author states
"The lower bound B >: A declares that the type parameter B is constrained to some super type of type A"
Yet I seem to be able to do this and it works
val j1 = Just(1)
val l1 = j1.getOrElse("fdsf") //l1 : Any = 1
Is String a super type of Int? What am i not understanding as to why this works? Its like its falling back to argument 1 being type A being of type Any (which it is) rather than type Int.

In Scala you cannot have covariant types in method parameters.
This is because allowing covariant types in method parameters breaks type safety.
In order to have a covariant type you must use a bounded type:
getOrElse[B >: A](default: B): B
This says find some type, B, such that it is a superclass of A and that becomes the method return type.
In your case A is Int and you pass in a String. The only type B which is a superclass of both Int and String is Any.
In this case B becomes Any so the method returns Any.

Related

What is meant by a type that denotes an implicit conversion

The scala language specification, section 7.2 is about implicit scope:
It explains that implicit scope are the modules associated in some way with the parts of type T. What the parts of T are is listed below. One of those points is
if T denotes an implicit conversion to a type with a method with
argument types T1,…,Tn and result type U, the union of the parts of
T1,…,Tn and U;
I can't make head or tails from this. I don't understand how a type T can denote an implicit conversion.
What is meant by this part of the specification of implicit scope?
I believe this is referring to the following situation
case class Foo(v: Int)
object Foo {
implicit def stringToFoo(s: String) = Foo(42)
}
def f[A](v: A)(implicit ev: A => Foo) = ev(v)
f("woohoo")
where the implicit conversion type T = A => Foo, and Foo is the part associated with type parameter A, therefore object Foo becomes part of the implicit scope and stringToFoo implicit conversion is resolved without needing an import.
Here are examples:
trait A
object A {
implicit def f(a: A): B = null
}
trait B
val b: B = new A {} // compiles
or
trait A
trait B
object B {
implicit def f(a: A): B = null
}
val b: B = new A {} // compiles
Let T denote an implicit conversion to a type, from A to B (val b: B = new A {}), it denotes the conversion with a method with argument types T1,…,Tn = A and result type U = B. So the parts of T are the union of the parts of A and parts of B. So an implicit can be defined as a member of the companion object of a base class of the parts of T (i.e. A or B).

Understanding Scala AnyVal and Null

Why does the following compile? I understand that AnyVal instances correspond to things in the underlying host system that cannot be constructed, and that Null is a subtype of all reference types but not of value types. I have an AnyVal type Boolean I give to safeMapDifferent, but don't see how it can satisfy this constraint of U >: Null.
object MyMainScala extends App {
implicit class RichObject[T](o: T) {
def safeMap[U](method: T => U)(implicit ev: Null <:< U): U =
Option(o).flatMap(result => Option(method(result))).orNull
def safeMapDifferent[U >: Null](method: T => U): U =
Option(o).flatMap(result => Option(method(result))).orNull
}
override def main(args: Array[String]): Unit = {
val testSubject = new Object() {
def scalaBoolean: Boolean = ???
}
// println(testSubject.safeMap(_.scalaBoolean)) // If not commented, this will fail to compile as I expect.
println(testSubject.safeMapDifferent(_.scalaBoolean).getClass) // Why does it compile?
}
}
Its because of Autoboxing. If you see in predef.scala, you will see bunch of implicit conversion methods that convert scala AnyVal to Java.
/** #group conversions-anyval-to-java */
implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = x.asInstanceOf[java.lang.Boolean]
When you invoke your print method, println(testSubject.safeMapDifferent(_.scalaBoolean).getClass), you are providing T => U value i.e. _.scalaBoolean which takes testSubject as parameter which satisfy T type parameter and returns Boolean which does not satisfy U >: Null. Upon getting this error, instead of throwing exception, the compiler looks for implicit methods which can convert Boolean into expected U >: Null type and it found boolean2Boolean in predef.scala which satisfy this constraint because java.land.Boolean is a reference type. Hence, compile execute the code correctly.
def foo[U >: Null](o : U) = println(o)
foo(true) // compile correctly.
foo[java.lang.Boolean](true) //compile correctly, because true is implicitly converted to java Boolean and java.lang.Boolean is reference type and superType of scala.Null.
To avoid this, you must statically provide type parameter: foo[Boolean](true) //won't compile.

Scala type parameter inference based on return type (function vs method)

I try to create a small matching library in Scala.
I have the following type representing a matcher that reprsents a constraint on a type T:
trait Matcher[-T] extends (T => Boolean)
and a matches function that checks whether that constraint holds on a given instance:
def matches[A](x: A, m: Matcher[A]) = m(x)
With this I would like to be able to write checks like:
matches(Option(1), contains(1))
matches(Seq(1,2), contains(1))
where the contains can abstract over any container. I tried the following abstraction using type classes:
trait F[-C[_]] {
def contains[A >: B, B](c: C[A], x: B): Boolean
}
which I can then use to define contains function:
def contains[A, B[A]](y: A)(implicit f: F[B]): Matcher[B[A]] = new Matcher[B[A]] {
override def apply(v1: B[A]): Boolean = f.contains(v1, y)
}
with two implicit definitions, one for Option:
implicit object OptionF extends F[Option] {
override def contains[A >: B, B](c: Option[A], x: B): Boolean = c.contains(x)
}
and for Iterable:
implicit object IterableF extends F[Iterable] {
override def contains[A >: B, B](c: Iterable[A], x: B): Boolean = c.exists(_ == x)
}
However, when I get the errors on each call to matches. They are all the same:
Error:(93, 39) ambiguous implicit values:
both object OptionF in object MatchExample of type MatchExample.OptionF.type
and object IterableF in object MatchExample of type MatchExample.IterableF.type
match expected type MatchExample.F[B]
matches(Option(1), contains(1))
It seems that the type inference could not deduce the type properly and that is why both implicit matches.
How can the matches function be defined without ambiguity?
I also tried to use implicit conversion to add the matches function directly to any type:
implicit class Mather2Any[A](that:A) {
def matches(m: Matcher[A]): Boolean = m(that)
}
and that is working just fine:
Option(x1) matches contains(x1)
lx matches contains(x1)
lx matches contains(y1)
What I don't understand why the matches functions does not work while the method does? It looks like the problem is that the inference is only based on the return type. For example instead of contains I could isEmpty with not arguments which again works with the matches method but not function.
The full code listing is in this gist.
What you need is to split the parameters into two lists:
def matches[A](x: A)(m: Matcher[A]) = m(x)
matches(Option(1))(contains(1))
matches(Seq(1,2))(contains(1))
A gets inferred from x and is then available while type-checking m. With Mather2Any you have the same situation.
Side note: variations on this get asked often, I just find it faster to reply than to find a duplicate.

Scala covariance and lower bound i dont get it

I am currently learning scala and i am confused about the variance annotations especially the covariance and contravariance.
So i did some research an came upon following example
class Box[+T] {
def put[U >: T](x: U): List[U] = {
List(x)
}
}
class Animal {
}
class Cat extends Animal {
}
class Dog extends Animal {
}
var sb: Box[Animal] = new Box[Cat];
So this says class Box is covariant in T whiche means Box[Cat] is a subclass of Box[Animal] since Cat is a subclass of Animal. Sofar i understand this. But when it comes to method parameters my understanding ends. The spec says methods parameters can not be covariant so we have to use this lower bound annotation.
Lets look at the method definiton
def put[U >: T](x: U): List[U] = {
List(x)
}
So [U >: T] says that U must be a superclass of T
Trying following code
var sb: Box[Animal] = new Box[Cat];
sb.put(new Cat);
Works as expected but this drives me nuts
var sb: Box[Animal] = new Box[Cat];
sb.put(1);
It logically makes no sense to me to put an INT into a Box of Animals alltough its correct since INT will be resolved to Any which is a superclass of Animal.
So my question is
How do i have to adapt the code that the put method accepts only subtypes of
animal? I can not use the upper bound annotation
class Box[+T] {
def put[U <: T](x: U): List[U] = {
List(x)
}
}
since i get this well known error
covariant type T occurs in contravariant position in type
You can add both a lower and an upper bound:
class Box[+T] { def put[U >: T <: Animal](x: U): List[U] = List(x) }
But this is not what you want, since you wire the definition of Box to Animal and logically there is no reason to add such an upper bound.
You say:
It logically makes no sense to me to put an INT into a Box of Animals alltough its correct since INT will be resolved to Any which is a superclass of Animal.
You don't put an Int into a Box[Animal], the existing box is immutable (and it is not possible to make it mutable, since the definition of covariance doesn't allow it). Instead you get a box (or in case of your put method) of a new type. If your goal is to get only a List[Anmial], then you just have to specify that:
scala> class Box[+T] { def put[U >: T](x: U): List[U] = List(x) }
defined class Box
scala> var b: Box[Animal] = new Box[Cat]
b: Box[Animal] = Box#23041911
scala> val xs: List[Animal] = b put new Dog
xs: List[Animal] = List(Dog#f8d6ec4)
scala> val xs: List[Animal] = b put 1
<console>:14: error: type mismatch;
found : Int(1)
required: Animal
val xs: List[Animal] = b put 1
^
scala> val xs = b put 1 // this will result in a List[Any]
xs: List[Any] = List(1)
There is no need to complicate the definition of the put method.
For a more in depth explanation about why co- and contravariance is needed see this question.

F-Bounded Polymorphism in Scala

I am using Scala 2.10-RC5
Here is my code:
object Fbound {
abstract class E[A <: E[A]] {
self: A =>
def move(a: A): Int
}
class A extends E[A] {
override def toString = "A"
def move(a: A) = 1
}
class B extends E[B] {
override def toString = "B"
def move(b: B) = 2
}
def main(args: Array[String]): Unit = {
val a = new A
val b = new B
val l = List(a, b)
val t = l.map(item => item.move(null.asInstanceOf[Nothing]))
println(t)
}
}
when run the program, exception occurs:
Exception in thread "main" java.lang.NullPointerException
at fb.Fbound$$anonfun$1.apply(Fbound.scala:20)
at fb.Fbound$$anonfun$1.apply(Fbound.scala:20)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.TraversableLike$$anonfun$map$1.apply(TraversableLike.scala:244)
at scala.collection.immutable.List.foreach(List.scala:309)
at scala.collection.TraversableLike$class.map(TraversableLike.scala:244)
at scala.collection.AbstractTraversable.map(Traversable.scala:105)
at fb.Fbound$.main(Fbound.scala:20)
at fb.Fbound.main(Fbound.scala)
my question is:
Why it pass the compiler but fail at runtime?
Adding a line at the bottom - val t1 = l.map(item => item.move(item)) will fail the compiler, why?
Your code with null.asInstanceOf[Nothing] compiles because Nothing is a subclass of everything and, as such, complies with the required type for move. Needless to say, it will throw an exception at runtime.
When you try to compile the second line you gave, you are given something in the lines of this error:
<console>:19: error: type mismatch;
found : E[_6(in value $anonfun)] where type _6(in value $anonfun) >: B with A
<: E[_ >: B with A <: Object]
required: <root>._6
When you put the two instances in the same List, you have lost important information about the type of their elements. The compiler can't ensure that an element of type T >: B with A <: E[_ >: B with A] can be passed to the move method of an object of the same type, the same way that you can't do:
val c: E[_ >: B with A] = new A
val d: E[_ >: B with A] = new B
c.move(d) // note: the _ in c and d declarations are different types!
I don't know enough about self-types to be completely sure of this explanation, but it seems to me that it is a class-level restriction, and not an instance-level one. In other words, if you lose the information about the type parameter in E, you can't expect the compiler to know about the move argument particular type.
For instance-level restrictions, you have this.type. If you define move as:
def move(a: this.type): Int
Your code compiles, but I don't think it is what you want, as move will accept only the same instance you are calling it on, which is useless.
I can't think of any way you may enforce that restriction the way you want. I suggest you try to do that with type variables (i.e. defining a type variable type T = A in class E), which have, as far as I know, some degree of binding to instances. Perhaps you can explain in more detail your specific situation?
Re: second question
The problem is type of the argument of move method, I can't see it being possible to make it work if it is in any way tied to subclass(es), instead:
l has to be 'some form' of list of E-s
so then item will be 'some form' of E
type of argument to move has to have the same type
This is then the only way I could make it work with type arguments (changing btw name of type argument to X, not to be confused with name of class A, and removing self type declaration, which I think is irrelevant for this problem/discussion):
abstract class E[X <: E[X]]
{
def move (a: E[_]): Int
}
class A extends E[A]
{
def move(a: E[_]): Int = 1
}
class B extends E[B]
{
def move(b: E[_]): Int = 2
}
...
{
val a = new A
val b = new B
val l = List (a, b)
val t = l.map (item => item.move(item))
...
}
If someone could give a more 'type-restrictive' solution, I would really like to see it.
Another option, as Rui has suggested, would be to use a type member, something like this:
abstract class E
{
type C <: E
def move (x: E): Int
}
class A extends E
{
type C = A
def move(x: E): Int = 1
}
class B extends E
{
type C = B
def move(x: E): Int = 2
}
...
{
val a = new A
val b = new B
val l = List (a, b)
val t = l.map (item => item.move(item))
...
}