Lazy initialization with func

Published on den 5 November 2010

This post is about how you can use Func to intialize properties in a lazy while avoiding some if logic.

Background

What does null mean? It might seem like a simple question and you might say that the answer is that the variable has not been initialized. Hopefully you realize that this is only half the fact though. The problem is that null sometimes doesn't match our domain and we often let null mean more than one thing. It could be that the variable is not intialized but it could also be that a call to the database didn't find a matching record and the result therefore is null.

Not thinking through what null really means in your problem domain might lead to defects. I came across this problem today. I was working on the homepage for my club and as usual I was running SQL Server Profiler.  What almost caused me to fall of my chair was the lines below in SSP.

LazyInit_Before

The reason this suprised me was damn sure I was caching away the current user in my service. A quick look at the code confirmed that it should be cached.

public User GetUser()
{

    if (this.currentUser == null)
    {
        this.currentUser = this.membershipRepository.GetUser();
        if (this.currentUser != null)
        {
            this.currentUser.Avatar = new AvatarImage(this.avatarSettingsReader.AvatarPath, this.currentUser.UserName, p => File.Exists(this.avatarSettingsReader.MapPath(p)));
        }
    }
    return this.currentUser;

}

The clue that made me realize my misstake was that I was testing in FF and IE in parallell and in FF I was logged in and there the user was only fetched from the db once. I had considered the meaning of null as "The item  needs to be fetched" when in reality it could also mean that the "The item has been fetched but had no value".

So how to solve the problem?

To be clear I consider the problem to be that I wanted to give null a meaning(Not fetched) when my domain already had a meaning for null (Not logged in).

Changing the domain was out  of the question because that would have meant more work. The first thought was to add a hasLoaded boolean. The first check in the code above would simply have changed in that case. I'm not sure why but I don't like having flags like these in my code so I came up with another approach.

I created a private variable:

private Func getUserFunc;

And in the constructor I instialized it to:

this.getUserFunc = () =>
{
   this.currentUser = this.membershipRepository.GetUser();
   if (this.currentUser != null)
   {
       this.currentUser.Avatar = new AvatarImage(this.avatarSettingsReader.AvatarPath, this.currentUser.UserName, p => File.Exists(this.avatarSettingsReader.MapPath(p)));
   }
   this.getUserFunc = () => this.currentUser;
   return this.currentUser;
};

Note line 8 where the func alter itself. So the method above only runs once then it alter itself to return the saved value.

My GetUser method now reads:

public User GetUser()
{
    return this.getUserFunc();
}

As seen below the generated SQL is now what I would expect.

LazyInit_After

Conclusion

Take a few seconds to consider if null already has a  meaning in your domain before assigning it a new one. 

I'm not sure if the way I solved it above is good or not. I'm afraid it might make the code harder to understand. I will have to try it out and see what I think of it. 

Then feel free to it or if you have any comments or questions mention @MikaelEliasson on Twitter.

CTO and co-founder at Bokio with a background as an elite athlete. Still doing a lot of sports but more for fun.

#development, #web, #orienteering, #running, #cycling, #boardgames, #personaldevelopment