Question

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)
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top