I discover a strange phenomenon:
class A {
val dual: A = this
object T {
implicit def doubleDual(t: T): dual.dual.T = t.asInstanceOf[dual.dual.T]
implicit def justForTest(t: T): Int = 777
}
class T
}
val a = new A
val t = new a.T
// import a.T._
val x: Int = t //this works!
val t1: a.dual.dual.T = t //this doesn't work!
According to implicit search rule, the method doubleDual in object T should be applied. But it doesn't. I have to import a.T._ manually. Why?
According to implicit search rule, the method doubleDual in object T should be applied.
It looks to me like the search should find two implicits: a.T.doubleDual and a.dual.dual.T.doubleDual The question is why it doesn't give "implicit conversions are not applicable because they are ambiguous" error. Maybe because they have the same name?
No, that's wrong, a.dual.dual.T.doubleDual has a wrong type. But I still suspect the problem may be related to the T object appearing twice when searching for a.T and a.dual.dual.T. It's just that this would be a compiler bug, unless I missed something else.
The key is "the same name"!
class A {
val dual: A = this
object T {
implicit def doubleDual(t: T): dual.dual.T = t.asInstanceOf[dual.dual.T]
}
class T
}
val a = new A
val t = new a.T
import a.T.doubleDual //
import a.dual.dual.T.doubleDual //the same name!
val t1: a.dual.dual.T = t // won't compile
But after rename:
import a.T.doubleDual //
import a.dual.dual.T.{doubleDual => dd} // different name!
val t1: a.dual.dual.T = t // can compile
Related
I have a generic class:
class GenericType[T] {
def func(t: T) = ???
}
I need to implement a function that takes a List[String] and outputs the corresponding GenericType[T]. For example, if a client passes in List("SomeType1", "SomeType2"), the function should return List(GenericType[SomeType1], GenericType[SomeType2]). Basically, there's a string that maps to a type.
I don't find a good way to represent the return type for such function. Seq[GenericType[_]] as the return type can be an option but it requires the client to cast it into corresponding subclasses to invoke func as the type info is lost.
Alternatively, a case class can be used but this is not flexible as I need to modify the case class every time a new subclass is added.
case class (s1: Option[GenericType[SomeType1]] = None, s2: Option[SomeType2] = None, ...)
I'm curious what's a good way to represent the return type?
The easiest is
def stringToGenericType(s: String): GenericType[_] = s match {
case "SomeType1" => new GenericType[SomeType1]
case "SomeType2" => new GenericType[SomeType2]
}
GenericType[_] (or GenericType[Any] if you make GenericType covariant: class GenericType[+T]) would be an honest return type. You can't know at compile time which specific GenericType[...] you return based on a runtime string. Anyway you can't avoid casting somewhere because you can't guarantee the type statically. Anyway this kind of programming can't be type-safe.
Since we're doing a choice based on a runtime string, compile-time techniques (macros, implicits, Shapeless) are off the table. (*)
Actually, currently you don't need even runtime reflection. Your class GenericType[T] and method func in it seem not to do anything at runtime differently depending on type T. GenericType[SomeType1] and GenericType[SomeType2] are just GenericType[_] at runtime. So even the following implementation is possible
def stringToGenericType(s: String): GenericType[_] = new GenericType[Any]
Another situation would be if you created instances of different classes
class GenericType1[T]
class GenericType2[T]
import scala.reflect.runtime
import scala.reflect.runtime.universe._
val runtimeMirror = runtime.currentMirror
def stringToGenericTypeX(s: String): Any = {
val classSymbol = runtimeMirror.staticClass(s)
val constructorSymbol = classSymbol.typeSignature.decl(termNames.CONSTRUCTOR).asMethod
runtimeMirror.reflectClass(classSymbol).reflectConstructor(constructorSymbol).apply()
}
or you called different methods
class GenericType[T] {
def func1(t: T) = ???
def func2(t: T) = ???
}
def callFuncX(methodName: String, t: Any) = {
val classSymbol = runtimeMirror.classSymbol(classOf[GenericType[_]])
val methodSymbol = classSymbol.typeSignature.decl(TermName(methodName)).asMethod
runtimeMirror.reflect(new GenericType[Any]).reflectMethod(methodSymbol).apply(t)
}
or something behaved at runtime differently depending on type T
class GenericType[T: ClassTag] {
def func(t: T) = println(classTag[T].runtimeClass)
}
import scala.tools.reflect.ToolBox
val toolbox = runtimeMirror.mkToolBox()
def stringToGenericType(s: String): GenericType[_] = {
toolbox.eval(q"new GenericType[${TypeName(s)}]").asInstanceOf[GenericType[_]]
}
(*) Well, actually the first pattern matching (as I wrote it) can be automated with a macro
// in a different subproject
import scala.language.experimental.macros
import scala.reflect.macros.blackbox
def stringToGenericType(s: String): GenericType[_] = macro stringToGenericTypeImpl
def stringToGenericTypeImpl(c: blackbox.Context)(s: c.Tree): c.Tree = {
import c.universe._
val cases = List("SomeType1", "SomeType2").map(str =>
cq"$str => new GenericType[${TypeName(str)}]"
)
q"$s match { case ..$cases }"
}
val s = "SomeTime1"
stringToGenericType(s)
// scalacOptions += "-Ymacro-debug-lite"
//s match {
// case "SomeType1" => new GenericType[SomeType1]()
// case "SomeType2" => new GenericType[SomeType2]()
//}
I have a program that can yield an abstract TypeTag when executed:
class TypeResolving extends FunSpec {
import org.apache.spark.sql.catalyst.ScalaReflection.universe._
val example = new Example
it("can convert") {
val t1 = implicitly[TypeTag[example.T]]
println(t1)
}
}
object TypeResolving {
class Example {
type T = Map[String, Int]
}
val example = new Example
}
The execution results in:
TypeTag[TypeResolving.this.example.T]
Since in this case example.T is already defined, I would also like to get the actual TypeTag:
TypeTag[Map[String,Int]]
How do I get there?
Try dealias
def dealias[T, T1](typeTag: TypeTag[T]): TypeTag[T1] = backward(typeTag.tpe.dealias)
val typeTag = implicitly[TypeTag[TypeResolving.example.T]] //TypeTag[TypeResolving.example.T]
val typeTag1 = dealias(typeTag) //TypeTag[scala.collection.immutable.Map[String,Int]]
val typeTag2 = implicitly[TypeTag[Map[String, Int]]] //TypeTag[Map[String,Int]]
val typeTag3 = dealias(typeTag2) //TypeTag[scala.collection.immutable.Map[String,Int]]
typeTag1 == typeTag3 //true
How to get the aliased type of a type alias in scala runtime?
Get a TypeTag from a Type? (backward is from here)
I am trying to migrate to the latest version of upickle 0.7.1. Where I had previously passed around implicit Readers and Writers I believe I must now use a single ReadWriter and explicitly define them in a companion object for any case classes I want to serialize. But I cannot figure out how this works for a parameterized type. So for example say I had the following before upgrading (from 0.4.4):
trait OldTrait[T] {
implicit val evr: Reader[T]
implicit val evw: Writer[T]
def save(t: T): String = write(t)
def restore(str: String): T = read[T](str)
}
class MyOldClass[T](implicit val evr: Reader[T], val evw: Writer[T]) extends OldTrait[T] {
}
case class Request[T](msg: T)
val c1 = new MyOldClass[Request[Int]]
The above code compiled fine for me. To migrate this code I have tried the following:
trait NewTrait[T] {
implicit val evrw: ReadWriter[T]
}
class MyNewClass[T](implicit val evrw: ReadWriter[T]) extends NewTrait[T] {
}
object Request {
implicit val rw: ReadWriter[Request[_]] = macroRW
}
val c2 = new MyNewClass[Request[Int]]
But this will not compile for me. I get the following errors:
Don't know how to derive type ...Request[] implicit val rw:
ReadWriter[Request[]] = macroRW
... could not find implicit value for parameter evrw:
upickle.default.ReadWriter[Request[Int]]
...not enough arguments for constructor MyNewClass: (implicit evrw:
upickle.default.ReadWriter[Request[Int]])MyNewClass[Request[Int]].
Unspecified value parameter evrw. val c2 = new
MyNewClass[Request[Int]]
What would be the correct approach to migrating the old code?
Not tested, but I would expect you need
implicit def rw[T: ReadWriter]: ReadWriter[Request[T]] = macroRW
So e.g. because there is a ReadWriter[Int], there's also a ReadWriter[Request[Int]].
(I would be very surprised if this doesn't work, but you can certainly do it manually instead of macroRW in this case.)
I am trying to support an abstraction of an ID type for a framework. Example here:
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
}
class Foo[ID] {
// ID can be String, Long, or Int
import AmINecessary._
// If ID is string, return string, otherwise convert to ID
def getID(id: String)(implicit c: StringConverter[ID] = null): ID = if (c == null) id.asInstanceOf[ID] else c.op(id)
}
This is then used as:
val fooString = new Foo[String]
val fooLong = new Foo[Long]
val fooInt = new Foo[Int]
fooString.getID("asdf") // "asdf":String
fooLong.getID("1234") // 1234:Long
fooInt.getID("1234") // 1234:Int
fooInt.getID("asdf") // java.lang.NumberFormatException
This works as expected. My questions are:
using an optional implicit by defaulting it to null then branching on it feels bad. What is the scala way to accomplish that?
Is it really necessary to write implicit conversions for a string to long or int?
I think the best option would be to simply add an implicit StringConverter[String] and remove the default null value.
That way your fooString works without risking a ClassCastException for every other type.
object AmINecessary {
case class StringConverter[T](op: String => T)
implicit val toInt = new StringConverter[Int](_.toInt)
implicit val toLong = new StringConverter[Long](_.toLong)
implicit val idConverter = new StringConverter[String](identity)
}
class Foo[ID] {
import AmINecessary.StringConverter
def getID(id: String)(implicit c: StringConverter[ID]): ID = c.op(id)
}
Regarding your question 2, the type class approach is not really necessary (but note that there are no implicit conversions here). You can also do it like this:
abstract class Foo[ID] {
def getID(id: String): ID
}
class FooInt extends Foo[Int] {
def getID(id: String) = id.toInt
}
class FooLong extends Foo[Long] {
def getID(id: String) = id.toLong
}
class FooString extends Foo[String] {
def getID(id: String) = id
}
1) About implicit defaulting to null, you could just:
object Unsafe {
implicit val toT[T] = new StringConverter[T](_.asInstanceOf[T])
}
2) It doesn't seem as a good idea. First, because you're hiding asInstanceOf, which is unsafe operation (potential runtime exception). Second, the more explicit conversion is - the better.
If you expect some complex transformations - it's better to return option from your getID method:
def getId[T](id: String)(converter: Option[StringConverter] = None) = converter.map(_.op(id))
However, default parameters aren't the best approach either. I'd stick with compile-time error requiring user to either write own converter or explicitly do an asInstanceOf, in general.
In your concrete case asInstanceOf doesn't make much sense as the only type it would work for is String, like getId[String], so what's the point of calling getId then?
I have some code like this:
class ReflectiveJsonFormat[T:TypeTag] extends JsonFormat[T] {
def write(x: T) : JsValue = {
val t = typeOf[T]
val getters = t.declarations.filter { s => s.isMethod && s.asMethod.isGetter }
val mirror = runtimeMirror(this.getClass.getClassLoader)
val instanceMiror = mirror.reflect(x)
}
}
That last line fails with:
No ClassTag available for T
I thought TypeTag was more info than a ClassTag? Can I get the ClassTag from the TypeTag? If not, is there some syntax for saying that T has two context bounds -- both TypeTag and ClassTag? Or, how would you otherwise fix this code?
The library doesn't provide a built-in method that directly converts a TypeTag to a ClassTag, but you can write one:
import reflect.runtime.universe._
import reflect.ClassTag
def typeToClassTag[T: TypeTag]: ClassTag[T] = {
ClassTag[T]( typeTag[T].mirror.runtimeClass( typeTag[T].tpe ) )
}
Then in your method just add before the implicit ClassTag is needed:
implicit val c = typeToClassTag[T]
Well scala does support multiple context bounds if that is what you are after:
class ReflectiveJsonFormat[T:TypeTag:ClassTag]