tags:

views:

664

answers:

7

We've all been there, we have some deep property like cake.frosting.berries.loader that we need to check if it's null so there's no exception. The way to do is is to use a short-circuiting if statement

if (cake != null && cake.frosting != null && cake.frosting.berries != null) ...

This strikes me however as not very elegant, there should perhaps be an easier way to check the entire chain and see if it comes up against a null variable/property.

So is it possible using some extension method or would it be a language feature, or is it just a bad idea?

+16  A: 

If you need to have such an expression in your code, you are violating the Law of Demeter. You should consider redesigning so that you don't need to access properties of properties of properties of an object directly.

In the few cases where it actually makes sense to violate that law, the way it works is pretty concise, thanks to the short-circuiting "and" operator.

Mehrdad Afshari
I like Martin Fowler's take on the "Law" ... he calls it the occassionally useful suggestion of demeter ;)
Daniel Elliott
@Daniel, fabulous quote. Googling for it found me a fine paper, "The Law of Demeter is Not a Dot Counting Exercise": http://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx
Wayne Conrad
That's like saying "if you get seasick, sink all ships". I've never understood the rationale behind this suggestion, other than being a code smell for potentially to tight coupling when it crosses an isolation domain. I'd love to see a **reasonable** redesign of any of these examples.
peterchen
@peterchen: My answer consists of two paragraphs. Read the second too.
Mehrdad Afshari
I've read that, too, but my questions remain - why this should be a "law" at all, and how would a design avoiding the property chain look like. These question's aren't directed at you, though ;)
peterchen
@peterchen: In theory a desirable characteristics to reduce coupling, however, in practice, it can be costly (contradicts YAGNI). Engineering practices are all about these kind of trade-offs, after all. The point of my answer is, it does violate a "law" (which is appropriate most of the time), so you should *consider* looking at your design to see whether you have violated that "law" for a valid reason. If it's valid, then go on by all means. I completely agree with you on this that these "laws" are not meant to be blindly followed.
Mehrdad Afshari
I agree in theory but there are however cases where you still end up with this kind of syntax, and adding too many layers of classes can get too messy if they are more like poltergeists
MattiasK
@Mattias: Indeed there are such cases but adding a feature to the language for every small thing like this will make it too bloated. Maybe it's acceptable for ruby but doesn't look "right" for C#.
Mehrdad Afshari
+9  A: 

Besides violating the Law of Demeter, as Mehrdad Afshari has already pointed out, it seems to me you need "deep null checking" for decision logic.

This is most often the case when you want to replace empty objects with default values. In this case you should consider implementing the Null Object Pattern. It acts as a stand-in for a real object, providing default values and "non-action" methods.

Johannes Rudolph
"Objective-C"-ish approach to solve the problem ;)
Mehrdad Afshari
no, objective-c allows sending messages to null objects and returns the appropriate default value if necessary. No problems there.
Johannes Rudolph
@Johannes: Yeah. That's the point. Basically, you'll emulate the ObjC behavior with Null Object Pattern.
Mehrdad Afshari
Ah yes, now I see. I didn't get that one :-)
Johannes Rudolph
+4  A: 

Another, albeit not very nice option (apart from re-designing your code, see Mehrdad Afshari's answer) would be to use a try..catch block to see if a NullReferenceException occurs sometime during that deep property lookup.

try
{
    var x = cake.frosting.berries.loader;
    ...
}
catch (NullReferenceException ex)
{
    // either one of cake, frosting, or berries was null
    ...
}

I personally wouldn't do this. It doesn't look nice, and since it uses exception handling, it probably also doesn't perform very well.

So is it possible using some extension method or would it be a language feature, [...]

This would almost certainly have to be a language feature, unless C# already had more sophisticated lazy evaluation, or unless you want to use reflection (which probably also isn't a good idea for reasons of performance and type-safety).

Since there's no way to simply pass cake.frosting.berries.loader to a function (it would be evaluated and throw a null reference exception), you would have to implement a general look-up method in the following way: It takes in an objects and the names of properties to look up:

static object LookupProperty( object startingPoint, params string[] lookupChain )
{
    // 1. if 'startingPoint' is null, return null, or throw an exception.
    // 2. recursively look up one property/field after the other from 'lookupChain',
    //    using reflection.
    // 3. if one lookup is not possible, return null, or throw an exception.
    // 3. return the last property/field's value.
}

...

var x = LookupProperty( cake, "frosting", "berries", "loader" );

(Note: code edited.)

You quickly see several problems with such an approach. First, you don't get any type safety and possible boxing of property values of a simple type. Second, you can either return null if something goes wrong, and you will have to check for this in your calling function, or you throw an exception, and you're back to where you started. Third, it might be slow. Fourth, it looks uglier than what you started with.

[...], or is it just a bad idea?

I'd either stay with:

if (cake != null && cake.frosting != null && ...) ...

or go with the above answer by Mehrdad Afshari.

stakx
I Don't know why this was downvoted, I did an upvote for balance: Answer is correct and brings in a new aspect (and explicitely mentions the drawbacks of this solution...)
MartinStettner
Danke, Martin, your balance vote is appreciated.
stakx
+1 from me, it's the only answer the directly addresses the question instead of the stock "don't do that" answer
fearofawhackplanet
+9  A: 

I've found this extension to be quite useful for deep nesting scenarios.

public static R Coal<T, R>(this T obj, Func<T, R> f)
    where T : class
{
    return obj != null ? f(obj) : default(R);
}

It's an idea I derrived from the null coalescing operator in C# and T-SQL. The nice thing is that the return type is always the return type of the inner property.

That way you can do this:

var berries = cake.Coal(x => x.frosting).Coal(x => x.berries);

...or a slight variation of the above:

var berries = cake.Coal(x => x.frosting, x => x.berries);

It's not the best syntax I know, but it does work.

John Leidegren
+1...in our project it's called "IfNotNull"
flq
Why "Coal", that looks a extremely creepy. ;) However, your sample would fail if frosting were null. Should've looked like so: var berries = cake.NullSafe(c => c.Frosting.NullSafe(f => f.Berries));
Robert Giesecke
Oh, but you're implying that the second argument is not a call to Coal which it of course has to be. It just a convenient alteration. The selector (x => x.berries) is passed to a Coal call inside the Coal method that takes two arguments.
John Leidegren
The name coalescing or coalesce was taken from T-SQL, that's where I first got the idea. IfNotNull implies that something takes place if not null, however what that is, is not explained by the IfNotNull method call. Coal is indeed an odd name, but this is in deed an odd method worth taking notice of.
John Leidegren
The best literally name for this would be something like "ReturnIfNotNull" or "ReturnOrDefault"
John Leidegren
+27  A: 

We have considered adding a new operation ".?" to the language that has the semantics you want. That is, you'd say

cake.?frosting.?berries.?loader

and the compiler would generate all the short-circuiting checks for you.

It didn't make the bar for C# 4. Perhaps for a hypothetical future version of the language.

Eric Lippert
That would rock.
EricLaw -MSFT-
Love it but without the ., i.e. cake?frosting?berries?loader. I also want similar functionality for the null coalescing operator: return cake.frosting ?? new ButterCream();
Jamie Ide
Without the dot it becomes syntactically ambiguous with the conditional (A?B:C) operator. We try to avoid lexical constructs that require us to "look ahead" arbitrarily far in the token stream. (Though, unfortunately, there already are such constructs in C#; we'd rather not add any more.)
Eric Lippert
While I would welcome a null-safe dereference operator, the `.?` is a bit hard on the eyes. I would propose something like `..` instead. On a separate note, out of curiosity, what are some examples of lexical constructs in C# that require arbitrarily long look ahead?
LBushkin
@LBushkin - There's plenty of things which are not used for operators, today, that are as of C# 4.0, and to my knowledge illegal. i.e. # and $, so you could write cake#frosting#berries that are not ambiguous.@Eric - I think adding a .? operator will be unnecessary, if you think about another promise, which is to open up the compiler as a service. I'm not really sure what Anders means about that, but I have an idea myself. And that's to be able to manipulate expression trees at compile time. It would allow for a lot more language flexibility and it won't require new operators.
John Leidegren
@LBushkin: Pavel's comment on this post describes one situation: http://stackoverflow.com/questions/1561515/where-can-i-find-c-3-0-grammar/1561621#1561621
Mehrdad Afshari
@LBushkin: We also do deep lookahead when attempting to figure out is "(something)anotherthing" a cast and its operand, or a parenthesized expression followed by anotherthing. For example, "(Foo.Bar)/Blah" vs "(Foo.Bar)Blah". The rules here are quite complicated, see section 7.6.6 for details. Or section 7.5.4.2 also has some interesting situations where parsing requires considerable lookahead and heuristics.
Eric Lippert
please don't add it, this is problem that is not very common
Ian Ringrose
@Ian: this problem is *extremely* common. This is one of the most frequent requests that we get.
Eric Lippert
There's a .Net language, called Oxygene, which has this feature a while now. ( http://prismwiki.codegear.com/en/Colon_Operator ) I used to write some parts of my software in it, and I really, really miss this operator. It would turn value type-results into nullables. And you could call the methods of the value type that is nullable directly, w/o going through GetValueOrDefault. Nullable<SomeStruct> x; x:SomeMethod();
Robert Giesecke
@Eric, maybe because I know the Null Object Pattern and tend to avoid code the reach deep into other objects I don't hit this.
Ian Ringrose
@Ian: I also prefer to use the null object pattern when feasible to do so, but most people do not have the luxury of working with object models that they themselves designed. Lots of existing object models use nulls and so that's the world we have to live with.
Eric Lippert
@Eric - If you give a man a fish, he will be fed for the day, if you teach the man to fish, he'll never go hungry again, or so I've heard. If you you give inexperienced programmers a short-hand notation to avoid thinking about the problems, I reckon I'll be having an even more difficult time trying to convince our development team to think about the architectural implications of they way they write code. You should promote more good language practices than giving people cheap tricks of getting out of a bad situation.
John Leidegren
@John: We get this feature request almost entirely *from* our most experienced programmers. The MVPs ask for this *all the time*. But I understand that opinions vary; if you'd like to give a constructive language design suggestion in addition to your criticism, I'm happy to consider it.
Eric Lippert
@Eric - My original proposition was to expose expression trees at compile time. I strongly believe in turning the compiler in to a service I can control and it won't really require any syntactic sugar. e.g. Coal(x => x.cake.frosting.color) is transformed at compile time into appropriate short circuiting code by the compile time transform Coal. Coal looks something like this, const Expression<Func<T, V>> Coal<T, V>(this T obj, Expression<Func<T, V>> expr). I've re-purposed the const keyword to act as both a static modifier and compile time flag. The returned expression tree is emitted as IL.
John Leidegren
Hypothetically awesome!
Mel Gerats
+5  A: 

I got inspired by this question to try and find out how this kind of deep null checking can be done with an easier / prettier syntax using expression trees. While I do agree with the answers stating that it might be a bad design if you often need to access instances deep in the hierarchy, I also do think that in some cases, such as data presentation, it can be very useful.

So I created an extension method, that will allow you to write:

var berries = cake.IfNotNull(c => c.Frosting.Berries);

This will return the Berries if no part of the expression is null. If null is encountered, null is returned. There are some caveats though, in the current version it will only work with simple member access, and it only works on .NET Framework 4, because it uses the MemberExpression.Update method, which is new in v4. This is the code for the IfNotNull extension method:

using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace dr.IfNotNullOperator.PoC
{
    public static class ObjectExtensions
    {
        public static TResult IfNotNull<TArg,TResult>(this TArg arg, Expression<Func<TArg,TResult>> expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression");

            if (ReferenceEquals(arg, null))
                return default(TResult);

            var stack = new Stack<MemberExpression>();
            var expr = expression.Body as MemberExpression;
            while(expr != null)
            {
                stack.Push(expr);
                expr = expr.Expression as MemberExpression;
            } 

            if (stack.Count == 0 || !(stack.Peek().Expression is ParameterExpression))
                throw new ApplicationException(String.Format("The expression '{0}' contains unsupported constructs.",
                                                             expression));

            object a = arg;
            while(stack.Count > 0)
            {
                expr = stack.Pop();
                var p = expr.Expression as ParameterExpression;
                if (p == null)
                {
                    p = Expression.Parameter(a.GetType(), "x");
                    expr = expr.Update(p);
                }
                var lambda = Expression.Lambda(expr, p);
                Delegate t = lambda.Compile();                
                a = t.DynamicInvoke(a);
                if (ReferenceEquals(a, null))
                    return default(TResult);
            }

            return (TResult)a;            
        }
    }
}

It works by examining the expression tree representing your expression, and evaluating the parts one after the other; each time checking that the result is not null.

I am sure this could be extended so that other expressions than MemberExpression is supported. Consider this as proof-of-concept code, and please keep in mind that there will be a performance penalty by using it (which will probably not matter in many cases, but don't use it in a tight loop :-) )

driis
I'm impressed by your lambda skills :) the syntax does however seem to be a tad bit more complex than one would like, atleast for the if-statement scenario
MattiasK
+1  A: 

One option is to use the Null Object Patten, so instead of having null when you don’t have a cake, you have a NullCake that returns a NullFosting etc. Sorry I am not very good at explaining this but other people are, see

Ian Ringrose