Scala avoid using null
Asked Answered
P

5

7

I hava a project on github that is analysed by codacy . The analysis suggest to "Avoid using null" for the following line of code:

def doSomethingWithPath(path:Path) = {
    require(path != null, "Path should not be null") //<-to avoid
    ...
}

What is the simplest scala idiomatic thing to do to fix it?

Prevot answered 17/4, 2017 at 8:30 Comment(1)
consider accepting one of the answers, or comment why you don't think they are a solution. This way, other users who end up in your question will have more information on how to solve the same problemWestfalen
C
6

I would keep it as is. You aren't really using null here, just guarding against it. The alternative could be to just delete that line altogether, and decide to not handle the null at all. Ignoring the possibility of null might be fine in a well built code base where it shouldn't come up anyway and null would be a bug, but a simple guard to catch it could prevent more subtle bugs from showing up in case something went wrong and null actually happens.

Checkerberry answered 17/4, 2017 at 9:12 Comment(0)
W
6

If path might actually be null this is probably the simplest.

require(Option(path).isDefined, "Must have a real Path")
Warfold answered 17/4, 2017 at 8:39 Comment(2)
path != null makes much more sense than Option(path).isDefined. It accomplishes the same thing but avoids completely unnecessary object allocation. I also think it's also a little clearer.Checkerberry
@puhlen, I agree. I also think that @Westfalen makes some valid/valuable points. But the OP asked for the "simplest" way to avoid nullin this scenario and that's what I tried to provide.Warfold
C
6

I would keep it as is. You aren't really using null here, just guarding against it. The alternative could be to just delete that line altogether, and decide to not handle the null at all. Ignoring the possibility of null might be fine in a well built code base where it shouldn't come up anyway and null would be a bug, but a simple guard to catch it could prevent more subtle bugs from showing up in case something went wrong and null actually happens.

Checkerberry answered 17/4, 2017 at 9:12 Comment(0)
W
4

the most idiomatic way would be to avoid the require (not sure but I have the idea it can thrown an exception - something Scala heavily recommends against)

def doSomethingWithPath(path:Path): Option[stuff] = { // will return an option of the type you were returning previously.
     Option(path).map { notNullPath =>
       ...
     }
}

Now the possible null case will be returned to the caller, that can/will propagate the returned Option until the layer that knows how to handle it properly.

Note: it is possible that the best place to handle the null case is inside you function. In that case you should do something like

Option(path).map { notNullPath =>
    ...
}.getOrElse(/* take care of null case */)

If you do want to keep the require, then the answer by jwvh would be my choice also

Westfalen answered 17/4, 2017 at 8:58 Comment(1)
This just unnecessarily complicates things. Instead of "do something with path", now your function is "maybe do something with path if you give me one, but silently don't if you give me None". If the user wants to work with Options, they can map the original function over their Option themselves. If they don't want to work with options, they shouldn't have to do doSomethingWithPath(Option(path)).get. It's not even truly more safe, because your Option could be null or even Some(null).Mackenie
F
2

There's no need to explicitly check for null or wrap path in an Option. You can do this:

 path match {
  case p: String => Option(doSomethingWith(p))
  case _         => None //if path is null this will be returned
 }

That will return an Option, which may not be what you want, but in that case instead of producing a None, raise an exception. require will raise an exception in your example anyway so if that's what your caller expects just do it explicitly.

Farnsworth answered 17/4, 2017 at 14:7 Comment(0)
P
0

Problem

The interdiction not to use null is a best practice. This article explains why and Guava: Ad-hoc Error Handling, Ambiguous Semantic, Slow Failing and so on.

Writing a require comes from the need to fail fast and clean when the preconditions for calling the method are not met. The problem is that it only replaces a NPE with another exception (nevertheless more descriptive) as @puhlen explained.

Ideal Solution

In an ideal world path:Path will be identical to number:Int and a test for the existence of the object will not be needed. The problem is that scala (as plethora of other languages) allows null breaking the pure object oriented approach.

Intermediate Solution

A java/scala compiler should force the Optional type as the only code that manages null and force the existence of null in the typing system. In such cases any use of null could be considered a compilation error. I don't know if this is completely feasible.

Using @NotNull/@Nullable annotations

Since there is no language/compiler level default behavior you will have impedance mismatch between libraries.

Practical Solution

Define my own class with Predef2 with minimal boilerplate logic. I will still get only one "Avoid using null" or use guava Preconditions.checkNotNull

object Predef2{
    def requireNotNull(object:AnyRef) = 
       require(path != null, "Some object should not be null")
}
def doSomethingWithPath(path:Path) = {
    requireNotNull(path)
    ...
}
Prevot answered 1/5, 2017 at 16:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.