Search code examples
scalagroovy

Best Scala imitation of Groovy's safe-dereference operator (?.)?


I would like to know what the best Scala imitation of Groovy's safe-dereference operator (?.), or at least some close alternatives are?

I've discussed it breifly on Daniel Spiewak's blog, but would like to open it up to StackOverFlow...

For the sake of everyone's time, here is Daniel's initial response, my counter, and his 2nd response:

@Antony

Actually, I looked at doing that one first. Or rather, I was trying to replicate Ragenwald’s andand “operator” from Ruby land. The problem is, this is a bit difficult to do without proxies. Consider the following expression (using Ruby’s andand, but it’s the same with Groovy’s operator):

test.andand().doSomething()

I could create an implicit conversion from Any => some type implementing the andand() method, but that’s where the magic stops. Regardless of whether the value is null or not, the doSomething() method will still execute. Since it has to execute on some target in a type-safe manner, that would require the implementation of a bytecode proxy, which would be flaky and weird (problems with annotations, final methods, constructors, etc).

A better alternative is to go back to the source of inspiration for both andand as well as Groovy’s safe dereference operator: the monadic map operation. The following is some Scala syntax which uses Option to implement the pattern:

val something: Option[String] = … // presumably could be either Some(…) or None

val length = something.map(_.length)

After this, length either be Some(str.length) (where str is the String object contained within the Option), or None. This is exactly how the safe-dereferencing operator works, except it uses null rather than a type-safe monad.

As pointed out above, we could define an implicit conversion from some type T => Option[T] and then map in that fashion, but some types already have map defined, so it wouldn’t be very useful. Alternatively, I could implement something similar to map but with a separate name, but any way it is implemented, it will rely upon a higher-order function rather than a simple chained call. It seems to be just the nature of statically typed languages (if anyone has a way around this, feel free to correct me).

Daniel Spiewak Monday, July 7, 2008 at 1:42 pm

My 2nd question:

Thanks for the response Daniel regarding ?. I think I missed it! I think I understand what you’re proposing, but what about something like this, assuming you don’t have control over the sources:

company?.getContactPerson?.getContactDetails?.getAddress?.getCity

Say it’s a java bean and you can’t go in and change the return values to Something[T] - what can we do there?

Antony Stubbs Tuesday, July 21, 2009 at 8:07 pm oh gosh - ok on re-read that’s where you’re proposing the implicit conversion from T to Option[T] right? But would you still be able to chain it together like that? You’d still need the map right? hmm….

var city = company.map(_.getContactPerson.map(_.getContactDetails.map(_.getAddress.map(_.getCity))))

?

Antony Stubbs Tuesday, July 21, 2009 at 8:10 pm

His 2nd response:

@Antony

We can’t really do much of anything in the case of company?.getContactPerson, etc… Even assuming this were valid Scala syntax, we would still need some way to prevent the later calls in the chain. This is not possible if we’re not using function values. Thus, something like map is really the only option.

An implicit conversion to Option wouldn’t be bad, but by making things implicit, we’re circumventing some of the protection of the type system. The best way to do this sort of thing is to use for-comprehensions in concert with Option. We can do map and flatMap, but it’s much nicer with magical syntax:

 for {
   c < - company
   person <- c.getContactPerson   
   details <- person.getContactDetails
   address <- details.getAddress 
  } yield address.getCity

Daniel Spiewak Tuesday, July 21, 2009 at 9:28 pm

P.s. if Daniel posts his original answers on his blog as answers, I will edit the question to remove them for the sake of the System.


Solution

  • How about this?

    def ?[A](block: => A) =
      try { block } catch {
        case e: NullPointerException if e.getStackTrace()(2).getMethodName == "$qmark" => null
        case e => throw e
      }
    

    Using this little snippet, you can dereference safely and the code itself is quite succinct:

    val a = ?(b.c.d.e)
    

    a == null if b or b.c or b.c.d or b.c.d.e is null, otherwise, a == b.c.d.e

    I think the value of a safe-dereference operator is diminished when you are using a language like Scala which has facilities like call-by-name and implicits.

    ps: I modify the code above a bit in light of one of the comments below to handle the case when NullPointerException is actually thrown inside the called function.

    BTW, I think using the function below is a more idiomatic way of writing Scala:

    def ??[A](block: => A): Option[A] = ?(block) match {
        case a: A => Some(a)
        case _ => None
      }
    

    like so:

    ??(a.b.c.d) match {
        case Some(result) => // do more things with result
        case None => // handle "null" case
      }