Im reading this page http://www.scala-lang.org/node/137, I understand what covariance is and lower bounds as well, but what it's not clear is this line:
Unfortunately, this program does not compile, because a covariance
annotation is only possible if the type variable is used only in
covariant positions. Since type variable T appears as a parameter type
of method prepend, this rule is broken.
why elem has to be an instance of a supertype of T, if ListNode is already covariant why elem cannot be prepended to the current list.
class Super {override def toString = "Super"}
class Sub extends Super {override def toString = "Sub"; def subMethod {} }
val sup = new Super
val sub = new Sub
Imagine the following were allowed:
// invalid code
class Foo[+T] {
def bar(x: T) = println(x)
}
Since Foo is covariant on T, this is valid (a simple upcast, since a Foo[Sub] is a Foo[Super]):
val foo : Foo[Super] = new Foo[Sub] {
override def bar(x: Sub) = x.subMethod
}
Now foo is, as far as we know, a Foo[Super] like any other, but its bar method won't work, because the bar implementation requires a Sub:
foo.bar(sup) // would cause error!
Related
Given a trait:
# trait Foo {
def withStuffAdded(str: String): Foo
}
defined trait Foo
I then defined a sub-class of Foo:
# class X(val str: String) extends Foo {
override def withStuffAdded(s: String): Foo = new X(str + s)
}
defined class X
Finally, I tried to define this function:
# def something(x: X): X = x.withStuffAdded("something")
cmd3.sc:1: type mismatch;
found : ammonite.$sess.cmd1.Foo
required: ammonite.$sess.cmd2.X
def something(x: X): X = x.withStuffAdded("something")
^
Compilation Failed
The compiler fails as it expected a Foo to be returned, not an X.
How can I change the definition of Foo#withStuffAdded to compile, i.e. return a sub-type of Foo in the type signature?
Luis' comment is perfectly valid. I'll try explaining how to arrive to the solution mentioned in the comment.
If I got this right, you are actually interested in having the subclass as a result type in the subclass' method, but since your trait definition does not allow it, you are forced to return a Foo in method withStuffAdded of class X.
Although not obvious, this sounds like a code smell. Perhaps an abstract type is what are you looking for to begin with, to loosen up the design and allow your requirement to comply:
trait Foo {
type T <: Foo
def withStuffAdded(str: String): T
}
class X(val str: String) extends Foo {
type T = X
override def withStuffAdded(s: String): X = new X(str + s)
}
Now this will work:
def something(x: X): X = x.withStuffAdded("something")
Although a flexible design, from here on, it becomes clearer that in order to further improve on it, possible solutions include either using f-bounded polymorphism or a typeclass.
I would probably be inclined to use a typeclass as this is the functional way. What you'll need depends on your requirements, but either will work.
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 the following simple test-case:
trait Printable[T] {
val string: String
def print() = println("It works: " + string)
}
def foo[T](x: T)(implicit ev: T => Printable[T]) = {
x.print()
}
implicit def doubleToPrint(x: Double): Printable[Double] = new Printable[Double] {
override val string: String = x.toString
}
foo(2.0) // => It works: 2.0
However, creating a new function bar[T](x: T) which should call foo(x) raises an error that there is no implicit view available from T => Printable[T] :
// this does not work
def bar[T](x: T) = {
println("Some other stuff")
foo(x)
}
However, when adding the same parameter it works ofcourse:
// this does work
def bar[T](x: T)(implicit ev: T => Printable[T]) = {
println("Some other stuff")
foo(x)
}
It seems to me quite cumbersome to keep chaining these implicit parameters, because I was under the assumption that the foo function will start searching for the implicit conversion and not the function bar calling foo. As I understand the implicit def doubleToPrint should be in scope for foo also when it is being called from within foo.
What am I overlooking?
Additional question in response to the answer of dth
So I understand the answer, which is actually very logical.
However, the solution of the context bounds does not work in the situation where foo and bar are both part of another trait, since context bounds are not allowed in traits:
// not allowed to do trait FooBar[T : Printable]
trait FooBar[T] {
def foo(x: T)(implicit ev: T => Printable[T]) = {
println("Running foo...")
x.print()
}
// this is not allowed
def bar(x: T) = {
println("But running bar first...")
foo(x)
}
}
So is it also possible to solve this without using the implicit parameter?
My own, not so nice, solution
I came to the conclusion that I actually don't need a trait in my specific code and can replace the FooBar[T] trait with an abstract class FooBar[T <% Printable[T]].
It is a solution for my problem, but not the additional question I added.
Think about, how implicit parameters work:
When you call a method requiring an implicit parameter somewhere the compiler looks in the context (scope, involved types) for a suitable implicit.
Now look at your definition of bar:
def bar[T](x: T) = {
foo(x)
}
When you call foo the compiler looks for an implicit value of the type T => Printable[T] which it cannot find. It does not matter, that you will call bar later with a type Double as it does not know that.
So the answer is yes, you have to pass implicit parameters around everywhere, where you can not find a suitable value in the context (so usually everywhere, where you do not know the concrete type).
There is however syntactic sugar called context bounds, so you can define bar like this:
def bar[T: Printable](x: T) = foo(x)
You could also define foo like this and use implicitly[Printable[T]] to access the values. So you do not have to concern yourself with implicit parameters at all in simple setting like this.
Traits
Context bounds are just syntactic sugar for an implicit parameter. The implicit value is passed where you define the type bound. I.e. if it is the type parameter of a method it is passed to the method.
A trait may not have any constructor parameters as due to linearisation you do not no where it will end up in the inheritance hierarchy. Thus it may not have any implicit parameters or type bounds either.
So you really have to add an implicit parameter to both methods.
If you are implementing some complex API this is fine, if this appears a lot in user code, maybe you can change your design.
Classes
You can use context bounds for type parameters of classes, however the implicit parameter will not be directly used inside of methods of that class. To achieve that you have to provide a local implicit conversion like this:
class FooBar[T: Printable] {
implicit def conv(x: T) = implicitly[Printable[T]]
def foo(x: T) = {
println("Running foo...")
x.print()
}
def bar(x: T) = {
println("But running bar first...")
foo(x)
}
}
View Bounds
There are also view bounds as an alternative. They have however been deprecated. If you run scalac with -Xfuture it will show you that.
The problem here is the type T.
Means, that without
(implicit ev: T => Printable[T])
the compiler tries to find an implicit that would work for any type of T
which he can not, because there is an implicit only for Double.
But if you add
(implicit ev: T => Printable[T])
the compiler tries to find the implicit at the place you call bar.
And if you call it with a Double parameter he takes doubleToPrint and passes it by.
A case classes copy() method is supposed to make an identical copy of the instance, plus replacing any fields by name. This seems to fail when the case class has type parameters with manifests. The copy loses all knowledge of the types of its parameters.
case class Foo[+A : Manifest](a: A) {
// Capture manifest so we can observe it
// A demonstration with collect would work equally well
def myManifest = implicitly[Manifest[_ <: A]]
}
case class Bar[A <: Foo[Any]](foo: A) {
// A simple copy of foo
def fooCopy = foo.copy()
}
val foo = Foo(1)
val bar = Bar(foo)
println(bar.foo.myManifest) // Prints "Int"
println(bar.fooCopy.myManifest) // Prints "Any"
Why does Foo.copy lose the manifest on the parameters and how do I make it retain it?
Several Scala peculiarities interact to give this behavior. The first thing is that Manifests are not only appended to the secret implicit parameter list on the constructor but also on the copy method. It is well known that
case class Foo[+A : Manifest](a: A)
is just syntactic sugar for
case class Foo[+A](a: A)(implicit m: Manifest[A])
but this also affects the copy constructor, which would look like this
def copy[B](a: B = a)(implicit m: Manifest[B]) = Foo[B](a)(m)
All those implicit ms are created by the compiler and sent to the method through the implicit parameter list.
This would be fine as long as one was using the copy method in a place where the compiler knew Foos type parameter. For example, this will work outside of the Bar class:
val foo = Foo(1)
val aCopy = foo.copy()
println(aCopy.myManifest) // Prints "Int"
This works because the compiler infers that foo is a Foo[Int] so it knows that foo.a is an Int so it can call copy like this:
val aCopy = foo.copy()(manifest[Int]())
(Note that manifest[T]() is a function that creates a manifest representation of the type T, e.g. Manifest[T] with a capital "M". Not shown is the addition of the default parameter into copy.) It also works within the Foo class because it already has the manifest that was passed in when the class was created. It would look something like this:
case class Foo[+A : Manifest](a: A) {
def myManifest = implicitly[Manifest[_ <: A]]
def localCopy = copy()
}
val foo = Foo(1)
println(foo.localCopy.myManifest) // Prints "Int"
In the original example, however, it fails in the Bar class because of the second peculiarity: while the type parameters of Bar are known within the Bar class, the type parameters of the type parameters are not. It knows that A in Bar is a Foo or a SubFoo or SubSubFoo, but not if it is a Foo[Int] or a Foo[String]. This is, of course, the well-known type erasure problem in Scala, but it appears as a problem here even when it doesn't seem like the class is doing anything with the type of foos type parameter. But it is, remember there is a secret injection of a manifest every time copy is called, and those manifests overwrite the ones that were there before. Since the Bar class has no idea was the type parameter of foo is, it just creates a manifest of Any and sends that along like this:
def fooCopy = foo.copy()(manifest[Any])
If one has control over the Foo class (e.g. it's not List) then one workaround it by doing all the copying over in the Foo class by adding a method that will do the proper copying, like localCopy above, and return the result:
case class Bar[A <: Foo[Any]](foo: A) {
//def fooCopy = foo.copy()
def fooCopy = foo.localCopy
}
val bar = Bar(Foo(1))
println(bar.fooCopy.myManifest) // Prints "Int"
Another solution is to add Foos type parameter as a manifested type parameter of Bar:
case class Bar[A <: Foo[B], B : Manifest](foo: A) {
def fooCopy = foo.copy()
}
But this scales poorly if class hierarchy is large, (i.e. more members have type parameters, and those classes also have type parameters) since every class would have to have the type parameters of every class below it. It also seems to make the type inference freak out when trying to construct a Bar:
val bar = Bar(Foo(1)) // Does not compile
val bar = Bar[Foo[Int], Int](Foo(1)) // Compiles
There are two problems as you identified. The first problem is the type erasure problem inside of Bar, where Bar doesn't know the type of Foo's manifest. I would personally use the localCopy workaround you suggested.
The second issue is that another implicit is being secretly injected into copy. That issue is resolved by explicitly passing the value again into the copy. For example:
scala> case class Foo[+A](a: A)(implicit val m: Manifest[A #uncheckedVariance])
defined class Foo
scala> case class Bar[A <: Foo[Any]](foo: A) {
| def fooCopy = foo.copy()(foo.m)
| }
defined class Bar
scala> val foo = Foo(1)
foo: Foo[Int] = Foo(1)
scala> val bar = Bar(foo)
bar: Bar[Foo[Int]] = Bar(Foo(1))
scala> bar.fooCopy.m
res2: Manifest[Any] = Int
We see the copy has kept the Int manifest but the type of fooCopy and res2 is Manifest[Any] due to erasure.
Because I needed access to the implicit evidence to do the copy I had to use the explicit implicit (hah) syntax instead of the context bound syntax. But using the explicit syntax caused errors:
scala> case class Foo[+A](a: A)(implicit val m: Manifest[A])
<console>:7: error: covariant type A occurs in invariant position in type => Manifest[A] of value m
case class Foo[+A](a: A)(implicit val m: Manifest[A])
^
scala> case class Foo[+A](a: A)(implicit val m: Manifest[_ <: A])
defined class Foo
scala> val foo = Foo(1)
<console>:9: error: No Manifest available for Int.
WTF? How come the context bound syntax works and the explicit implicit doesn't? I dug around and found a solution to the problem: the #uncheckedVariance annotation.
UPDATE
I dug around some more and found that in Scala 2.10 case classes have been changed to only copy the fields from the first parameter list in copy().
Martin says: case class ness is only bestowed on the first argument
list the rest should not be copied.
See the details of this change at https://issues.scala-lang.org/browse/SI-5009.
I would like to define a method parameterized with type T that has behavior dependent on what implicit argument can be found of type Box[T]. The following code has this method defined as foo. When called with foo[Int] or foo[String] it will without issue return 1 or "two" as expected.
Where things get weird is with the method bar. It is defined as returning an Int, but instead of foo[Int] I have just foo. My hope was that the compiler would infer that T must be of type Int. It does not do that and instead fails:
bash $ scalac Code.scala
Types.scala:15: error: ambiguous implicit values:
both value one in object Main of type => Main.Box[Int]
and value two in object Main of type => Main.Box[java.lang.String]
match expected type Main.Box[T]
def bar: Int = foo
^
one error found
What is causing this error? Replacing foo with foo[Int] compiles fine. The simpler situation where there is no Box[T] type also compiles fine. That example is also below and uses argle and bargle instead of foo and bar.
object Main extends Application {
case class Box[T](value: T)
implicit val one = Box(1)
implicit val two = Box("two")
def foo[T](implicit x: Box[T]): T = {
x.value
}
// does not compile:
// def bar: Int = foo
// does compile
def bar: Int = foo[Int]
println(bar)
// prints 1
// the simpler situation where there is no Box type
implicit val three = 3
implicit val four = "four"
def argle[T](implicit x: T): T = x
def bargle: String = argle
println(bargle)
// prints "four"
}
What is going on in this snippet that causes this behavior? What about this interaction of implicit arguments, type inference, and erasure is causing problems? Is there a way to modify this code such that the line def foo: Int = bar works?
Someone else will have to explain why the type inference mechanism cannot handle that case, but if you are looking to cleanup your code you could probably do this:
object Test extends App {
case class Box[T](value: T)
implicit val one: Box[Int] = Box(1)
implicit val two: Box[String] = Box("two")
def foo[T : Box]: T = implicitly[Box[T]].value
val bar = foo[Int]
}
Note that:
I removed the type annotation from bar so you are really just indicating the type once (just in a different spot than you wanted)
I am using App instead of deprecated Application
Using a context bound in the type signature of foo
This might be related to SI-3346, though there it is implicit arguments to implicit conversions, and here you have a single implicit.