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.
Related
Suppose you have a trait like this:
trait Foo[A]{
def foo: A
}
I want to create a function like this:
def getFoo[A <: Foo[_]](a: A) = a.foo
The Scala Compiler deduces Any for the return type of this function.
How can I reference the anonymous parameter _ in the signature (or body) of getFoo?
In other words, how can I un-anonymize the parameter?
I want to be able to use the function like
object ConcreteFoo extends Foo[String] {
override def foo: String = "hello"
}
val x : String = getFoo(ConcreteFoo)
which fails compilation for obvious reasons, because getFoo is implicitly declared as Any.
If this is not possible with Scala (2.12 for that matter), I'd be interested in the rational or the technical reason for this limitation.
I am sure there are articles and existing questions about this, but I appear to be lacking the correct search terms.
Update: The existing answer accurately answers my question as stated, but I suppose I wasn't accurate enough regarding my actual usecase. Sorry for the confusion. I want to be able to write
def getFoo[A <: Foo[_]] = (a: A) => a.foo
val f = getFoo[ConcreteFoo.type]
//In some other, unrelated place
val x = f(ConcreteFoo)
Because I don't have a parameter of type A, the compiler can't deduce the parameters R and A if I do
def getFoo[R, A <: Foo[R]]: (A => R) = (a: A) => a.foo
like suggested. I would like to avoid manually having to supply the type parameter R (String in this case), because it feels redundant.
To answer literally your exact question:
def getFoo[R, A <: Foo[R]](a: A): R = a.foo
But since you don't make any use of the type A, you can actually omit it and the <: Foo[..] bound completely, retaining only the return type:
def getFoo[R](a: Foo[R]): R = a.foo
Update (the question has been changed quite significantly)
You could smuggle in an additional apply invocation that infers the return type from a separate implicit return type witness:
trait Foo[A] { def foo: A }
/** This is the thing that remembers the actual return type of `foo`
* for a given `A <: Foo[R]`.
*/
trait RetWitness[A, R] extends (A => R)
/** This is just syntactic sugar to hide an additional `apply[R]()`
* invocation that infers the actual return type `R`, so you don't
* have to type it in manually.
*/
class RetWitnessConstructor[A] {
def apply[R]()(implicit w: RetWitness[A, R]): A => R = w
}
def getFoo[A <: Foo[_]] = new RetWitnessConstructor[A]
Now it looks almost like what you wanted, but you have to provide the implicit, and you have to call getFoo[ConcreteFoo.type]() with additional pair of round parens:
object ConcreteFoo extends Foo[String] {
override def foo: String = "hey"
}
implicit val cfrw = new RetWitness[ConcreteFoo.type, String] {
def apply(c: ConcreteFoo.type): String = c.foo
}
val f = getFoo[ConcreteFoo.type]()
val x: String = f(ConcreteFoo)
I'm not sure whether it's really worth it, it's not necessarily the most straightforward thing to do. Type-level computations with implicits, hidden behind somewhat subtle syntactic sugar: that might be too much magic hidden behind those two parens (). Unless you expect that the return type of foo will change very often, it might be easier to just add a second generic argument to getFoo, and write out the return type explicitly.
I have a situation similar to this:
trait Abst{
type T
def met1(p: T) = p.toString
def met2(p: T, f: Double=>this.type){
val v = f(1.0)
v.met1(p)
}
}
class MyClass(x: Double) extends Abst{
case class Param(a:Int)
type T = Param
val s = met2(Param(1), (d: Double) => new MyClass(d))
}
And it doesn't show errors until I run it, then it says:
type mismatch; found: MyClass, required:
MyClass.this.type
I tried also a solution with generic type but then I have conflict that this.T differs from v.T.
So I just need to overcome the error message above if possible?
Update
So, it turns out that this.type is the singleton type for that single instance. And I proposed in a comment usage of
val s = met2(Param(1), (d: Double) => (new MyClass(d)).asInstanceOf[this.type])
So just if someone would make a comment about this, I am aware how ugly it is, just interested how unsafe it is?
Also you all proposed to move definition of Param outside the class, which I definitely agree. So its definition will be in the companion object MyClass
The this.type is the singleton type that is inhabited by one single value, namely this. Therefore, accepting a function of type f: X => this.type as an argument is guaranteed to be nonsensical, because every invocation of f can just be replaced by this (plus the side-effects performed by f).
Here is a way of forcing your code to compile with minimal changes:
trait Abst { self =>
type T
def met1(p: T) = p.toString
def met2(p: T, f: Double => Abst { type T = self.T }){
val v = f(1.0)
v.met1(p)
}
}
case class Param(a:Int)
class MyClass(x: Double) extends Abst {
type T = Param
val s = met2(Param(1), (d: Double) => new MyClass(d))
}
But honestly: don't do it. And also don't do any of the F-bounded-stuff either, it will probably end up as a total mess, especially if you are not familiar with the pattern. Instead, refactor your code so that you don't have any self-referential spirals in it.
Update
Remark on why telling to the compiler that (new MyClass(d)) is of type this.type for some other this: MyClass is a really bad idea:
abstract class A {
type T
val x: T
val f: T => Unit
def blowup(a: A): Unit = a.asInstanceOf[this.type].f(x)
}
object A {
def apply[X](point: X, function: X => Unit): A = new A {
type T = X
val x = point
val f = function
}
}
val a = A("hello", (s: String) => println(s.size))
val b = A(42, (n: Int) => println(n + 58))
b.blowup(a)
This blows up with a ClassCastException, despite a and b both being of type A.
If you don't mind making the trait take T as a generic parameter, this is a fairly simple and straightforward equivalent solution:
trait Abst[T]{
def met1(p: T) = p.toString
def met2(p: T, f: Double=>Abst[T]){
val v = f(1.0)
v.met1(p)
}
}
case class Param(a:Int)
class MyClass(x: Double) extends Abst[Param]{
val s = met2(Param(1), (d: Double) => new MyClass(d))
}
I say it's equivalent because you're not losing any information by having met2 use the supertype instead of the subtype. The classic use case for referencing the subtype in a trait is e.g. having a method which you want to return MyClass instead of Abst even though it's defined in Abst, but that's not the situation you're in here. The only place your subtype reference is used is in the definition of f, and since function types are covariant on their output parameter you can pass any f: Double => MyClass into an f: Double => Abst[T] without problems.
If you do want to reference the subtype anyway, see Markus' answer... and if you do want to avoid having T be a generic parameter, things get a lot more complicated again, because now you have potential conflicts between the T of Abst versus the T of the subtype in the definition of met2.
To overcome this error message you have to use F-bounded polymorphism.
Your code will look somewhat like this:
trait Abst[F <: Abst[F, T], T]{ self: F =>
def met1(p: T): String = p.toString
def met2(p: T, f: Double => F): String = {
val v = f(1.0)
v.met1(p)
}
}
case class Param(a:Int)
class MyClass(x: Double) extends Abst[MyClass, Param] {
val s = met2(Param(1), (d: Double) => new MyClass(d))
}
Explanation:
Using self: F => inside of a trait or class definition constraints the value of this. So your code will not compile if this is not of type F.
We are using a cyclic type constraint of F: F <: Abst[F, T]. Though counterintuitive, the compiler does not mind it.
In the implementation, MyClass, we then extend MyClass with Abst[MyClass, Param], which in turn satisfies F <: Abst[F, T].
Now you can use F as return type of a function in Abst and have the MyClass return MyClass in the implementation.
You might think this solution is ugly, and if you do, then you're right.
Instead of using F-bounded polymorphism it's always recommended to use typeclasses for ad-hoc-polymorphism.
You will find more information about it in the link I provided earlier.
Really, read it. It will change your view on generic programming forever.
I hope this helps.
I've been experimenting with implicit conversions, and I have a decent understanding of the 'enrich-my-libray' pattern that uses these. I tried to combine my understanding of basic implicits with the use of implicit evidence... But I'm misunderstanding something crucial, as shown by the method below:
import scala.language.implicitConversions
object Moo extends App {
case class FooInt(i: Int)
implicit def cvtInt(i: Int) : FooInt = FooInt(i)
implicit def cvtFoo(f: FooInt) : Int = f.i
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
}
def dump() = {
println("first is " + first)
println("second is " + second)
}
}
val x = new Pair(FooInt(200), 100)
x.dump
x.swap
x.dump
}
When I run the above method I get this error:
Error:(31, 5) Cannot prove that nodescala.Moo.FooInt =:= Int.
x.swap
^
I am puzzled because I would have thought that my in-scope implict conversion would be sufficient 'evidence' that Int's can be converted to FooInt's and vice versa. Thanks in advance for setting me straight on this !
UPDATE:
After being unconfused by Peter's excellent answer, below, the light bulb went on for me one good reason you would want to use implicit evidence in your API. I detail that in my own answer to this question (also below).
=:= checks if the two types are equal and FooInt and Int are definitely not equal, although there exist implicit conversion for values of these two types.
I would create a CanConvert type class which can convert an A into a B :
trait CanConvert[A, B] {
def convert(a: A): B
}
We can create type class instances to transform Int into FooInt and vise versa :
implicit val Int2FooInt = new CanConvert[Int, FooInt] {
def convert(i: Int) = FooInt(i)
}
implicit val FooInt2Int = new CanConvert[FooInt, Int] {
def convert(f: FooInt) = f.i
}
Now we can use CanConvert in our Pair.swap function :
class Pair[A, B](var a: A, var b: B) {
def swap(implicit a2b: CanConvert[A, B], b2a: CanConvert[B, A]) {
val temp = a
a = b2a.convert(b)
b = a2b.convert(temp)
}
override def toString = s"($a, $b)"
def dump(): Unit = println(this)
}
Which we can use as :
scala> val x = new Pair(FooInt(200), 100)
x: Pair[FooInt,Int] = (FooInt(200), 100)
scala> x.swap
scala> x.dump
(FooInt(100), 200)
A =:= B is not evidence that A can be converted to B. It is evidence that A can be cast to B. And you have no implicit evidence anywhere that Int can be cast to FooInt vice versa (for good reason ;).
What you are looking for is:
def swap(implicit ev: T => S, ev2: S => T) {
After working through this excercise I think I have a better understanding of WHY you'd want to use implicit evidence serves in your API.
Implicit evidence can be very useful when:
you have a type parameterized class that provides various methods
that act on the types given by the parameters, and
when one or more of those methods only make sense when additional
constraints are placed on parameterized types.
So, in the case of the simple API given in my original question:
class Pair[T, S](var first: T, var second: S) {
def swap(implicit ev: T =:= S, ev2: S =:= T) = ???
def dump() = ???
}
We have a type Pair, which keeps two things together, and we can always call dump() to examine the two things. We can also, under certain conditions, swap the positions of the first and second items in the pair. And those conditions are given by the implicit evidence constraints.
The Programming in Scala book gives a nice example of how this technique
is used in Scala collections, specifically on the toMap method of Traversables.
The book points out that Map's constructor
wants key-value pairs, i.e., two-tuples, as arguments. If we have a
sequence [Traversable] of pairs, wouldn’t it be nice to create a Map
out of them in one step? That’s what toMap does, but we have a
dilemma. We can’t allow the user to call toMap if the sequence is not
a sequence of pairs.
So there's an example of a type [Traversable] that has a method [toMap] that can't be used in all situations... It can only be used when the compiler can 'prove' (via implicit evidence) that the items in the Traversable are pairs.
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.
I'm working on a small library for economic models that check the Units of the entities, using Types, e.g. instead of val apples = 2.0 we write val apples = GoodsAmount[KG, Apples](2.0). For creating bundle of goods, I trying to use HLists from the shapeless library. This works fine, but in some cases I can not be as generic code as I prefer. See e.g. the following problem.
I start with a simple code that explain what I want to lift into shapeless. We create two classes, on that represent Km, the other Miles. It should be allowed to add Km classes, but not miles. That I use a abstract type T is mainly motivated be our more complex library. And the indirect call to the '+' function is just because we need something similar in the shapeless case behind.
trait Foo {
type T
val v: Double
def +[B <: Foo](other: B)(implicit ev: this.T =:= other.T) = v + other.v
}
trait _Km
trait _Miles
case class Km(v: Double) extends Foo { type T = _Km }
case class Miles(v: Double) extends Foo { type T = _Miles }
object ExampleSimple extends App {
def add[A <: Foo, B <: Foo](a: A, b: B)(implicit ev: a.T =:= b.T) = { a + b }
add(Km(1), Km(2))
// add(Km(1), Miles(2)) /* does not compile as intended */
}
This works as intended. But it's necessary to have the Type Contraint check on the 'add' function. My attempt to extend this to HLists looks like this:
object ExampleShapeless extends App {
import shapeless._
val l1 = Km(1) :: Km(2) :: HNil
val l2 = Km(4) :: Km(3) :: HNil
object add extends Poly1 {
implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a, b) => a + b }
}
(l1 zip l2).map(add)
}
But this generate the following error message (using Scala 2.10.2):
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:50: Cannot prove that a.T =:= b.T.
[error] implicit def caseTuple[A <: Foo] = at[(A,A)] { case (a: Foo, b) => a + b }
[error] ^
[error] /home/fuerst/gitg3m/code/types/src/main/scala/lagom_d/extract.scala:54: could not find implicit value for parameter mapper: shapeless.Mapper[ExampleShapeless.add.type,shapeless.::[(Km, Km),shapeless.::[(Km, Km),shapeless.HNil]]]
[error] (l1 zip l2).map(add)
The first error should be fixed, in the case that I could add a Type Constraint to the caseTuple function, but to be honest, I have not understood how the at function is working and where I could add the implicit evidence parameter. And I'm also don't know, what I must do, so that the Mapper would find his implicit value.
A less generic version, where I replase the caseTuple function with
implicit def caseTuple = at[(Km,Km)] { case (a, b) => a + b }
works fine, but would need to write a lot of redundant code (okay, this solution would be still better as our current solution using Tuples). Can somebody give me a hint how I can solve this problem?
Thanks,
Klinke
You can require the type members to match by adding a type parameter to the case:
object add extends Poly1 {
implicit def caseTuple[_T, A <: Foo { type T = _T }] = at[(A, A)] {
case (a, b) => a + b
}
}
Or you could use an existential type, since you only really care that they're the same:
object add extends Poly1 {
implicit def caseTuple[A <: Foo { type T = _T } forSome { type _T }] =
at[(A, A)] {
case (a, b) => a + b
}
}
Either version will provide the behavior you want.