While working on a Scala hobby project, I wanted to convert an `Option[A]`

into an `Option[B]`

. I’ve noticed that it’s often straightforward to come up with an ugly way to do things in Scala, but with a little more thought it’s almost always possible to find a much more elegant and concise way to do things. I had initially written the following:

def intersect(ray: Ray): Option[Intersection] = { val opt = shape intersect ray // Returns an Option[(DifferentialGeometry, Double)] if (opt.isEmpty) None else { val (dg, t) = opt.get Some(new Intersection(dg, t, this)) } }

This code is part of my Scala ray tracer (which isn’t yet publicly available – at the moment it’s too incomplete). It calls the `intersect`

method on a shape, which returns an `Option`

containing two values: a `DifferentialGeometry`

object that contains information about the intersection point on the surface of the shape, and a `Double`

which is the distance of the intersection point along the ray.

The `intersect`

method above is part of class `Primitive`

, which represents an object in the scene – something that has a shape, a material and other properties. This method converts the `Option[(DifferentialGeometry, Double)]`

into an `Option[Intersection]`

– class `Intersection`

represents an intersection between a primitive and a ray.

I wasn’t satisfied with the code above, and after looking at the Scala API documentation I discovered that it can be written much more concisely by using the `collect`

method of class `Option`

, like this:

def intersect(ray: Ray): Option[Intersection] = shape intersect ray collect { case (dg, t) => new Intersection(dg, t, this) }

The `collect`

method takes a partial function as an argument. It returns `None`

for inputs for which the partial function isn’t defined, and a `Some(...)`

for inputs for which the partial function is defined. The partial function can be written as `{ case value => ... }`

. By writing the code this way, I don’t have to deal with checking, unpacking and packing the `Option`

objects myself, which makes the code nice and clean.

*edit*: Using `map`

instead of `collect`

is a little bit more efficient, as Brian Howard points out. See the comments for details.

Since your function applies to _all_ of the `Some(…)` values coming out of `shape intersect ray`, you could do this more efficiently (no need to check whether the function is defined) with `map` instead of `collect`. Or, you could use the `for` syntax (which is equivalent):

for ((dg, t) <- shape intersect ray) yield new Intersection(dg, t, this)

Thanks Brian!

You’re right, you can also replace

`collect`

by`map`

. I’ve tried it out in my ray tracer, and also using the`for`

syntax. There’s no noticeable performance improvement when I do this, though. Looking at the implementation of`map`

and`collect`

in class`Option`

:There is indeed an extra condition in the

`if`

-statement in`collect`

, so in principle it’s less efficient.I don’t like the

`for`

syntax for this; when I see a`for`

, I’d expect a loop, but there’s not really a loop here.