Scala: Implicit conversion of a function doesn't work - scala

I have this trait with a single method of type WSResponse => HTTPCallResult[A]
trait Parsable[A] {
def parse(response: WSResponse): HTTPCallResult[A]
}
I want to define an implicit conversion from a function WSResponse => A
object Parsable {
implicit class DefaultResponseParser[A](parser: WSResponse => A) extends Parsable[A] {
override def parse(r: WSResponse): HTTPCallResult[A] = {
//implementation
}
}
}
The desired behaviour is such, that if a function WSResponse => HTTPCallResult[A] is passed the anonymous class of Parsable[A] is automatically created. If a function of any other return type is passed (WSResponse => A) the implicit conversion is triggered.
However, an error occurs when compiling with SBT
[error] /Auth.scala:24:60: type mismatch;
[error] found : String
[error] required: HTTPCall.HTTPCallResult[?]
[error] (which expands to) scala.util.Either[String,?]
[error] .post((r: WSResponse) => (r.json \ "key").as[String])
This function was used in order to test it.
def post[A](parser: Parsable[A])
.post((r: WSResponse) => (r.json \ "key").as[String])
EDIT 1:
Even making the implicit class an implicit method and moving it to the very same scope as post didn't help.
EDIT 2:
It seems that the problem stems from the use of trait with single undefined method. Therefore when passed a function to the post method, the compiler tries to create an anonymous class of type Parser[A] from that. Due to a type missmatch it throws, without even trying to be looking for any implicits.

Related

Polymorphic return type by using TypeTag in Scala

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.

How do I get the class object of Class with type parameters in Scala?

I'm new to Scala and rusty with Java and I'm tripping up on some semantics. I'm trying to get the class object of SequenceFileOutputFormat.
Other stack overflow posts say to simple do the following:
classOf[SequenceFileOutputFormat]
Which yields the error:
class SequenceFileOutputFormat takes type parameters
Ok fine, so it requires the parameter types, so I do the following:
classOf[SequenceFileOutputFormat[String, String]]
Which yields the error:
[error] found : Class[org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat[String,String]](classOf[org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat])
[error] required: Class[_ <: org.apache.hadoop.mapred.OutputFormat[_, _]]
What gives? How do I get the class object of a class that requires type parameters?
With hadoop-mapreduce-client-core "3.0.0", this here:
import org.apache.hadoop.mapreduce.lib.output._
object HadoopQuestion_48818781 {
def main(args: Array[String]): Unit = {
val c = classOf[SequenceFileOutputFormat[_, _]]
println("Class: " + c)
}
}
prints:
Class: class org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat
Explanation:
Even though classOf[T] is processed at compile time, the Class[T] thing itself is a runtime construct, and it does not know anything about the generic type parameters of T. Therefore, you have to put underscores _ for the runtime-erased type parameters. These underscores are really just syntactic sugar for existential types in Scala, but in this particular case they fulfill a role similar to that of the wildcards in Java.

Why does var cause a type variance error where val compiles in Scala?

scala> case class Data[+T](val value:T=null)
defined class Data
scala> val foo=Data[ArrayBuffer[Data[Any]]]()
foo: Data[scala.collection.mutable.ArrayBuffer[Data[Any]]] = Data(null)
scala> foo.value+=Data[String]()
java.lang.NullPointerException
... 33 elided
I would like to have a Data class that is instantiated either as Data[String], Data[ArrayBuffer[Data[Any]]] or Data[Map[String,Data[Any]]]. In the above example I try to instantiate it as Data[ArrayBuffer[Data[Any]]] and add a Data[String] to its arraybuffer. Of course I get a null pointer exception because value is null. But the point of this example that it at least compiles and runs.
Now, in the Data constructor I would like to instantiate value as either a Data[String], an ArrayBuffer[Data[Any]] or Map[String,Data[Any]] depending on the type of the initially null value returned by the getClass method. However for this I need value to be a var, so that I can modify it after examining the type of its null value.
However I get this error:
scala> case class Data[+T](var value:T=null)
<console>:11: error: covariant type T occurs in contravariant position in type T of value value_=
case class Data[+T](var value:T=null)
Make your Data invariant in T. Just remove the +: Data[T] - this should compile.
Better yet, rethink your design to get rid of nulls and mutable variables - they both smell.
Edit: after reading your comments, I understand better what you are trying to do. Consider something like this for example as one of the options.
sealed trait Node
case class ListNode(list: Seq[Node]) extends Node
case class MapNode(map: Map[String, Node]) extends Node
case class LeafNode(data: String) extends Node
Now you can parse your document with something like (this is "pseudocode", adjust it to whatever xml-parsing library you are using):
def parseNode(tag: XMLTag): Node = tag.tagType match {
case LIST =>
val subNodes = tag.getNestedTags.map(parseNode)
ListNode(subNodes)
case MAP =>
val subNodes = tag.getNestedTags.map { tag =>
tag.name -> parseNode(tag)
}
MapNode(subNodes.toMap)
case _ =>
LeafNode(tag.text)
}
http://like-a-boss.net/2012/09/17/variance-in-scala.html#variance_and_type_safety
Variance and type safety
When defining a generic class with a var field we can get compile time errors:
scala> class Invariant[T](var t: T)
defined class Invariant
scala> class Covariant[+T](var t: T)
<console>:7: error: covariant type T occurs in contravariant position in type T of value t_=
class Covariant[+T](var t: T)
^
scala> class Contravariant[-T](var t: T)
<console>:7: error: contravariant type T occurs in covariant position in type => T of method t
class Contravariant[-T](var t: T)
Let’s break it down a little. Why doesn’t the compiler allow getters in the Covariant class?
scala> abstract trait Covariant[+T] {
| def take(t: T): Unit
| }
<console>:8: error: covariant type T occurs in contravariant position in type T of value t
def take(t: T): Unit
^
scala> abstract trait Contravariant[-T] {
| def take(t: T): Unit
| }
defined trait Contravariant
Why? Let’s think about usages of covariance let’s say that we have a class:
class Printer[+T] {
| def print(t: T): Unit = ???
| }
<console>:8: error: covariant type T occurs in contravariant position in type T of value t
def print(t: T): Unit = ???
If the print method can print Dogs does it make sense (in general) that it should also print Animals? Maybe sometimes but in the general sense if we want to generalize the Printer class we should use contravariance. The compiler is smart enough to check this type of usage for us.
Let’s think about the second use case: returning a generic parameter:
scala> class Create[-T] {
| def create: T = ???
| }
<console>:8: error: contravariant type T occurs in covariant position in type => T of method create
def create: T = ???
And again - does it make sense that Create should generalize by contravariance? If Create returns instances of the Animal class should we be able to use it in every place that expects Create[Dog]? The scala compiler is smart enough that it explodes in our face if we try it.
I can make it work this way:
package data
case class Data[+T](val value:T)
{
println(value.getClass)
}
This way I have to explicitly initialize value from the constructor. Nothing wrong with this, just I find it a bit too verbose.
import data.Data
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.Map
object Run extends App
{
val a=Data[ArrayBuffer[Data[Any]]](ArrayBuffer[Data[Any]]())
a.value+=Data[String]("bar")
println(a.value)
val m=Data[Map[String,Data[Any]]](Map[String,Data[Any]]())
m.value+=("foo"->Data[String]("bar"))
println(m.value)
}
This prints:
class scala.collection.mutable.ArrayBuffer
class java.lang.String
ArrayBuffer(Data(bar))
class scala.collection.mutable.HashMap
class java.lang.String
Map(foo -> Data(bar))
The program only compiles with Data having +T type parameter, otherwise I get the error:
type mismatch;
[error] found : data.Data[String]
[error] required: data.Data[Any]
[error] Note: String <: Any, but class Data is invariant in type T.
[error] You may wish to define T as +T instead. (SLS 4.5)
[error] a.value+=Data[String]("bar")

Implicit class for overriding String.toBoolean

I tried following this answer, but it did not help. Here's the implementation I have.
implicit class MyString(s: String) {
override def toBoolean = s.trim.toLowerCase match {
case "true" | "t" | "1" => true
case _ => false
}
}
And the error I am getting is:
[error] found : s.type (with underlying type String)
[error] required: ?{def toBoolean: ?}
[error] Note that implicit conversions are not applicable because they are ambiguous:
[error] both method augmentString in object Predef of type (x: String)scala.collection.immutable.StringOps
[error] and method MyString in trait ImplicitsStartingWithS of type (s: String)foo.MyString
[error] are possible conversion functions from s.type to ?{def toBoolean: ?}
[error] case Some(s) => s.toBoolean
[error] ^
I can't seem to find what's wrong with the code.
Other than the fact that toBoolean does not override anything, your implementation is fine. However, as the compiler error helpfully indicates, the name of your method clashes with the toBoolean method in the automatically imported StringOps class in Predef. As a result, there is more than one implicit conversion that could be applied and the compiler cannot decide which one to use. This is why the error indicates that there is ambiguity. The solution is to name your method differently, so the following should work.
implicit class MyString(s: String) {
def toBooleanAlt = s.trim.toLowerCase match {
case "true" | "t" | "1" => true
case _ => false
}
}
First, note that implicit conversions can't override methods in the type being converted from: if such a method exists, the compiler simply won't look for the implicit! There is a fork of Scala called Scala-Virtualized which does allow this (you'd define a method infix_toBoolean(x: String)), but I'd recommend against it for general usage: if you can't live without this feature check it out.
In this case, as #moem's answer says, the toBoolean isn't actually defined on String. As an alternative to simply giving a different name to your toBoolean, you can also explicitly hide augmentString in a class by defining something else with this name: def augmentString = ??? or
class MyString(s: String) {
def toBoolean = s.trim.toLowerCase match {
case "true" | "t" | "1" => true
case _ => false
}
}
implicit def augmentString(s: String) = new MyString(s)
Of course, this loses all other methods provided by this implicit as well, but you can provide them in MyString (e.g. by extending StringOps).

Pass type information at runtime

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.