Why asInstanceOf doesn't initiate implicit conversion? [duplicate] - scala

This question already has answers here:
What are the differences between asInstanceOf[T] and (o: T) in Scala?
(4 answers)
Closed 8 years ago.
I have a case class with a companion object.
I have implicit conversion method inside the companion object.
case class Foo(p:T)
object Foo {
implicit def Foo2Bar(foo: Foo): Bar = new Bar(doSmth(foo.p))
}
I have a method with a param of type Object. I want to pass an instance of Bar there.
Unfortunatelly, the following code doesn't do the conversion but throws ClassCastException:
import Foo._
...
val foo = createFoo()
bazz(foo.asInstanceOf[Bar])
At the same time, the next (more verbose) code do the job:
import Foo._
...
val foo = createFoo()
val bar: Bar = foo
bazz(bar)
Any ideas why the former code doesn't work?

asInstanceOf deals only with subtype relationships, but defining an implicit conversion doesn't create a subtype relationship.

Related

can scala implicit convert from `Long` to `AnyRef` [duplicate]

This question already has answers here:
Result type of an implicit conversion must be more specific than AnyRef
(4 answers)
Closed 4 years ago.
def testLong(v: Any): Unit = {
println(v.getClass) // print: class java.lang.Long
}
testLong(103L) // compile passed
from last snippet, it shows that the variable v is class java.lang.Long.And it's a subclass of java.lang.Object.
We also know from the scala Unified types system the AnyRef is equals to java.lang.Object type. But why it compile failed as follows:
def testLong(v: AnyRef): Unit = {
println(v.getClass)
}
testLong(103L) // compile failed
Probably the reason why the implicit conversion was not used in the second example is because this:
// val l: AnyRef = 10L
// error: the result type of an implicit conversion must be more specific than AnyRef.
This answer may explain welll why this happens.
However, you can re-write your method for make it work using an implicit evidence.
def testLong[T](v: T)(implicit ev: T => AnyRef): Unit = {
println(v.getClass)
}
testLong(10L)
// class java.lang.Long
Curious enough, if you make the method specific to Long only, the printed class changes.
def testLong(v: Long)(implicit ev: Long => AnyRef): Unit = {
println(v.getClass)
}
testLong(10L)
// long

What does [+A] mean in Scala class declaration? [duplicate]

This question already has answers here:
Why doesn't the example compile, aka how does (co-, contra-, and in-) variance work?
(4 answers)
Closed 7 years ago.
In scala Option class is declared like
sealed abstract class _Option[+A]
case object _None extends _Option[Nothing] {}
final case class _Some[+A](x: A) extends _Option[A] {}
What is [+A]? Why not just [A]? Could it be [-A] and what it would mean?
Sorry if it is a duplicate but I couldn't find the answer on SO.
It declares the class to be covariant in its generic parameter. For your example, it means that Option[T] is a subtype of Option[S] if T is a subtype of S. So, for example, Option[String] is a subtype of Option[Object], allowing you to do:
val x: Option[String] = Some("a")
val y: Option[Object] = x
Conversely, a class can be contravariant in its generic parameter if it is declared as -A.
Read above variances in Scala in the docs here.

Scala: How to make case class copy keep manifest information

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.

Why does Scala's type inferencer fail with this set of implicit arguments involving parameterized types?

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.

Use of abstract type in a concrete class? [duplicate]

This question already has answers here:
Concrete classes with abstract type members
(2 answers)
Closed 9 years ago.
scala> class A { type T <: String; def f(a: T) = println("foo")}
defined class A
scala> (new A).f("bar")
<console>:9: error: type mismatch;
found : java.lang.String("bar")
required: _1.T where val _1: A
(new A).f("bar")
^
Class A has an abstract type T, but is not an abstract class. Creating an object of A (as shown) does not define type T.
My first thought was, I am allowed to pass any type as T which is a subclass of String, but I am not. So what type actually is T in the object and what am I allowed to pass through ?
As you say, T in A is abstract; therefore you won't find any value you can put into method f, until you have a subtype of A which actually fixes T.
(new A { type T = String }).f("bar")
The idea is that the type can be successively refined:
trait Var[A] { def get: A; def set(v: A): Unit }
trait Sys {
type V[A] <: Var[A]
def swap[A](x: V[A], y: V[A]): Unit = {
val tmp = x.get
x.set(y.get)
y.set(tmp)
}
}
trait HistVar[A] extends Var[A] { def created: java.util.Date }
trait HistSys extends Sys {
type V[A] <: HistVar[A]
def newest[A](x: V[A], y: V[A]): A =
if (x.created after y.created) x.get else y.get
}
But of course you're question is good -- there is no reason why you would want a concrete instantiation of a class whose type parameter is not fixed. I can't think of a case where that makes sense. (Well of course, you could still have functionality that is accessible, if it does not involve type T)
Further searching finds the following, quasi duplicate, SO question. You can find there a reference to a Scala ticket which outlines it as a 'feature' -- still doesn't show a case where this 'feature' is actually useful :)