I am trying to modify the Enterprise trait that extends the StarShip type.
(I apologize in advance for not knowing a proper title for this but I will update it after I understand the answer.)
For some reason I cannot get the parameters of the starShip that is passed.
I commented where I am getting the error.
Simple example to demonstrate this:
object Test {
trait Akira extends StarShip
trait Enterprise extends StarShip
sealed trait StarShip {
val captain: String
}
def doSomething[T: StarShip](starShip: T): T =
new T {
val captain = starShip.captain // Error: Cannot resolve symbol
}
doSomething(new Enterprise {
override val captain = "Picard"
})
}
Since I am passing an object of Enterprise I expect to get the same class out.
Edit:
Just realized that I want all variables in the starShip that is passed to be copied to the new class. With the exception that I will modify a few of them.
I believe the Monocle lib may solve my problem.
When I compile your code with the scala REPL, I get this:
<console>:17: error: Test.StarShip does not take type parameters
def doSomething[T: StarShip](starShip: T): T =
^
<console>:18: error: class type required but T found
new T {
^
<console>:19: error: value captain is not a member of type parameter T
val captain = starShip.captain // Error: Cannot resolve symbol
^
<console>:18: error: type mismatch;
found : T{}
required: T
new T {
^
As #dcastro mentioned, you probably wanted a type bound on T. However, even fixing that syntactical error isn't good enough because:
scala> def doSomething[T <: StarShip](starShip : T) : T = new T { val captain = starShip.captain }
<console>:8: error: class type required but T found
It is not possible to instantiate an object from a type parameter because the compiler does not know the actual type to instantiate until runtime. It could be anything, including a type written after the compilation of this function.
Based on your invocation of doSomething, I don't think you want the type parameter or the instantiation at all. That is, this works:
scala> def doSomething[T <: StarShip](starShip : T) : T = { val captain = starShip.captain; starShip }
doSomething: [T <: StarShip](starShip: T)T
scala> doSomething(new Enterprise { val captain = "Kirk" })
res0: Enterprise = $anon$1#26653222
So, I think with the above adjustments you have accomplished your goal. You've modified your trait (StarShip) by insantiating an Enterprise with an overriden value for the captain member.
Related
What I want to do is returning generics type in Scala function by using TypeTag. Here is the example code.
trait Parent[T]
object IntChild extends Parent[Int]
object StringChild extends Parent[String]
object SomeClass {
def of[A: TypeTag]: Parent[T] = {
getElementType[A] match {
case Int => IntChild
case String => StringChild
}
}
}
SomeClass.of[Array[Int]]
But it throws a compile error. Because the returned type of of method is not fixed in the compile type. Is there any way to get the type information from TypeTag and embed the type in the returned type?
What I am expecting is like
// T is inferred from TypeTag A.
def of[A: TypeTag, T]: Parent[T] = {
//...
}
I found this code also has not passed compile. So we need to fix the type information inferred from A's TypeTag.
def of[A: TypeTag]: Parent[_] = {
//...
}
This is the error.
type mismatch;
[error] found : Array[Int]
[error] required: Array[_$1]
How can I get the element type in advance?
I'm not sure it's possible with those definitions. How about changing the definitions a little?
trait Parent[T]
implicit object IntChild extends Parent[Int]
implicit object StringChild extends Parent[String]
object SomeClass {
def of[A: Parent]: Parent[A] = implicitly
}
This makes sure everything is done at the type level so that you get the return type you want. It requires the implicit modifier on IntChild and StringChild. There's no need to have another type parameter named T, as it would always be the same as A in your example.
Here is my code straight & simple:
package scalaproj
import scala.reflect._
case class MyClass() {}
def bar[T](cls : Class[T]) = println(cls)
def foobar[T: ClassTag] = println(classTag[T])
bar(classOf[MyClass])
foobar[MyClass]
Results: class scalaproj.GetFields$MyClass$2
scalaproj.GetFields$MyClass$2
Now I would like to do the following without the famous error: "class type required but T found"
def foo[T] = println(classOf[T])
foo[MyClass]
foo is just a function that takes a Generic Type Parameter and does not need a value parameter. I think this is strange given the two examples that work and all the flexibility build in into the Scala language and its handeling of generics.
Update:
Just to specify further strangeness:
def foo1[T](t : T) = {} // no compile error
def foo2[T](): List[T] = { List[T]() } // no compile error
def foo3[T](): T = { T() } // compile error: "not found: value T"
A good explanation is appreciated.
You can't, as classOf will not work with arbitrary types (and your T is an arbitrary type).
For example:
scala> classOf[Int with String]
<console>:15: error: class type required but Int with String found
classOf[Int with String]
^
You can achieve the same thing with ClassTag#runtimeClass:
def foo[T: ClassTag] = println(classTag[T].runtimeClass)
I´m trying to create an implicit class using generic, here the class
object Utils {
implicit class optionUtils(option: Option[Any]) {
def sortedList[T]:List[T] = {
val list:List[T] = option.get.asInstanceOf[List[T]]
list.sorted[T]
}
}
}
And here the invocation
jsonResponse.get("products").sortedList[String]
But seems like sorted is not compiling, and the compiler says.
Error:(8, 18) not enough arguments for method sorted: (implicit ord: scala.math.Ordering[T])List[T].
Unspecified value parameter ord.
list.sorted[T]
^
Any idea how to make it works?.
Regards.
You have to tell the compiler that T is restricted to an order-able type.
def sortedList[T: Ordering]:List[T] = { ...
I have a DSL and some runtime code. The problem is I got somewhere at runtime:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
and I have a class
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass
}
val wrapper = new MyWrapper(value)
The problem is I need to return java.lang.String from a call of toString. But I got java.io.Serializable. Unfortunately I am neither able to create fixed pattern matching for each java.io.Serializable subtype (this would be crazy) nor to create MyWrapper explicit with new MyWrapper[String](value). I don't know the type of value, maybe it is a subtype of Serializable.
Is there some way to pass type/manifest value at runtime if I know that value type is equal to variable clazz?
Update (solution from Régis Jean-Gilles don't work). REPL test:
val clazz: Class[_ <: java.io.Serializable] = classOf[java.lang.String]
val value: java.io.Serializable = "abc"
class MyWrapper[T <: java.io.Serializable](val data: T)(implicit m: Manifest[T]) {
override def toString = m.runtimeClass.getName
}
val wrapper = new MyWrapper(value)
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz).asInstanceOf[ClassTypeManifest[java.io.Serializable]])
//val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
System.err.println(wrapper.toString)
I got an error, if I tried to pass manifest explicit:
scala> :load test.scala
Loading test.scala...
clazz: Class[_ <: java.io.Serializable] = class java.lang.String
value: java.io.Serializable = abc
defined class MyWrapper
<console>:10: error: type mismatch;
found : scala.reflect.ClassManifest[_$1] where type _$1 <: java.io.Serializable
(which expands to) scala.reflect.ClassTag[_$1]
required: Manifest[java.io.Serializable]
val wrapper = new MyWrapper(value)(ClassManifest.fromClass(clazz))
^
<console>:8: error: not found: value wrapper
System.err.println(wrapper.toString)
Also I am unable to cast manifest explicit.
There is more strange error when I try to compile my application -
[error] found : scala.reflect.ClassManifest[(some other)_0(in method setProperty)]
[error] (which expands to) scala.reflect.ClassTag[(some other)_0(in method setProperty)]
[error] required: Manifest[_0(in method setProperty)]
[error] new Value.Static(default, Context.virtual(element))(ClassManifest.fromClass(elementProperty.typeClass)))
IMHO Régis Jean-Gilles very very close to solution. How to make it work with Scala 2.10?
If I understand correctly, you are using manifests to work around type erasure but at a specific point all you have is a Class[_] so you need to convert it back to a manifest. Correct?
If so, you can use ClassManifest.fromClass, and then explicitly pass it as the implicit value m.
val wrapper = new MyWrapper(value)(Manifest.classType(clazz))
You should probably abstract it away:
object MyWrapper {
def fromRuntimeType[T <: java.io.Serializable]( value: T ): MyWrapper[T] = {
new MyWrapper(value)(Manifest.classType(value.getClass))
}
}
Keep in mind though that because you only have a Class instance in the first place, you are at the mercy of type erasure again. This means that if the class (that you need to get a manifest for) is generic, you won't have any type parameter information in the manifest returned by ClassManifest.fromClass.
Wouldn't
override def toString = data.getClass.getName
already work for you? That yields java.lang.String.
The question is why doesn't the following code work with type inference (below is a REPL session to demonstrate), and can it be fixed? More specifically, how is this different from the use of CanBuildFrom which the compiler uses to infer the return type?
Given this code:
object S {
import java.net._
trait UrlLike[T] {
def url(s: String): T
}
object UrlLike {
implicit object str extends UrlLike[String]{def url(s: String) = s}
implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
}
trait UrlSupport {
val _url: String
def url[T : UrlLike]: T = implicitly[UrlLike[T]].url(_url)
}
}
I have this session in the REPL (2.8.1):
scala> :load c:\temp\UrlTest.scala
Loading c:\temp\UrlTest.scala...
defined module S
scala> import java.net._
import java.net._
scala> import S._
import S._
scala> new UrlSupport{val _url = "http://example.com"}
res0: java.lang.Object with S.UrlSupport = $anon$1#155bd22
scala> res0.url : String
<console>:14: error: ambiguous implicit values:
both object uri in object UrlLike of type object S.UrlLike.uri
and object url in object UrlLike of type object S.UrlLike.url
match expected type S.UrlLike[T]
res0.url : String
^
scala> res0.url : URL
<console>:14: error: ambiguous implicit values:
both object uri in object UrlLike of type object S.UrlLike.uri
and object url in object UrlLike of type object S.UrlLike.url
match expected type S.UrlLike[T]
res0.url : URL
^
scala> res0.url[String]
res3: String = http://example.com
scala> res0.url[URL]
res4: java.net.URL = http://example.com
I can see why you'd expect it to work, but, obviously, the type inferencer isn't using the return type to infer T. I'd expect it too as well.
As for the ambiguity, CanBuildFrom avoids being ambiguous by just not defining everything in the same "level". For instance, this solves the ambiguity problem:
trait LowPriorityImplicits {
implicit object url extends UrlLike[URL]{def url(s: String) = new URL(s)}
implicit object uri extends UrlLike[URI]{def url(s: String) = new URI(s)}
}
object UrlLike extends LowPriorityImplicits {
implicit object str extends UrlLike[String]{def url(s: String) = s}
}
However, it will not make the type inference work the way you want:
scala> res0.url : URL
<console>:16: error: type mismatch;
found : String
required: java.net.URL
res0.url : URL
^
Which indicates it obviously makes T inference without taking into consideration the return type.
> trait UrlLike[T] {
trait UrlLike[+T] {
Regarding any implicit ambiguity, the rule is (since Scala2.8):
When comparing two different applicable alternatives of an overloaded method or of an implicit, each method:
gets one point for having more specific arguments,
and another point for being defined in a proper subclass.
An alternative “wins” over another if it gets a greater number of points in these two comparisons.
This means in particular that if alternatives have identical argument types, the one which is defined in a subclass wins.
I don't think the implicits around URL or URI get a different set of points following those criteria.
It might not be obvious from the error report that you're seeing, but all three of the implicits defined in object UrlLike are contributing to the ambiguity (eg. try commenting out the definition of uri and you'll see the ambiguity reported as being between str and url).
The reason for the ambiguity is that the type parameter T of UrlSupport.url is bounded only by the requirement that there be an implicit UrlLike instance available for it. String, URL and URI all satisfy that requirement equally well thanks the UrlLike instances provided by your three implicit objects. The compiler isn't going to choose one of those for you arbitrarily, so it reports an ambiguity.
Unless, of course, you resolve the ambiguity by explicitly specifying the type argument, as you've done in the last two of your REPL interactions.