I recenly encountered this problem in a project: There's a chain of nested objects, e.g.: class A contains an instance variable of class B, which in turns has an instance variable of class C, ..., until we have a node in the tree of class Z.
----- ----- ----- ----- -----
| A | ---> | B | ---> | C | ---> | D | ---> ... ---> | Z |
----- ----- ----- ----- -----
Each class provides getters and setters for its members. The parent A instance is created by an XML parser, and it is legal for any object in the chain to be null.
Now imagine that at a certain point in the application, we have a reference to an A instance, and only if it contains a Z object, we must invoke a method on it. Using regular checks, we get this code:
A parentObject;
if(parentObject.getB() != null &&
parentObject.getB().getC() != null &&
parentObject.getB().getC().getD() != null &&
parentObject.getB().getC().getD().getE() != null &&
...
parentObject.getB().getC().getD().getE().get...getZ() != null){
parentObject.getB().getC().getD().getE().get...getZ().doSomething();
}
I know that exceptions should not be used for ordinary control flow, but instead of the previous code, I have seen some programmers doing this:
try {
parentObject.getB().getC().getD().getE().get...getZ().doSomething();
} catch (NullPointerException e){}
The problem with this code is that it may be confuse when maintaining it, since it doesn't show clearly which objects are allowed to be null. But on the other hand is much more concise and less "telescopic".
Is it an acceptable to do this to save development time? How could the API be redesigned to avoid this problem?
The only thing I can think of to avoid the long null checking is to provide void instances of the nested objects and providing isValid
methods for each one of them, but wouldn't this create a lot of innecesary objects in memory?
(I've used Java code, but the same question can apply to C# properties)
Thanks.
I think you could provide static
isValid
methods on each class, for example for classA
that would be:And so on. Then you would have:
However, although I won't get into you business I must say that such a method chaining does not say anything good about the design; maybe it's a sign of need for refactoring.
Using exceptions seem a poor fit here. What if one of the getters contained non-trivial logic, and threw a NullPointerException? Your code would swallow that exception without intending to. On a related note, your code samples exhibit different behaviour if
parentObject
isnull
.Also, there really is no need to "telescope":
Personally I like to avoid this problem altogether by using an option type. By adjusting the value returned from these methods/properties to be
Option<T>
rather thanT
the caller can choose how they wish to handle the case of no value.An option type can either have a contained value or not (but the option itself can never be null), but the caller cannot simply pass it on without unwrapping the value so it forces the caller to deal with the fact there may be no value.
E.g. in C#:
If the caller wants to throw, they merely retrieve the value without explicitly checking to see if there is one:
If the caller wants to just default if any step doesn't have a value, they can perform mapping/binding/projection:
If the caller wants to default at each stage, they can:
Option
is not currently part of C# but I imagine one day will be. You can get an implementation by referencing the F# libraries or you may be able to find an implementation on the web. If you'd like mine, let me know and I'll send it to you.