I'm having trouble finding a way in scala to simultaneously impose an upper and lower type bound. I need to make a generic function where the type parameter is both hashable (subtype of AnyRef) and nullable (supertype of Null).
I could achieve the former like this:
def foo[T <: AnyRef](t: T) = ???
And the latter like this:
def bar[T >: Null)(t: T) = ???
Is there a way that I can do both simultaneously? Thanks.
What about this?
def foo[T >: Null <: AnyRef](t: T) = ???
It should work. That is:
foo(42) // does not compile
foo(null) // compiles
foo("hello") // compiles
Any type that is a subclass of AnyRef can be assigned the value null, so you do not need the upper bound.
def foo[T <: AnyRef](x: T) = x
foo(null) // returns null
That said, since you need to be able to hash the value, it should be noted that if you attempt to dereference null (e.g. null.hashCode) you will get a NullPointerException. For example:
def foo[T <: AnyRef](x: T) = x.hashCode
foo(null) // Throws an NPE
Furthermore, any use of null in Scala programs is strongly discouraged. Bearing all that in mind, I think what you might really want is something like this, which works for any type:
def foo[T](x: Option[T]) = x.hashCode
def foo(None) // Works. None is equivalent to no value (and Option(null) == None).
def foo(Some(1)) // Works. Note an Int isn't an AnyRef or nullable!
def foo(Some("Hello, world!")) // Works
def foo(Option(null)) // Works.
def foo(Option(z)) // Works, where z can be any reference type value, including null.
Option[T] is a functional means of dealing with undefined values (such as nullable types), and it works for any type T.
Related
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.
Can someone explain to me (or redirect to resources) why in this particular case the type tag is not "properly" generated:
class A(s: Seq[_]*)
def toto[T: TypeTag](p: Seq[T]): Seq[T] = {
println(typeTag[T].tpe)
p
}
val data = Seq( ("a", "a") )
val x = data.map(_._1)
new A(
toto(x),
toto(data.map(_._2)),
toto[String](data.map(_._2))
)
// output:
// java.lang.String
// Any
// String
As far as I understand, it seems that as my class A takes "untyped" (well with existential types) sequences, then the compiler does not bother generate the proper type tag when not required explicitly (though it does know the type of data.map(_._2) it still uses TypeTag[Any]... ). But it looks quite strange and I wondered if there was a more scientific explanation to this phenomenom.
Also, how can I force the compiler to generate a proper TypeTag[String] even if I don't want to create special variable (like this x variable above)?
Nice problem! I have an explanation, but I am not certain it's right (80%, let's say).
As very often with Scala type inference question, you need to be aware of expected types. In this case, all arguments of new A are typed with expected type Seq[_], which is the same as Seq[Any] because of covariance. So:
toto(data.map(_._2)) is typed with expected type Seq[Any]; data.map(_._2) is typed with expected type Seq[Any]. The signature of Seq#map is
def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Seq[A], B, That]): That
so That is inferred based on the expected type and a suitable implicit bf is found. I am not actually sure if B is inferred to String or Any, but it probably doesn't matter.
In the val x = data.map(_._1), there is no expected type so B is inferred to String, an implicit bf is found based on A and B and then That is inferred from the complete type of bf.
toto(x) is typed with expected type Seq[Any]; x is typed with expected type Seq[Any], but it already has type Seq[String] and the expected type doesn't matter.
I would like to extend answer of #AlexeyRomanov by possible solution how to force compiler to evaluate specific type:
From here I took idea for forcing type difference:
sealed class =!=[A,B]
trait LowerPriorityImplicits {
implicit def equal[A]: =!=[A, A] = sys.error("should not be called")
}
object =!= extends LowerPriorityImplicits {
implicit def nequal[A,B](implicit same: A =:= B = null): =!=[A,B] =
if (same != null) sys.error("should not be called explicitly with same type")
else new =!=[A,B]
}
Now we can add limitation for parameter to toto:
class A(s: Seq[_]*)
def toto[T: TypeTag](p: Seq[T])(implicit guard: T =!= Any): Seq[T] = {
println(typeTag[T].tpe)
p
}
val data = Seq(("a", "a"))
val x = data.map(_._1)
new A(
toto(x),
toto(data.map(_._2)),
toto[String](data.map(_._2))
)
And output I have
java.lang.String
java.lang.String
String
In my Scala code, I have an array of Option[T], like so:
val items = Array.fill[Option[T]](10)(None)
Now, I want to read a specific item from that array; if it has not been set, I want to have null. But when I do items(desiredIndex).orNull, the Scala compiler yells at me:
Error:(32, 34) Cannot prove that Null <:< T.
(items(desiredIndex).orNull).asInstanceOf[T]
I don't fully understand this error. What I do understand is that the compiler cannot infer that null is indeed a valid value for T (since it is not known what T will be). Looking at the implementation, I should supply implicit evidence for the fact that null is a valid value for T:
#inline final def orNull[A1 >: A](implicit ev: Null <:< A1): A1 = this getOrElse ev(null)
Now, my question is: how can I supply such evidence? What type is ev supposed to be, and how can I create a value for it?
By a type bound:
scala> def f[T >: Null : ClassTag]: T = {
| val items = Array.fill[Option[T]](10)(None)
| items(0).orNull }
f: [T >: Null](implicit evidence$1: scala.reflect.ClassTag[T])T
scala> f[String]
res3: String = null
Per Pedro:
scala> def f[T >: Null]: T = Array.fill[Option[T]](10)(None).apply(0).orNull
f: [T >: Null]=> T
While the solution given by som-snytt is simpler and better for this specific case, to answer the questions directly:
What type is ev supposed to be
Null <:< A1 (this is just a different way to write <:<[Null, A1]).
and how can I create a value for it
For a specific type you don't need to, the compiler will provide this evidence itself (using scala.Predef.$conforms). But when working with a generic T, you can just add the same implicit parameter to your method (or, for <:< specifically, a type bound), and to methods calling it, etc. until you come to a specific type.
Bounds in Scala allow more granular control of types in Scala, for example argument types.
For example
def foo[ S <: String ]( arg: S ): S = ...
The above allows a function to accept arguments that are sub types of String, also
def bar[ S >: A <: B ]( arg: S ): S = ...
The above allows the setting of an upper and lower bound so that S is a sub type of B and a super type of A.
My question is (I assume the bounds are inclusive) would it be possible to set up an argument type so that the argument would be a supertype of say String, but not include some super type of the lower bound (in this case String) say type Any.
UPDATE
sealed trait Helper[S]
object Helper {
implicit def stringSubtype[S >: String] = new Helper[S]{}
implicit def any = new Helper[Any]{}
}
def foo[S: Helper](r: S): Int = 1
val arg1: String = "hi"
val arg2: Any = "hello"
foo(arg1)
foo(arg2)
I would expect that the call with arg2 should result in an illegal argument exception.
For more complex type constraints like this you can do type-level programming via implicits:
sealed trait Helper[S]
object Helper {
implicit def stringSubtype[S >: String] = new Helper[S]{}
implicit def any = new Helper[Any]{}
implicit def any2 = new Helper[Any]{}
}
def foo[S: Helper] = ...
foo can only be invoked with a type S for which an implicit Helper[S] can be resolved. stringSubtype supplies a Helper[S] for any S >: String. But for Any, both that and any apply and the two implicits conflict, so it's not possible (well, except by explicitly passing one or the other) to call foo[Any].
Update: it seems that any is somehow higher priority than stringSubtype, so it's resolved for foo[Any]. Rather than figure out exactly why this is, the simplest workaround was to also define any2.
I already know that:
<: is the Scala syntax type constraint
while <:< is the type that leverage the Scala implicit to reach the type constrait
for example:
object Test {
// the function foo and bar can have the same effect
def foo[A](i:A)(implicit ev : A <:< java.io.Serializable) = i
foo(1) // compile error
foo("hi")
def bar[A <: java.io.Serializable](i:A) = i
bar(1) // compile error
bar("hi")
}
but I want to know when we need to use <: and <:< ?
and if we already have <:, why we need <:< ?
thanks!
The main difference between the two is, that the <: is a constraint on the type, while the <:< is a type for which the compiler has to find evidence, when used as an implicit parameter. What that means for our program is, that in the <: case, the type inferencer will try to find a type that satisfies this constraint. E.g.
def foo[A, B <: A](a: A, b: B) = (a,b)
scala> foo(1, List(1,2,3))
res1: (Any, List[Int]) = (1,List(1, 2, 3))
Here the inferencer finds that Int and List[Int] have the common super type Any, so it infers that for A to satisfy B <: A.
<:< is more restrictive, because the type inferencer runs before the implicit resolution. So the types are already fixed when the compiler tries to find the evidence. E.g.
def bar[A,B](a: A, b: B)(implicit ev: B <:< A) = (a,b)
scala> bar(1,1)
res2: (Int, Int) = (1,1)
scala> bar(1,List(1,2,3))
<console>:9: error: Cannot prove that List[Int] <:< Int.
bar(1,List(1,2,3))
^
1. def bar[A <: java.io.Serializable](i:A) = i
<: - guarantees that instance of i of type parameter A will be subtype of Serializable
2. def foo[A](i:A)(implicit ev : A <:< java.io.Serializable) = i
<:< - guarantees that execution context will contains implicit value (for ev paramenter) of type A what is subtype of Serializable.
This implicit defined in Predef.scala and for foo method and it is prove if instance of type parameter A is subtype of Serializable:
implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]
fictional case of using <:< operator:
class Boo[A](x: A) {
def get: A = x
def div(implicit ev : A <:< Double) = x / 2
def inc(implicit ev : A <:< Int) = x + 1
}
val a = new Boo("hi")
a.get // - OK
a.div // - compile time error String not subtype of Double
a.inc // - compile tile error String not subtype of Int
val b = new Boo(10.0)
b.get // - OK
b.div // - OK
b.inc // - compile time error Double not subtype of Int
val c = new Boo(10)
c.get // - OK
c.div // - compile time error Int not subtype of Double
c.inc // - OK
if we not call methods what not conform <:< condition than all compile and execute.
There are definitely differences between <: and <:<; here is my attempt at explaining which one you should pick.
Let's take two classes:
trait U
class V extends U
The type constraint <: is always used because it drives type inference. That's the only thing it can do: constrain the type on its left-hand side.
The constrained type has to be referenced somewhere, usually in the parameter list (or return type), as in:
def whatever[A <: U](p: A): List[A] = ???
That way, the compiler will throw an error if the input is not a subclass of U, and at the same time allow you to refer to the input's type by name for later use (for example in the return type). Note that if you don't have that second requirement, all this isn't necessary (with exceptions...), as in:
def whatever(p: U): String = ??? // this will obviously only accept T <: U
The Generalized Type Constraint <:< on the other hand, has two uses:
You can use it as an after-the-fact proof that some type was inferred. As in:
class List[+A] {
def sum(implicit ev: A =:= Int) = ???
}
You can create such a list of any type, but sum can only be called when you have the proof that A is actually Int.
You can use the above 'proof' as a way to infer even more types. This allows you to infer types in two steps instead of one.
For example, in the above List class, you could add a flatten method:
def flatten[B](implicit ev: A <:< List[B]): List[B]
This isn't just a proof, this is a way to grab that inner type B with A now fixed.
This can be used within the same method as well: imagine you want to write a utility sort function, and you want both the element type T and the collection type Coll. You could be tempted to write the following:
def sort[T, Coll <: Seq[T]](l: Coll): Coll
But T isn't constrained to be anything in there: it doesn't appear in the arguments nor output type. So T will end up as Nothing, or Any, or whatever the compiler wants, really (usually Nothing). But with this version:
def sort[T, Coll](l: Coll)(implicit ev: Coll <:< Seq[T]): Coll
Now T appears in the parameter's types. There will be two inference runs (one per parameter list): Coll will be inferred to whatever was given, and then, later on, an implicit will be looked for, and if found, T will be inferred with Coll now fixed. This essentially extracts the type parameter T from the previously-inferred Coll.
So essentially, <:< checks (and potentially infers) types as a side-effect of implicit resolution, so it can be used in different places / at different times than type parameter inference. When they happen to do the same thing, stick to <:.
After some thinking, I think it has some different.
for example:
object TestAgain {
class Test[A](a: A) {
def foo[A <: AnyRef] = a
def bar(implicit ev: A <:< AnyRef) = a
}
val test = new Test(1)
test.foo // return 1
test.bar // error: Cannot prove that Int <:< AnyRef.
}
this menas:
the scope of <: is just in the method param generic tpye scope foo[A <: AnyRef]. In the example, the method foo have it's generic tpye A, but not the A in class Test[A]
the scope of <:< , will first find the method's generic type, but the method bar have no param generic type, so it will find the Test[A]'s generic type.
so, I think it's the main difference.