Scala implicit conversion problem - scala

I am struggling with a Scala implicit conversion problem. The following code snippet illustrates my problem :
import org.junit.{ Test, Before, After };
class ImplicitsTest {
implicit def toStringWrapper(str: String) = new StringWrapper(str);
#Test
def test(){
val res1: Predicate = "str" startsWith "other";
}
}
class StringWrapper(str: String){
def startsWith(other: String): Predicate = null;
}
trait Predicate
How can I force the String literal "str" to be converted through the implicit conversion toStringWrapper to get startsWith return Predicate instead of Boolean?
The code example doesn't compile. I am aware that String has already a startsWith method, I just want to use a different one, and I thought that using implicit conversions might be a way to do it.

Scala thankfully doesn't let you sneak replacement methods in without you noticing--if you call a method on a class, and the class has that method, that's the method call you get. To do otherwise would likely cause all sorts of confusion.
That leaves you with two other options:
(1) Rename the method
(2) Add a specific method to do the conversion.
The second approach works like so: you define a class that has both the method that you want and a uniquely-named method that returns itself, and optionally an implicit conversion from that class back to string if you want to be able to use the custom item like the original string (as if it had extended String):
object ImplicitExample {
class CustomString(s: String) {
def original = s
def custom = this
def startsWith(other: String): Int = if (s.startsWith(other)) 1 else 0
}
implicit def string_to_custom(s: String) = new CustomString(s)
implicit def custom_to_string(c: CustomString) = c.original
def test = {
println("This".custom.startsWith("Thi"))
println("This".custom.length())
}
}
scala> ImplicitExample.test
1
4
scala>

An implicit conversion is triggered in Scala only if the receiver does not contain the method being invoked or if an expression has a type different than the expected type.
Since the String object above contains the method startsWith, no implicit conversion is triggered. The compiler does, however, check if the type of the right hand expression "str".startsWith("other"); (that is Boolean) can be converted to a Predicate. Since there is no such implicit conversion in scope, it reports an error.
Note, also, that implicit conversions must be unambiguous. For instance, you might try to override Scala string behaviour for some other methods using implicit conversions. Java String objects are not Scala sequences (Seq), meaning that they do not have methods such as sorted, which returns the sorted version of the sequence. If you invoke it on a string:
scala> "string" sorted
res1: String = ginrst
This works because an implicit conversion defined in the Predef object gets triggered. Note that providing your own implicit conversion results in an error:
scala> implicit def wrap(s: String) = new { def sorted = "Hi!" }
wrap: (s: String)java.lang.Object{def sorted: java.lang.String}
scala> "string" sorted
<console>:7: error: type mismatch;
found : java.lang.String
required: ?{val sorted: ?}
Note that implicit conversions are not applicable because they are ambiguous:
...

Related

Why can't I reuse "unapply" without repeating the method signature

The following Scala code compiles fine:
val f = (input: String) => Some("result")
object Extract {
def unapply(input: String): Option[String] = f(input)
}
val Extract(result) = "a string"
But if I replace the extractor by:
object Extract {
def unapply = f
}
Then compilation fails with:
error: an unapply result must have a member `def isEmpty: Boolean
val Extract(result) = "a string"
^
Why? Where does def isEmpty: Boolean come from?
In Scala 2.10 (and before) unapply had to always return an Option or a Boolean. Since 2.11, it can return any type, so far as it has def isEmpty: Boolean and def get: <some type> methods (like Option does). See https://hseeberger.wordpress.com/2013/10/04/name-based-extractors-in-scala-2-11/ for an explanation why it's useful.
But your unapply returns a String => Some[String], which doesn't have either, and that's what the error says.
To answer your first question - isEmpty comes from internals of Option type.
def unapply = f means - create a parameterless method that returns a function. This is not a method by itself and thus you have an error.
You can further read about difference between function and method in Scala there: Difference between method and function in Scala

Scala: generic parser for Enumeration values

I thought it should be possible to write a generic function that works for all Enumeration values. I tried a simple parser first but I failed:
object Weekday extends Enumeration {
type Weekday = Value
val MONDAY = Value("MONDAY")
val OTHER = Value("OTHER")
implicit def valueToWeekday(v: Value): Weekday = v.asInstanceOf[Weekday]
implicit def stringToWeekday(s: String): Weekday = Weekday.withName(s)
}
object Enumerations {
import Weekday._
println("Welcome to the Scala worksheet")
def parseEnumeration[T <: Enumeration](s: String)(implicit ev: T): T#Value = {
ev.withName(s)
}
val test = parseEnumeration[Weekday]("MONDAY")
}
So how can I write a generict function taking an enumeration type as parameter and returning a Value of that type? I'm a bit confused here with the Object and the inner type with the same name.
Firstly, your implicit method valueToWeekday doesn't really do anything, as Weekday is simply an alias for Value in this context.
Secondly, your implicit method stringToWeekday is a working, albeit non-generic conversion from a string to its enumeration value.
However, it is not hard to make stringToWeekday generic. You simply need to pass the enumeration to the function, just like you do in parseEnumeration. Since you made the evidence in parseEnumeration implicit, all you need to do is put an appropriate implicit value in the context. Alternatively, you can pass the evidence explicitly.
So you can remove those implicit conversions (and the type alias, since the name-clash is slightly misleading).
object Weekday extends Enumeration {
val Monday = Value("MONDAY")
val Other = Value("OTHER")
}
The implicit way:
def parseEnumeration[T <: Enumeration](s: String)(implicit ev: T): T#Value = ev.withName(s)
implicit val evidence = Weekday
val weekday = parseEnumeration("MONDAY") // results in the value Weekday.Monday
The explicit way:
def parseEnumeration[T <: Enumeration](s: String, enumeration: T): T#Value = enumeration.withName(s)
val weekday = stringToEnumerationValue("MONDAY", Weekday) // results in the value Weekday.Monday
A third option would be to use a ClassTag as evidence, which is put in the context by the compiler through the generic parameters. However, this requires reflection to actually call the method withName and I would discourage going this way.

Scala - How can I exclude my function's generic type until use?

I have a map of String to Functions which details all of the valid functions that are in a language. When I add a function to my map, I am required to specify the type (in this case Int).
var functionMap: Map[String, (Nothing) => Any] = Map[String, (Nothing) => Any]()
functionMap += ("Neg" -> expr_neg[Int])
def expr_neg[T: Numeric](value: T)(implicit n: Numeric[T]): T = {
n.negate(value)
}
Instead, how can I do something like:
functionMap += ("Neg" -> expr_neg)
without the [Int] and add it in later on when I call:
(unaryFunctionMap.get("abs").get)[Int](-45)
You're trying to build your function using type classes (in this case, Numeric). Type classes rely on implicit parameters. Implicits are resolved at compile time. Your function name string values are only known at runtime, therefore you shouldn't build your solution on top of type classes like this.
An alternative would be to store a separate function object in your map for each parameter type. You could store the parameter type with a TypeTag:
import scala.reflect.runtime.universe._
var functionMap: Map[(String, TypeTag[_]), (Nothing) => Any] = Map()
def addFn[T: TypeTag](name: String, f: T => Any) =
functionMap += ((name, typeTag[T]) -> f)
def callFn[T: TypeTag](name: String, value: T): Any =
functionMap((name, typeTag[T])).asInstanceOf[T => Any](value)
addFn[Int]("Neg", expr_neg)
addFn[Long]("Neg", expr_neg)
addFn[Double]("Neg", expr_neg)
val neg10 = callFn("Neg", 10)
No type class implicit needs to be resolved to call callFn(), because the implicit Numeric was already resolved on the call to addFn.
What happens if we try to resolve the type class when the function is called?
The first problem is that a Function1 (or Function2) can't have implicit parameters. Only a method can. (See this other question for more explanation.) So if you want something that acts like a Function1 but takes an implicit parameter, you'll need to create your own type that defines the apply() method. It has to be a different type from Function1, though.
Now we get to the main problem: all implicits must be able to be resolved at compile time. At the location in code where the method is run, all the type information needed to choose the implicit value needs to be available. In the following code example:
unaryFunctionMap("abs")(-45)
We don't really need to specify that our value type is Int, because it can be inferred from the value -45 itself. But the fact that our method uses a Numeric implicit value can't be inferred from anything in that line of code. We need to specify the use of Numeric somewhere at compile time.
If you can have a separate map for unary functions that take a numeric value, this is (relatively) easy:
trait UnaryNumericFn {
def apply[T](value: T)(implicit n: Numeric[T]): Any
}
var unaryNumericFnMap: Map[String, UnaryNumericFn] = Map()
object expr_neg extends UnaryNumericFn {
override def apply[T](value: T)(implicit n: Numeric[T]): T = n.negate(value)
}
unaryNumericFnMap += ("Neg" -> expr_neg)
val neg3 = unaryNumericFnMap("Neg")(3)
You can make the function trait generic on the type class it requires, letting your map hold unary functions that use different type classes. This requires a cast internally, and moves the specification of Numeric to where the function is finally called:
trait UnaryFn[-E[X]] {
def apply[T](value: T)(implicit ev: E[T]): Any
}
object expr_neg extends UnaryFn[Numeric] {
override def apply[T](value: T)(implicit n: Numeric[T]): T = n.negate(value)
}
var privateMap: Map[String, UnaryFn[Nothing]] = Map()
def putUnary[E[X]](key: String, value: UnaryFn[E]): Unit =
privateMap += (key -> value)
def getUnary[E[X]](key: String): UnaryFn[E] =
privateMap(key).asInstanceOf[UnaryFn[E]]
putUnary("Neg", expr_neg)
val pos5 = getUnary[Numeric]("Neg")(-5)
But you still have to specify Numeric somewhere.
Also, neither of these solutions, as written, support functions that don't need type classes. Being forced to be this explicit about which functions take implicit parameters, and what kinds of implicits they use, starts to defeat the purpose of using implicits in the first place.
You can't. Because expr_neg is a method with a type parameter T and an implicit argument n depending on that parameter. For Scala to lift that method to a function, it needs to capture the implicit, and therefore it must know what kind of type you want.

Is it possible to write a method in Scala returning objects with different type parameter?

Is it possible to write a method in Scala which returns an object of a type-parameterized class with different type paramter ? Something like this:
class A[T]
def f(switch: Boolean): A = if(switch) new A[Int] else new A[String]
Please note: The Code above is fictional to show the type of problem; The code above does not make semantically sense.
The code above will not compile because return type A is not parameterized.
You can, and you can even do it with type-safety with the aid of implicit arguments that encapsulate the pairings:
class TypeMapping[+A,B] {
def newListB = List.empty[B]
}
trait Logical
object True extends Logical
object False extends Logical
implicit val mapFalseToInt = new TypeMapping[False.type,Int]
implicit val mapTrueToString = new TypeMapping[True.type,String]
def f[A <: Logical,B](switch: A)(implicit tmap: TypeMapping[A,B]) = tmap.newListB
scala> f(True)
res2: List[String] = List()
scala> f(False)
res3: List[Int] = List()
You do have to explicitly map from boolean values to the custom True and False values.
(I have chosen List as the target class just as an example; you could pick anything or even make it generic with a little more work.)
(Edit: as oxbow_lakes points out, if you need all possible return values to be represented on the same code path, then this alone won't do it, because the superclass of List[Int] and List[String] is List[Any], which isn't much help. In that case, you should use an Either. My solution is for a single function that will be used only in the True or False contexts, and can maintain the type information there.)
One way of expressing this would be by using Either;
def f(switch: Boolean) = if (switch) Left(new A[Int]) else Right(newA[String])
This of course returns an Either[A[Int], A[String]]. You certainly cannot (at the moment) declare a method which returns some parameterized type P, with some subset of type parameters (i.e. only Int or String).
The language ceylon has union types and I understand the intention is to add these to scala in the near future, in which case, you could define a method:
def f(switch: Boolean): A[Int|String] = ...
Well, you could do something like that.
scala> class A {
| type T
| }
defined class A
scala> def f(b: Boolean): A = if(b) new A { type T = Int } else new A { type T = String }
f: (b: Boolean)A
But this is pointless. Types are a compile time information, and that information is getting lost here.
How about an absolutely minimal change to the "fictional code"? If we just add [_] after the "fictional" return type, the code will compile:
class A[T]
def f(switch: Boolean):A[_] = if(switch) new A[Int] else new A[String]
It is worth noting that A[_] is not the same as A[Any]. A[T] does not need to be defined covariant for the code to compile.
Unfortunately, information about the type gets lost.

Why this type of implicit conversion is illegal?

I write the following implicit conversion in scala:
implicit def strToInt2(str: String):Int = {
str.toInt
}
But it rises this compilation error:
<console>:9: error: type mismatch;
found : str.type (with underlying type String)
required: ?{val toInt: ?}
Note that implicit conversions are not applicable because they are ambiguous:
both method augmentString in object Predef of type (x: String)scala.collection.
immutable.StringOps
and method toi in object $iw of type (str: String)Int
are possible conversion functions from str.type to ?{val toInt: ?}
str.toInt
^
If I remove the return type, just declare it like this:
implicit def strToInt2(str: String) = {
str.toInt
}
It compiles successfully. Can anyone tell me what's the difference between the two ?
Ok, let's start with the beginning, why does it fail in the first case:
You try to define an implicit method that transforms a String into an Int and to do so you call toInt.
Unfortunately, toInt is not a part of the String class. Thus, the compiler needs to find an implicit to convert str in something that has a toInt:Int method.
Fortunately, Predef.augmentString convert a String into a StringOps, which has such a method.
But the Int type also have such a method and AS you define a return type, the method strToInt2 can be called recursively, and as the method is implicit, it can be applied to transform something with a toInt:Int function.
The compiler doesn't know which implicit method to use (between yours and Predef.augmentString and throws an error.
In the second case, as you omit the return type, the strToInt2 function cannot be recursive, and there are no longer two candidates to transform the String.
BUT if after this definition, you try: "2".toInt, the error is back: you now have two ways to obtain something with a toInt:Intfunction when you have a String.