Scala Option implicit conversion - Bad practice or missing feature? - scala

I represented my data model as case classes typing values that may be null as Option.
case class Document(id: Long, title: String, subtitle: Option[String])
Now I try to instantiate the case class:
Document(123, "The Title", "Subtitle") // Doesn't work
But NOPE! This doesn't work, I have to wrap the optional value in a Some.
Document(123, "The Title", Some("Subtitle")) // Works
Scala is very clever about types in general, but why is it not self-evident that a hard coded literal, or (any string for that matter) is a different than null/None?
I was able to fix this and make Scala "more clever" by adding this implicit conversion
implicit def autoSome[T](any:T) = Some(any)
Document(123, "The Title", "Subtitle") // Now it works!
Question: Am I the only one that the language should provide implicit conversion T -> Some(T) out of the box? Or is there any gotchas that I'm not aware of about having so broad implicit everywhere by default?

This can cause untold number of problems. The issue here isn't what you might think but what you don't think could happen. That is, if you make another implicit class that works on Option types you could wind up creating artificial results that you never intended to happen, i.e. operators for your overloaded types being present in your non-overloaded types.
implicit class OptDouble(opt: Option[Double]) extends Any{
def *(x: Double) = Some((opt getOrElse 0.0) * x)
def ^(x: Double) = Some(Math.power(opt getOrElse 1.0, x))
}
val z = q^4.5
The type of z is Option[Double]. You wouldn't expect that to happen but first Scala did an implicit conversion to Option and then it used the implicit class to call the ^ operator. Now people looking at your code are going to be scratching their heads wondering why they have an Option. You might start seeing a few defensive x getOrElse 0.0 sprinkled around the code as people fight to keep Option away (and yes, this is from personal experience.)
That said, what you should do is use another apply on the object:
object Document{
def apply(id: Long, title: String, subtitle: String) = new Document(id, title, Some(subtitle))
}
which will do everything you wanted it to do as long as you don't have a default defined for subtitle, i.e. subtitle: Option[String] = None.

Most problems pointed out earlier can easily be fixed with a small change to the implicit:
implict def autoOpt[T](x: T): Option[T] = Option(x)
I can't really think of a good reason scala does not provide this conversion as a part of the default library of implicit converters.
The fact that implicts make code harder to understand can be used as an argument against using any implicit, but not as one against using this particular one

That's a pretty dangerous implementation:
scala> val s: String = null
s: String = null
scala> Document(123, "The Title", s)
res2: Document = Document(123,The Title,Some(null))

Related

Scala Implicit Conversion Gotchas

EDIT
OK, #Drexin brings up a good point re: loss of type safety/surprising results when using implicit converters.
How about a less common conversion, where conflicts with PreDef implicits would not occur? For example, I'm working with JodaTime (great project!) in Scala. In the same controller package object where my implicits are defined, I have a type alias:
type JodaTime = org.joda.time.DateTime
and an implicit that converts JodaTime to Long (for a DAL built on top of ScalaQuery where dates are stored as Long)
implicit def joda2Long(d: JodaTime) = d.getMillis
Here no ambiguity could exist between PreDef and my controller package implicits, and, the controller implicits will not filter into the DAL as that is in a different package scope. So when I do
dao.getHeadlines(articleType, Some(jodaDate))
the implicit conversion to Long is done for me, IMO, safely, and given that date-based queries are used heavily, I save some boilerplate.
Similarly, for str2Int conversions, the controller layer receives servlet URI params as String -> String. There are many cases where the URI then contains numeric strings, so when I filter a route to determine if the String is an Int, I do not want to stringVal.toInt everytime; instead, if the regex passes, let the implicit convert the string value to Int for me. All together it would look like:
implicit def str2Int(s: String) = s.toInt
get( """/([0-9]+)""".r ) {
show(captures(0)) // captures(0) is String
}
def show(id: Int) = {...}
In the above contexts, are these valid use cases for implicit conversions, or is it more, always be explicit? If the latter, then what are valid implicit conversion use cases?
ORIGINAL
In a package object I have some implicit conversions defined, one of them a simple String to Int:
implicit def str2Int(s: String) = s.toInt
Generally this works fine, methods that take an Int param, but receive a String, make the conversion to Int, as do methods where the return type is set to Int, but the actual returned value is a String.
Great, now in some cases the compiler errors with the dreaded ambiguous implicit:
both method augmentString in object Predef of type (x: String)
scala.collection.immutable.StringOps and method str2Int(s: String) Int
are possible conversion functions from java.lang.String to ?{val
toInt: ?}
The case where I know this is happening is when attempting to do manual inline String-to-Int conversions. For example, val i = "10".toInt
My workaround/hack has been to create an asInt helper along with the implicits in the package object: def asInt(i: Int) = i and used as, asInt("10")
So, is implicit best practice implicit (i.e. learn by getting burned), or are there some guidelines to follow so as to not get caught in a trap of one's own making? In other words, should one avoid simple, common implicit conversions and only utilize where the type to convert is unique? (i.e. will never hit ambiguity trap)
Thanks for the feedback, implicits are awesome...when they work as intended ;-)
I think you're mixing two different use cases here.
In the first case, you're using implicit conversions used to hide the arbitrary distinction (or arbitrary-to-you, anyway) between different classes in cases where the functionality is identical. The JodaTime to Long implicit conversion fits in that category; it's probably safe, and very likely a good idea. I would probably use the enrich-my-library pattern instead, and write
class JodaGivesMS(jt: JodaTime) { def ms = jt.getMillis }
implicit def joda_can_give_ms(jt: JodaTime) = new JodaGivesMS(jt)
and use .ms on every call, just to be explicit. The reason is that units matter here (milliseconds are not microseconds are not seconds are not millimeters, but all can be represented as ints), and I'd rather leave some record of what the units are at the interface, in most cases. getMillis is rather a mouthful to type every time, but ms is not too bad. Still, the conversion is reasonable (if well-documented for people who may modify the code in years to come (including you)).
In the second case, however, you're performing an unreliable transformation between one very common type and another. True, you're doing it in only a limited context, but that transformation is still liable to escape and cause problems (either exceptions or types that aren't what you meant). Instead, you should write those handy routines that you need that correctly handle the conversion, and use those everywhere. For example, suppose you have a field that you expect to be "yes", "no", or an integer. You might have something like
val Rint = """(\d+)""".r
s match {
case "yes" => println("Joy!")
case "no" => println("Woe!")
case Rint(i) => println("The magic number is "+i.toInt)
case _ => println("I cannot begin to describe how calamitous this is")
}
But this code is wrong, because "12414321431243".toInt throws an exception, when what you really want is to say that the situation is calamitous. Instead, you should write code that matches properly:
case object Rint {
val Reg = """([-]\d+)""".r
def unapply(s: String): Option[Int] = s match {
case Reg(si) =>
try { Some(si.toInt) }
catch { case nfe: NumberFormatException => None }
case _ => None
}
}
and use this instead. Now instead of performing a risky and implicit conversion from String to Int, when you perform a match it will all be handled properly, both the regex match (to avoid throwing and catching piles of exceptions on bad parses) and the exception handling even if the regex passes.
If you have something that has both a string and an int representation, create a new class and then have implicit conversions to each if you don't want your use of the object (which you know can safely be either) to keep repeating a method call that doesn't really provide any illumination.
I try not to convert anything implicitly just to convert it from one type to another, but only for the pimp my library pattern. It can be a bit confusing, when you pass a String to a function that takes an Int. Also there is a huge loss of type safety. If you would pass a string to a function that takes an Int by mistake the compiler could not detect it, as it assumes you want to do it. So always do type conversion explicitly and only use implicit conversions to extend classes.
edit:
To answer your updated question: For the sake of readability, please use the explicit getMillis. In my eyes valid use cases for implicits are "pimp my library", view/context bounds, type classes, manifests, builders... but not being too lazy to write an explicit call to a method.

Map from Class[T] to T without casting

I want to map from class tokens to instances along the lines of the following code:
trait Instances {
def put[T](key: Class[T], value: T)
def get[T](key: Class[T]): T
}
Can this be done without having to resolve to casts in the get method?
Update:
How could this be done for the more general case with some Foo[T] instead of Class[T]?
You can try retrieving the object from your map as an Any, then using your Class[T] to “cast reflectively”:
trait Instances {
private val map = collection.mutable.Map[Class[_], Any]()
def put[T](key: Class[T], value: T) { map += (key -> value) }
def get[T](key: Class[T]): T = key.cast(map(key))
}
With help of a friend of mine, we defined the map with keys as Manifest instead of Class which gives a better api when calling.
I didnt get your updated question about "general case with some Foo[T] instead of Class[T]". But this should work for the cases you specified.
object Instances {
private val map = collection.mutable.Map[Manifest[_], Any]()
def put[T: Manifest](value: T) = map += manifest[T] -> value
def get[T: Manifest]: T = map(manifest[T]).asInstanceOf[T]
def main (args: Array[String] ) {
put(1)
put("2")
println(get[Int])
println(get[String])
}
}
If you want to do this without any casting (even within get) then you will need to write a heterogeneous map. For reasons that should be obvious, this is tricky. :-) The easiest way would probably be to use a HList-like structure and build a find function. However, that's not trivial since you need to define some way of checking type equality for two arbitrary types.
I attempted to get a little tricky with tuples and existential types. However, Scala doesn't provide a unification mechanism (pattern matching doesn't work). Also, subtyping ties the whole thing in knots and basically eliminates any sort of safety it might have provided:
val xs: List[(Class[A], A) forSome { type A }] = List(
classOf[String] -> "foo", classOf[Int] -> 42)
val search = classOf[String]
val finalResult = xs collect { case (`search`, result) => result } headOption
In this example, finalResult will be of type Any. This is actually rightly so, since subtyping means that we don't really know anything about A. It's not why the compiler is choosing that type, but it is a correct choice. Take for example:
val xs: List[(Class[A], A) forSome { type A }] = List(classOf[Boolean] -> 'bippy)
This is totally legal! Subtyping means that A in this case will be chosen as Any. It's hardly what we want, but it is what you will get. Thus, in order to express this constraint without tracking all of the types individual (using a HMap), Scala would need to be able to express the constraint that a type is a specific type and nothing else. Unfortunately, Scala does not have this ability, and so we're basically stuck on the generic constraint front.
Update Actually, it's not legal. Just tried it and the compiler kicked it out. I think that only worked because Class is invariant in its type parameter. So, if Foo is a definite type that is invariant, you should be safe from this case. It still doesn't solve the unification problem, but at least it's sound. Unfortunately, type constructors are assumed to be in a magical super-position between co-, contra- and invariance, so if it's truly an arbitrary type Foo of kind * => *, then you're still sunk on the existential front.
In summary: it should be possible, but only if you fully encode Instances as a HMap. Personally, I would just cast inside get. Much simpler!

Scala - implicit conversion with unapply

I'd like an extractor to implicitly convert its parameters, but it doesn't seem to work. Consider this very simple case:
case class MyString(s: String) {}
implicit def string2mystring(x: String): MyString = new MyString(x)
implicit def mystring2string(x: MyString) = x.s
object Apply {
def unapply(s: MyString): Option[String] = Some(s)
}
But I'm not able to use it as I would expect:
val Apply(z) = "a" // error: scrutinee is incompatible with pattern type
Can anyone explain why it fails to convert the parameter from String to MyString? I would expect it to call string2mystring("a") on the fly. Clearly I could work around the issue by saying val Apply(y) = MyString("a"), but it doesn't seem like I should have to do that.
Note: This question is similar to this one, but 1) that one doesn't really have a good answer for why this is happening, 2) the example is more complex than it needs to be.
Implicit conversions are not applied when pattern matching. That's not a bug or a problem with your code, it's simply a design decision of the creators of Scala.
To fix it, you should write another extractor that accepts a String — which in turn can call your implicit conversion.
Alternatively, you can try with a view bound, which seems to work as well, and will also work if you later define other implicit conversions to MyString:
object Apply {
def unapply[S <% MyString](s: S): Option[String] = Some(s.s)
}

Could/should an implicit conversion from T to Option[T] be added/created in Scala?

Is this an opportunity to make things a bit more efficient (for the prorammer): I find it gets a bit tiresome having to wrap things in Some, e.g. Some(5). What about something like this:
implicit def T2OptionT( x : T) : Option[T] = if ( x == null ) None else Some(x)
You would lose some type safety and possibly cause confusion.
For example:
val iThinkThisIsAList = 2
for (i <- iThinkThisIsAList) yield { i + 1 }
I (for whatever reason) thought I had a list, and it didn't get caught by the compiler when I iterated over it because it was auto-converted to an Option[Int].
I should add that I think this is a great implicit to have explicitly imported, just probably not a global default.
Note that you could use the explicit implicit pattern which would avoid confusion and keep code terse at the same time.
What I mean by explicit implicit is rather than have a direct conversion from T to Option[T] you could have a conversion to a wrapper object which provides the means to do the conversion from T to Option[T].
class Optionable[T <: AnyRef](value: T) {
def toOption: Option[T] = if ( value == null ) None else Some(value)
}
implicit def anyRefToOptionable[T <: AnyRef](value: T) = new Optionable(value)
... I might find a better name for it than Optionable, but now you can write code like:
val x: String = "foo"
x.toOption // Some("foo")
val y: String = null
x.toOption // None
I believe that this way is fully transparent and aids in the understanding of the written code - eliminating all checks for null in a nice way.
Note the T <: AnyRef - you should only do this implicit conversion for types that allow null values, which by definition are reference types.
The general guidelines for implicit conversions are as follows:
When you need to add members to a type (a la "open classes"; aka the "pimp my library" pattern), convert to a new type which extends AnyRef and which only defines the members you need.
When you need to "correct" an inheritance hierarchy. Thus, you have some type A which should have subclassed B, but didn't for some reason. In that case, you can define an implicit conversion from A to B.
These are the only cases where it is appropriate to define an implicit conversion. Any other conversion runs into type safety and correctness issues in a hurry.
It really doesn't make any sense for T to extend Option[T], and obviously the purpose of the conversion is not simply the addition of members. Thus, such a conversion would be inadvisable.
It would seem that this could be confusing to other developers, as they read your code.
Generally, it seems, implicit works to help cast from one object to another, to cut out confusing casting code that can clutter code, but, if I have some variable and it somehow becomes a Some then that would seem to be bothersome.
You may want to put some code showing it being used, to see how confusing it would be.
You could also try to overload the method :
def having(key:String) = having(key, None)
def having(key:String, default:String) = having(key, Some(default))
def having(key: String, default: Option[String]=Option.empty) : Create = {
keys += ( (key, default) )
this
}
That looks good to me, except it may not work for a primitive T (which can't be null). I guess a non-specialized generic always gets boxed primitives, so probably it's fine.

Pattern matching a String as Seq[Char]

In Scala it is possible formulate patterns based on the invididual characters of a string by treating it as a Seq[Char].
An example of this feature is mentioned in A Tour of Scala
This is the example code used there:
object RegExpTest1 extends Application {
def containsScala(x: String): Boolean = {
val z: Seq[Char] = x
z match {
case Seq('s','c','a','l','a', rest # _*) =>
println("rest is "+rest)
true
case Seq(_*) =>
false
}
}
}
The problem I have with this is the third line of the snippet:
val z: Seq[Char] = x
Why is this sort of cast necessary? Shouldn't a String behave like a Seq[Char] under all circumstances (which would include pattern matching)? However, without this conversion, the code snippet will not work.
There is some real abuse of terminology going on in the question and the comments. There is no cast in this code, and especially "So basically, this is a major concession to Java interoperability, sacrificing some type soundness" has no basis in reality.
A scala cast looks like this: x.asInstanceOf[Y].
What you see above is an assignment: val z: Seq[Char] = x
This assignment is legal because there is an implicit conversion from String to Seq[Char]. I emphasize again, this is not a cast. A cast is an arbitrary assertion which can fail at runtime. There is no way for the implicit conversion to fail.
The problem with depending on implicit conversions between types, and the answer to the original question, is that implicit conversions only take place if the original value doesn't type check. Since it's perfectly legal to match on a String, no conversion takes place, the match just fails.
Not 100% sure if this is correct, but my intuition says that without this explicit cast you would pattern match against java.lang.String, which is not what you want.
The explicit cast forces the Scala compiler to use Predef.stringWrapper implicit conversion; thus, as RichString extends Seq[Char], you are able to do a pattern match as if the string were a sequence of characters.
I'm going to echo everything that andri said. For interoperability, Scala strings are java.lang.Strings. In Predef, there's an implicit conversion from String to RichString, which implements Seq[Char].
A perhaps nicer way of coding the pattern match, without needing an intermediate val z to hold the Seq[Char]:
def containsScala(x: String): Boolean = {
(x: Seq[Char]) match {
...
}
}