tags:

views:

396

answers:

2

I've been wondering whether transparent implicit conversions are really such a good idea and whether it might actually be better to use implicits more, um, explicitly. For example, suppose I have a method which accepts a Date as a parameter and I have an implicit conversion which turns a String into a Date:

implicit def str2date(s: String) : Date = new SimpleDateFormat("yyyyMMdd").parse(s)

private def foo(d: Date)

Then obviously I can call this with a transparent implicit conversion:

foo("20090910")

Would it be better to make the fact that I am converting the string into a date more explicit?

class DateString(val s: String) { 
  def toDate : Date = new SimpleDateFormat("yyyyMMdd").parse(s) 
}

implicit def str2datestr(s: String) : DateString = new DateString(s)

So then the usage looks more like:

foo("20090910".toDate)

The advantage of this is that it is clearer later on what is happening - I've been caught out a few times now by transparent implicit conversions I should know about (Option to Iterable anyone?) and this usage still allows us to take advantage of the power of implicits.

+16  A: 

I believe that the more "explicit" way of doing implicit conversions is much better in terms of readability than the fully transparent one, at least in this example.

In my opinion, using implicits fully transparently from type A to type B is OK when you can always view an object of type A as being able to be used whenever and object of type B is needed. For example, the implicit conversion of a String to a RandomAccessSeq[Char] always makes sense - a String can always, conceptually, be viewed as a sequence of characters (in C, a string is just a sequence of characters, for example). A call to x.foreach(println) makes sense for all Strings.

On the other hand, the more explicit conversions should be used when an object of type A can sometimes be used as an object of type B. In your example, a call to foo("bar") does not makes sense and throws an error. As Scala does not have checked exceptions, a call to foo(s.toDate) clearly signals that there might be an exception thrown (s might not be a valid date). Also, foo("bar".toDate) clearly looks wrong, while you need to consult documentation to see why foo("bar") might be wrong. An example of this in the Scala standard library is conversions from Strings to Ints, via the toInt method of the RichString wrapper (Strings can be seen as Ints, but not all the time).

-- Flaviu Cipcigan

Flaviu Cipcigan
@Flaviu - that is a **great** answer!
oxbow_lakes
Thanks! Glad I could help :)
Flaviu Cipcigan
+5  A: 

I'm a little late, and Flaviu has an excellent answer, but I wanted to add a comment about how I think about implicits.

When you make an implicit conversion from X to Y (like the conversion from String to Date above), you're essentially saying that, had you had full control over writing X in the first place, you would have made X implement or be a subclass of Y. If it makes sense for X to implement Y, then add the conversion. If it doesn't, then maybe it's not appropriate. For example, it makes sense for String to implement RandomAccessSeq[Char], but maybe it doesn't make sense for String to implement Date (though String implementing StringDate seems fine).

Jorge Ortiz