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.
for comprehension
,chained maps
, etc., all of these) in the world. What a pity! Hope Scala 3 with meta-programming magic will change this! – MadaleneDsl.scala
lib which is written by Thoughtworks canunifies monads, generators, asynchronous functions, coroutines and continuations to a single universal syntax
looks interesting. – Madalene