6

I've found somewhere an implementation of C# null coalescing operator '??':

implicit def coalescingOperator[T](pred: T) = new {
  def ??[A >: T](alt: =>A) = if (pred == null) alt else pred
}

It can be then used like a ?? b which means if (a == null) b else a.

And after decompiling the class files I saw that it produces code with reflection (in Scala 2.8.1).

Why it generates reflection and is it possible to modify that code so it would not generate reflection?

TN.
  • 18,874
  • 30
  • 99
  • 157
  • 4
    What about using `Option` as idiomatic way to handle this in Scala: `Option(a) getOrElse b`? – Tomasz Nurkiewicz May 28 '12 at 18:57
  • Too many characters to say a simple thing... – TN. May 28 '12 at 19:29
  • `Option` exists to handle "coalescing" as well as various other ways to deal with a value not being there. And the types force you to deal with the possibility of `None`, saving you from `null`-related headaches later. – Dan Burton May 29 '12 at 06:23
  • I use `Option` for pure Scala parts but this is need for tight interop with Java apis. But still I think that Kotlin solves this better. – TN. May 29 '12 at 07:35
  • http://stackoverflow.com/questions/1364361/how-to-write-a-proper-null-safe-coalescing-operator-in-scala – psp May 30 '12 at 15:25

1 Answers1

12

Scala doesn't have the same idea of anonymous classes as Java does. If you say something like

new {
  def fish = "Tuna"
}

then it will interpret all uses of the new method as requiring a structural type, i.e. the same as

def[T <: {def fish: String}](t: T) = t.fish

which needs to use reflection since there's no common superclass. I don't know why it's this way; it's exactly the wrong thing to do for performance, and usually isn't what you need.

Regardless, the fix is easy: create an actual class, not an anonymous one.

class NullCoalescer[T](pred: T) {
  def ??[A >: T](alt: => A) = if (pred == null) alt else pred
}
implicit def anyoneCanCoalesce[T](pred: T) = new NullCoalescer(pred)

In 2.10, it still does the arguably wrong thing, but (1) it will throw warnings at you for using reflection this way (so at least you'll know when it's happened) unless you turn them off, and (2) you can use a shorter version implicit class /* blah blah */ and skip the implicit def which just adds boilerplate.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407
  • @TN. - I mean the next version, which is not yet out (but which is far enough along that there have been statements that the reflection behavior will not change in this version). – Rex Kerr May 28 '12 at 22:01