Generalised type constraints and this - scala

I'm trying to add a method to a generic class that should only work for some types, and I understand that a generalised type constraint is a way to achieve this. But I'm struggling to use this when the instance itself (this) needs to be passed, like so:
case class Sum(x: Value[Int], y: Value[Int]) {
def apply(): Int = x.v + y.v
}
case class Value[T](v: T) {
def plus(y: Value[Int])(using ev: T =:= Int): Int = Sum(this, y)()
}
I would have thought that the T =:= Int would have given the compiler enough information to know that this is a Value[Int], but it complains:
-- [E007] Type Mismatch Error: -------------------------------------------------
6 | def plus(y: Value[Int])(using ev: T =:= Int): Int = Sum(this, y)()
| ^^^^
| Found: (Value.this : Value[T])
| Required: Value[Int]
Is there a way to do what I am wanting here and have the compiler know that this is, indeed, Value[Int]?
Thanks for any help! ✌️

Unfortunately, no, passing T =:= Int, is not enough.
The way =:= works is that if at some place the compiler sees that implicit/given of T =:= T is required, it provides it.
At the call site of value1.plus(value2) the compiler can see that and create this evidence.
Once it is obtained, here - inside plus, =:= is NOT becoming a magic hint for the compiler for every type. It becomes an implicit conversion. If you'd do:
case class Value[T](v: T) {
def plus(y: Value[Int])(using ev: Value[T] =:= Value[Int]): Int = Sum(this, y)()
}
You'd see that it works, but with the help of e.g. IntelliJ + "show implicits" hint option you'd see that compiler turns your code into:
case class Value[T](v: T) {
def plus(y: Value[Int])(using ev: Value[T] =:= Value[Int]): Int = Sum(ev(this), y)()
}
This implicit conversion would work out of the box only on matching types.
However, there are other options:
case class Value[T](v: T) {
def plus(y: Value[Int])(using ev: T =:= Int): Int = Sum(ev.subsctituteCo[Value](this), y)()
}
ev.subsctituteCo lets you add a wrapper type and cast the wrapped value from the type on the left to the type on the right.
You could also cast it yourself with .asInstanceOf (less elegant) or unwrap and rewrap the value like suggested in the comments.

Related

How to transfer type parameter through class methods in scala?

In my project, I need to write a generic class, which in a single method handles some types with its handler in a special way (Numeric is used for clarity in the example).
class A[T](val a:T){
def doSomething(b:T):T = a match{
case a : Int => doSomethingWithIntOrDouble(b)
case a : Double => doSomethingWithIntOrDouble(b)
case _ => b
}
def doSomethingWithIntOrDouble(b:T)(implicit ev:Numeric[T]):T =
ev.plus(a,b)
}
<console>:13: error: could not find implicit value for parameter ev: Numeric[T]
case a : Int => doSomethingWithIntOrDouble(b)
^
<console>:14: error: could not find implicit value for parameter ev: Numeric[T]
case a : Double => doSomethingWithIntOrDouble(b)
I think this happens because the compiler picks up the type parameter but not the actual one. Tell me, is there any way around this?
PS Okay If we assume that the answer is correct, then it is necessary to overload the dosomething method to achieve polymorphism.
class A[T](val a:T){
def doSomething(b:T)(implicit ev:Numeric[T]):T = ev.plus(a,b)
def doSomething(b:T):T = b
}
But in this case, another problem arises.
scala> a.doSomething(2)
<console>:13: error: ambiguous reference to overloaded definition,
both method doSomething in class A of type (b: Int)Int
and method doSomething in class A of type (b: Int)(implicit ev: Numeric[Int])Int
match argument types (Int)
a.doSomething(2)
I am not completely sure this is want your want, but I hope it helps.
Basically, you need to forward the evidence that the T type is a Numeric to the outer method. But, you also have to handle the case where it is not.
For that case, you can provide a default value for the implicit parameter like this:
class A[T](val a: T) {
def doSomething(b: T)(implicit ev: Numeric[T] = null): T = Option(ev) match {
case Some(ev) => doSomethingWithNumeric(b)(ev)
case None => b
}
def doSomethingWithNumeric(b: T)(implicit ev: Numeric[T]): T =
ev.plus(a, b)
}
It seems to work.
(new A(10)).doSomething(100) // res: Int = 110
(new A("hey")).doSomething("world") // res: String = "world"
Note that, if you will have many methods, maybe a cleanest solution would be to make A a trait with two implementations, one for numeric types and other for no numeric types.
Make the constructors of both sub classes private and create a factory for A in the companion object which ask for the implicit numeric parameter, and if found it will return a new instance of the numeric subclass.

Scala: generic method using implicit evidence doesn't compile

I'm learning Scala by working the exercises from the book "Scala for the Impatient". One question asks:
Given a mutable Pair[S, T] class, use a type constraint to define a
swap method that can be called if the type parameters are the same.
My code:
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S) {
val temp = first
first = second // doesn't compile
second = temp
}
}
The code above fails to compile with the complaint that first and second are different types. Well, I just nicely told the compiler that they're not. How can I tell it to shut up?
You've just told the compiler that types passed to your class as T and S should be equal - you just require an evidence of their equality, which can be used to infer actual T and S correctly when you pass actual types (but not inside generic class itself). It doesn't mean that T and S are interchangable. Btw, it doesn't change anything but you did a mistake by defining new S and T, should be:
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S) { //without [S, T] - they are unrelated to original ones, it's whole new names
val temp = first
first = second // doesn't compile
second = temp
}
}
However it's still doesn't compile. Why? Just think of it:
def getBoth(implicit ev: T =:= S) = List(first, second)
So what is return type compiler should infer? List[T] or List[S]. the only it can do is List[Any]. So having same and different types simulteniously has no sense. If you want different names - just use type S = T no evidence will be needed.
And what is the real case of having S and T different in constructor and same in some method. It's simply logically incorrect (when talking about abstract types - not concrete substitutions).
Btw, =:= is not the compiler feature - there is no special processing for that in compiler. The whole implementation is it inside scala Predef:
#implicitNotFound(msg = "Cannot prove that ${From} =:= ${To}.")
sealed abstract class =:=[From, To] extends (From => To) with Serializable
private[this] final val singleton_=:= = new =:=[Any,Any] { def apply(x: Any): Any = x }
object =:= {
implicit def tpEquals[A]: A =:= A = singleton_=:=.asInstanceOf[A =:= A]
}
So it's just tpEquals[A] implicit which takes type A and gives you A =:= A - when you require T =:= U it's trying to make such conversion which is possible only for equal types. And the process of checking implicit itself actually happens only when you pass actual T and U, not when you defining them.
About your particular problem:
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S) {
val temp = first
first = second.asInstanceOf[T]
second = temp.asInstanceOf[S]
}
}
scala> new Pair(5,6)
res9: Pair[Int,Int] = Pair#6bfc12c4
scala> res9.swap
scala> res9.first
res11: Int = 6
Or just (as #m-z and #Imm suggested):
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S, ev2: S =:= T) {
val temp = first
first = second
second = temp
}
}
T =:= S extends T => S and this implicitly added function (even as an object) is interpreted as implicit conversion from T to S in Scala, so it works like both types are equal, which is pretty cool.

Typeclass implicit not found when caller has parametrized value

EDIT: I've removed my overcomplicated example that only obfuscated the problem for a simple one
I'm trying to figure out how to provide the necessary evidence to a typeclass using method for which one parameter generic, but can should be determinable from context
trait Converter[A, B] {
def apply(a: A, b: B): String
}
object Converters {
implicit object DoubleIntConverter extends Converter[Double, Int] {
override def apply(a: Double, b: Int): String = a.toString + ":" + b.toString
}
implicit object IntIntConverter extends Converter[Int, Int] {
override def apply(a: Int, b: Int): String = a.toString + ":" + b.toString
}
}
// passing in an Int
println(fun1(1))
// calling fun2 with Int and Int
def fun1[A](a: A) = fun2(a, 42)
def fun2[A, B](a: A, b: B)(implicit converter: Converter[A, B]): String = converter(a, b)
The error i get is:
Error:(36, 49) could not find implicit value for parameter converter: Converter[A,Int]
def fun1[A](a: A)(implicit arg: Arg[A]) = fun2(a, 42)
^
Error:(36, 49) not enough arguments for method fun2: (implicit converter: Converter[A,Int])String.
Unspecified value parameter converter.
def fun1[A](a: A)(implicit arg: Arg[A]) = fun2(a, 42)
^
fun2 doesn't know what A is. In this example, from the use of fun1 A is clearly an Int and B is also an Int and there exists an implicit object IntIntConverter. I assumed that problem is that A could be anything at all even not in the compiled code.
So I tried constraining A to Int or Double so that the Converter could be exhaustively enumerated with another typeclass:
sealed trait Arg[T]
object Arg {
implicit object IntArg extends Arg[Int]
implicit object DoubleArg extends Arg[Double]
}
def fun1[A](a: A)(implicit arg: Arg[A]) = fun2(a, 42)
The error now complains that here is not Converter[A,Int] at fun1 and I tried various other implicit variations, but I cannot get Converter to recognize the constraint imposed by Arg and therefore can never find an implicit for itself.
Is there some way to define this so thatfun2 can have a generic parameter but have it be able to determine which implementation of Converter it needs to include?
You need to define fun1 like this.
def fun1[A](a: A)(implicit converter: Converter[A, Int]) = fun2(a, 42)
In Scala, the type inference does not "flow backwards", only from left to right and top to bottom. So, the usage of fun1(1) is not considered for the implicit resolution for fun1 – it does not fix A to an Int. Seeing only the function definition by its own, the compiler knows nothing about A when it tries to find the Converter[A, B] for fun2. It knows, that B must b an Int, but at this point, A could be anything. So, you'll have to provide the compiler with the proper type class it can use: (implicit converter: Converter[A, Int]). Now, when calling fun1(1), the compiler knows about A and can look for a Converter[Int, Int].

what's different between <:< and <: in scala

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.

How to know if an object is an instance of a TypeTag's type?

I have a function which is able to know if an object is an instance of a Manifest's type. I would like to migrate it to a TypeTag version. The old function is the following one:
def myIsInstanceOf[T: Manifest](that: Any) =
implicitly[Manifest[T]].erasure.isInstance(that)
I have been experimenting with the TypeTags and now I have this TypeTag version:
// Involved definitions
def myInstanceToTpe[T: TypeTag](x: T) = typeOf[T]
def myIsInstanceOf[T: TypeTag, U: TypeTag](tag: TypeTag[T], that: U) =
myInstanceToTpe(that) stat_<:< tag.tpe
// Some invocation examples
class A
class B extends A
class C
myIsInstanceOf(typeTag[A], new A) /* true */
myIsInstanceOf(typeTag[A], new B) /* true */
myIsInstanceOf(typeTag[A], new C) /* false */
Is there any better way to achieve this task? Can the parameterized U be omitted, using an Any instead (just as it is done in the old function)?
If it suffices to use subtyping checks on erased types, do as Travis Brown suggested in the comment above:
def myIsInstanceOf[T: ClassTag](that: Any) =
classTag[T].runtimeClass.isInstance(that)
Otherwise you need to explicitly spell out the U type, so that scalac captures its type in a type tag:
def myIsInstanceOf[T: TypeTag, U: TypeTag] =
typeOf[U] <:< typeOf[T]
In your specific case, if you actually need to migrate existing code and keep the same behavior, you want ClassTag. Using TypeTag is more precise, but exactly because of that some code is going to behave differently, so (in general) you need to be careful.
If you indeed want TypeTag, we can do even better than the above syntax; the effect at the call site is the same as omitting U.
Recommended alternatives
Using pimping
With Eugene's answer, one has to spell both types, while it's desirable to deduce the type of that. Given a type parameter list, either all or none are specified; type currying could maybe help, but it seems simpler to just pimp the method. Let's use for this implicit classes, also new in 2.10, to define our solution in just 3 lines.
import scala.reflect.runtime.universe._
implicit class MyInstanceOf[U: TypeTag](that: U) {
def myIsInstanceOf[T: TypeTag] =
typeOf[U] <:< typeOf[T]
}
I would in fact argue that something like this, with a better name (say stat_isInstanceOf), could even belong into Predef.
Use examples:
//Support testing (copied from above)
class A
class B extends A
class C
//Examples
(new B).myIsInstanceOf[A] //true
(new B).myIsInstanceOf[C] //false
//Examples which could not work with erasure/isInstanceOf/classTag.
List(new B).myIsInstanceOf[List[A]] //true
List(new B).myIsInstanceOf[List[C]] //false
//Set is invariant:
Set(new B).myIsInstanceOf[Set[A]] //false
Set(new B).myIsInstanceOf[Set[B]] //true
//Function1[T, U] is contravariant in T:
((a: B) => 0).myIsInstanceOf[A => Int] //false
((a: A) => 0).myIsInstanceOf[A => Int] //true
((a: A) => 0).myIsInstanceOf[B => Int] //true
A more compatible syntax
If pimping is a problem because it changes the invocation syntax and you have existing code, we can try type currying (more tricky to use) as follows, so that just one type parameter has to be passed explicitly - as in your old definition with Any:
trait InstanceOfFun[T] {
def apply[U: TypeTag](that: U)(implicit t: TypeTag[T]): Boolean
}
def myIsInstanceOf[T] = new InstanceOfFun[T] {
def apply[U: TypeTag](that: U)(implicit t: TypeTag[T]) =
typeOf[U] <:< typeOf[T]
}
myIsInstanceOf[List[A]](List(new B)) //true
If you want to learn to write such code yourself, you might be interested in the discussion of variations shown below.
Other variations and failed attempts
The above definition can be made more compact with structural types:
scala> def myIsInstanceOf[T] = new { //[T: TypeTag] does not give the expected invocation syntax
def apply[U: TypeTag](that: U)(implicit t: TypeTag[T]) =
typeOf[U] <:< typeOf[T]
}
myIsInstanceOf: [T]=> Object{def apply[U](that: U)(implicit evidence$1: reflect.runtime.universe.TypeTag[U],implicit t: reflect.runtime.universe.TypeTag[T]): Boolean}
Using structural types is however not always a good idea, as -feature warns:
scala> myIsInstanceOf[List[A]](List(new B))
<console>:14: warning: reflective access of structural type member method apply should be enabled
by making the implicit value language.reflectiveCalls visible.
This can be achieved by adding the import clause 'import language.reflectiveCalls'
or by setting the compiler option -language:reflectiveCalls.
See the Scala docs for value scala.language.reflectiveCalls for a discussion
why the feature should be explicitly enabled.
myIsInstanceOf[List[A]](List(new B))
^
res3: Boolean = true
The problem is the slowdown due to reflection, required to implement structural types. Fixing it is easy, just makes the code a bit longer, as seen above.
A pitfall I had to avoid
In the above code, I write [T] instead of [T: TypeTag], my first attempt. It is interesting why it fails. To understand that, take a look:
scala> def myIsInstanceOf[T: TypeTag] = new {
| def apply[U: TypeTag](that: U) =
| typeOf[U] <:< typeOf[T]
| }
myIsInstanceOf: [T](implicit evidence$1: reflect.runtime.universe.TypeTag[T])Object{def apply[U](that: U)(implicit evidence$2: reflect.runtime.universe.TypeTag[U]): Boolean}
If you look carefully at the type of the return value, you can see it's implicit TypeTag[T] => U => implicit TypeTag[U] (in pseudo-Scala notation). When you pass an argument, Scala will think it's for the first parameter list, the implicit one:
scala> myIsInstanceOf[List[A]](List(new B))
<console>:19: error: type mismatch;
found : List[B]
required: reflect.runtime.universe.TypeTag[List[A]]
myIsInstanceOf[List[A]](List(new B))
^
A tip
Last and least, one tip which might or not interest you: in this attempt, you are passing TypeTag[T] twice - hence you should remove : TypeTag after [T.
def myIsInstanceOf[T: TypeTag, U: TypeTag](tag: TypeTag[T], that: U) =
myInstanceToTpe(that) stat_<:< tag.tpe
I used the above suggestions to come up with the following. Feedback is welcomed.
/*
Attempting to cast Any to a Type of T, using TypeTag
http://stackoverflow.com/questions/11628379/how-to-know-if-an-object-is-an-instance-of-a-typetags-type
*/
protected def toOptInstance[T: ClassTag](any: Any) =
classTag[T].runtimeClass.isInstance(any) match {
case true =>
Try(any.asInstanceOf[T]).toOption
case false =>
/*
Allow only primitive casting
*/
if (classTag[T].runtimeClass.isPrimitive)
any match {
case u: Unit =>
castIfCaonical[T](u, "void")
case z: Boolean =>
castIfCaonical[T](z, "boolean")
case b: Byte =>
castIfCaonical[T](b, "byte")
case c: Char =>
castIfCaonical[T](c, "char")
case s: Short =>
castIfCaonical[T](s, "short")
case i: Int =>
castIfCaonical[T](i, "int")
case j: Long =>
castIfCaonical[T](j, "long")
case f: Float =>
castIfCaonical[T](f, "float")
case d: Double =>
castIfCaonical[T](d, "double")
case _ =>
None
}
else None
}
protected def castIfCaonical[T: ClassTag](value: AnyVal, canonicalName: String): Option[T] ={
val trueName = classTag[T].runtimeClass.getCanonicalName
if ( trueName == canonicalName)
Try(value.asInstanceOf[T]).toOption
else None
}
You can also capture type from TypeTag (into type alias), but only if it's not erased, so it will not work inside function:
How to capture T from TypeTag[T] or any other generic in scala?