36

In Groovy language, it is very simple to check for null or false like:

groovy code:

def some = getSomething()
if(some) {
// do something with some as it is not null or emtpy 

}

In Groovy if some is null or is empty string or is zero number etc. will evaluate to false. What is similar concise method of testing for null or false in Scala? What is the simple answer to this part of the question assuming some is simply of Java type String?

Also another even better method in groovy is:

def str = some?.toString()

which means if some is not null then the toString method on some would be invoked instead of throwing NPE in case some was null. What is similar in Scala?

ace
  • 11,526
  • 39
  • 113
  • 193
  • IMO, Daniel's answer below is the most appropriate. Scala already has lots of support for dealing with potentially empty values - better to learn and use that than to create a new `?` syntax with implicits. – Bill Jun 20 '11 at 20:47
  • 1
    One reason to go with `null`s instead of `None`s might be performance/memory usage - you might prefer allocating a short-lived object from the implicit conversion on the fly instead of keeping an `Option` wrapper around. Granted, not many people write high-performance code on the JVM, but still, I'd say it has its use-cases. – axel22 Jun 20 '11 at 21:01

7 Answers7

57

What you may be missing is that a function like getSomething in Scala probably wouldn't return null, empty string or zero number. A function that might return a meaningful value or might not would have as its return an Option - it would return Some(meaningfulvalue) or None.

You can then check for this and handle the meaningful value with something like

 val some = getSomething()
 some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
 }

So instead of trying to encode the "failure" value in the return value, Scala has specific support for the common "return something meaningful or indicate failure" case.

Having said that, Scala's interoperable with Java, and Java returns nulls from functions all the time. If getSomething is a Java function that returns null, there's a factory object that will make Some or None out of the returned value.

So

  val some = Option(getSomething())
  some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
  }

... which is pretty simple, I claim, and won't go NPE on you.

The other answers are doing interesting and idiomatic things, but that may be more than you need right now.

The Archetypal Paul
  • 41,321
  • 20
  • 104
  • 134
  • 1
    this is worst scala feature i encountered so far in my one month journey.. it's pardox to scala's "type less" ideology. imo NPE is easy to fix and you cant rely on lang to do everything for you. Even with Option people can write code that will lead to NPE. i.e. if instead of match case if someone just do Some(val).get then you still get NPE. maybe down the line this may looks more useful but so far i havent encounter any articles that explain otherwise – nir Apr 23 '15 at 17:49
  • 1
    Keep going, and I predict you'll change your mind. Of course you can provoke an NPE if you try, but good practice in Scala is not to use Option .get - there are many better ways of doing it. – The Archetypal Paul Apr 23 '15 at 17:58
35

Well, Boolean cannot be null, unless passed as a type parameter. The way to handle null is to convert it into an Option, and then use all the Option stuff. For example:

Option(some) foreach { s => println(s) }
Option(some) getOrElse defaultValue

Since Scala is statically type, a thing can't be "a null or is empty string or is zero number etc". You might pass an Any which can be any of those things, but then you'd have to match on each type to be able to do anything useful with it anyway. If you find yourself in this situation, you most likely are not doing idiomatic Scala.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
19

In Scala, the expressions you described mean that a method called ? is invoked on an object called some. Regularly, objects don't have a method called ?. You can create your own implicit conversion to an object with a ? method which checks for nullness.

implicit def conversion(x: AnyRef) = new {
  def ? = x ne null
}

The above will, in essence, convert any object on which you call the method ? into the expression on the right hand side of the method conversion (which does have the ? method). For example, if you do this:

"".?

the compiler will detect that a String object has no ? method, and rewrite it into:

conversion("").?

Illustrated in an interpreter (note that you can omit . when calling methods on objects):

scala> implicit def any2hm(x: AnyRef) = new {
     |   def ? = x ne null
     | }
any2hm: (x: AnyRef)java.lang.Object{def ?: Boolean}

scala> val x: String = "!!"
x: String = "!!"

scala> x ?
res0: Boolean = true

scala> val y: String = null
y: String = null

scala> y ?
res1: Boolean = false

So you could write:

if (some ?) {
  // ...
}

Or you could create an implicit conversion into an object with a ? method which invokes the specified method on the object if the argument is not null - do this:

scala> implicit def any2hm[T <: AnyRef](x: T) = new {
     |   def ?(f: T => Unit) = if (x ne null) f(x)
     | }
any2hm: [T <: AnyRef](x: T)java.lang.Object{def ?(f: (T) => Unit): Unit}

scala> x ? { println }
!!

scala> y ? { println }

so that you could then write:

some ? { _.toString }

Building (recursively) on soc's answer, you can pattern match on x in the examples above to refine what ? does depending on the type of x. :D

axel22
  • 32,045
  • 9
  • 125
  • 137
  • this is nice! if you could explain the `eq` and `ne` operators that form the gist of this answer, that would be even more helpful – asgs Jul 02 '17 at 18:08
  • 1
    https://stackoverflow.com/questions/10066927/what-is-the-difference-between-a-nenull-and-a-null-in-scala – axel22 Jul 02 '17 at 20:46
7

If you use extempore's null-safe coalescing operator, then you could write your str example as

val str = ?:(some)(_.toString)()

It also allows you to chain without worrying about nulls (thus "coalescing"):

val c = ?:(some)(_.toString)(_.length)()

Of course, this answer only addresses the second part of your question.

Community
  • 1
  • 1
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
6

What you ask for is something in the line of Safe Navigation Operator (?.) of Groovy, andand gem of Ruby, or accessor variant of the existential operator (?.) of CoffeeScript. For such cases, I generally use ? method of my RichOption[T], which is defined as follows

class RichOption[T](option: Option[T]) {
  def ?[V](f: T => Option[V]): Option[V] = option match {
    case Some(v) => f(v)
    case _ => None
  }
}

implicit def option2RichOption[T](option: Option[T]): RichOption[T] =
  new RichOption[T](option)

and used as follows

scala> val xs = None
xs: None.type = None

scala> xs.?(_ => Option("gotcha"))
res1: Option[java.lang.String] = None

scala> val ys = Some(1)
ys: Some[Int] = Some(1)

scala> ys.?(x => Some(x * 2))
res2: Option[Int] = Some(2)
Volkan Yazıcı
  • 1,530
  • 1
  • 15
  • 28
6

You could write some wrapper yourself or use an Option type.

I really wouldn't check for null though. If there is a null somewhere, you should fix it and not build checks around it.

Building on top of axel22's answer:

implicit def any2hm(x: Any) = new {
  def ? = x match {
    case null => false
    case false => false
    case 0 => false
    case s: String if s.isEmpty => false
    case _ => true
  }
}

Edit: This seems to either crash the compiler or doesn't work. I'll investigate.

soc
  • 27,983
  • 20
  • 111
  • 215
  • 1
    The problem is that for declaring `x` as `Any` it introduces 2 implicit conversions for the `?` method into scope. – axel22 Jun 20 '11 at 20:41
  • What if some is of type Java String? It seems scala lacks the conciseness of groovy. – ace Jun 20 '11 at 20:44
  • I am sorry but I am not following both of the answers but thanks for trying. I was just looking for simple solution. – ace Jun 20 '11 at 20:46
  • 1
    @axel22: I filed an issue about it: SI-4724. @amc: No problem. But I think the "simple solution" is not having values which might be either `null` **or** empty **or** false. – soc Jun 20 '11 at 21:02
0

Using pattern matching as suggested in a couple of answers here is a nice approach:

val some = Option(getSomething())
  some match {
    case Some(theValue) => doSomethingWith(theValue)
    case None           => println("Whoops, didn't get anything useful back")
  }

But, a bit verbose.

I prefer to map an Option in the following way:

Option(getSomething()) map (something -> doSomethingWith(something))

One liner, short, clear.

The reason to that is Option can be viewed as some kind of collection – some special snowflake of a collection that contains either zero elements or exactly one element of a type and as as you can map a List[A] to a List[B], you can map an Option[A] to an Option[B]. This means that if your instance of Option[A] is defined, i.e. it is Some[A], the result is Some[B], otherwise it is None. It's really powerful!

Johnny
  • 14,397
  • 15
  • 77
  • 118