Converting SAMs to lambdas: Preferred code style?

When looking though the Scala library in an IDE, I sometimes see the suggestion “Convert expression to Single Abstract Method”. I’m wondering if there is interest in having those expressions converted to lambdas.

If so, what style is preferred? For illustration purposes, I will use the method Equiv.reference, currently:

def reference[T <: AnyRef]: Equiv[T] = new Equiv[T] {
  def equiv(x: T, y: T) = x eq y

Which of the following styles is preferred def reference[T <: AnyRef]: Equiv[T] =

  1. (x: T, y: T) => x eq y
  2. (x, y) => x eq y
  3. _ eq _

Does the style preference depend on the situation? For some expressions, option 3 does not work. Which option is preferred in those cases?

1 Like

I’ll answer on code style first. Doing these changes on the standard library might have other lower-level considerations (I don’t know if the generated code is binary compatible, but that’s best found out through a PR).

A few general questions that are relevant when discussing such code style issues (about abstraction) are:

  • who is your audience? This is especially hard to answer for the std. library;
  • writing less by omitting redundant info (like here) can make reading harder for some; is there (IDE) support to help them understand? Here, can they easily jump to Equiv's definition? (for IDE users, I’d guess yes here).
  • others might prefer the more abstract/simplified code because it’s more concise. Can it code be understood (by the audience) without expanding it back into the old code?

Not sure these matters are standardized enough (yet), and not sure there’s a one-size fit all standard.
In this case, for a reader who knows or can easily see/guess what’s Equiv[T], this definition seems best — names like x and y add almost no info. Some of the more meaningful names might be useful to keep, instead.

def reference[T <: AnyRef]: Equiv[T] = _ eq _

I can now read this code as, reference is an Equivalence on T implemented by reference equality (_ eq _). Seems clear enough. The extra material is boilerplate.

The simplified code was already legal Scala in earlier releases, though only with Equiv[T] defined as type Equiv[T] = T => T. This might confuse some readers during transition.

OTOH, in some contexts one might wonder what is being inferred—that’s harder to figure out in the new code (though an IDE might help). This example is very lucky because the compact code can be read directly, but I’m not sure all examples are so easy.

There actually aren’t very many cases in the std. library (10), and most of them (8) are for Equiv, Ordering or Ordered (where, as you mentioned, it’s fairly easy to read the code directly).

Also, I think Equiv[T] would need to be defined as type Equiv[T] = (T, T) => Boolean.