169

I have a strange habit it seems... according to my co-worker at least. We've been working on a small project together. The way I wrote the classes is (simplified example):

[Serializable()]
public class Foo
{
    public Foo()
    { }

    private Bar _bar;

    public Bar Bar
    {
        get
        {
            if (_bar == null)
                _bar = new Bar();

            return _bar;
        }
        set { _bar = value; }
    }
}

So, basically, I only initialize any field when a getter is called and the field is still null. I figured this would reduce overload by not initializing any properties that aren't used anywhere.

ETA: The reason I did this is that my class has several properties that return an instance of another class, which in turn also have properties with yet more classes, and so on. Calling the constructor for the top class would subsequently call all constructors for all these classes, when they are not always all needed.

Are there any objections against this practice, other than personal preference?

UPDATE: I have considered the many differing opinions in regards to this question and I will stand by my accepted answer. However, I have now come to a much better understanding of the concept and I'm able to decide when to use it and when not.

Cons:

  • Thread safety issues
  • Not obeying a "setter" request when the value passed is null
  • Micro-optimizations
  • Exception handling should take place in a constructor
  • Need to check for null in class' code

Pros:

  • Micro-optimizations
  • Properties never return null
  • Delay or avoid loading "heavy" objects

Most of the cons are not applicable to my current library, however I would have to test to see if the "micro-optimizations" are actually optimizing anything at all.

LAST UPDATE:

Okay, I changed my answer. My original question was whether or not this is a good habit. And I'm now convinced that it's not. Maybe I will still use it in some parts of my current code, but not unconditionally and definitely not all the time. So I'm going to lose my habit and think about it before using it. Thanks everyone!

Machavity
  • 30,841
  • 27
  • 92
  • 100
John Willemse
  • 6,608
  • 7
  • 31
  • 45
  • 14
    This is the lazy-load pattern, its not exactly giving you a wonderful benefit here but it's still a good thing imho. – Machinarius Feb 08 '13 at 13:50
  • 28
    Lazy instantiation makes sense if you have a measurable performance impact, or if those members are rarely used and consuming an exorbitant amount of memory, or if it takes a long time to instantiate them and only want to do it on demand. At any rate, be sure to account for thread safety issues (your current code is _not_) and consider using the provided [Lazy](http://msdn.microsoft.com/en-us/library/dd642331.aspx) class. – Chris Sinclair Feb 08 '13 at 13:51
  • 10
    I think this question fits better on http://codereview.stackexchange.com – Eduardo Brites Feb 08 '13 at 13:52
  • 7
    @PLB it is not a singleton pattern. – Colin Mackay Feb 08 '13 at 13:53
  • @Machinarius Thanks for your input. I'll lookup info on that pattern. – John Willemse Feb 08 '13 at 13:53
  • @PLB this is not a singleton pattern – malkassem Feb 08 '13 at 13:54
  • @PLB Sorry, I know what a singleton is, and this is not it. – John Willemse Feb 08 '13 at 13:54
  • @ChrisSinclair Thanks, I'll check out `Lazy` first. – John Willemse Feb 08 '13 at 13:56
  • Thanks everyone for your quick advice. I now know I'm generally better off not doing it this way. I guess it's never too late to learn! – John Willemse Feb 08 '13 at 14:07
  • @EduardoBrites Thanks, I will consider that next time for any coding styles issues! – John Willemse Feb 08 '13 at 14:10
  • I think you need to reconsider the accepted answer. – AMissico Feb 08 '13 at 14:20
  • Rarely is there a `Set` property for collections. – AMissico Feb 08 '13 at 14:21
  • @AMissico I know, bad example. I will edit the question. – John Willemse Feb 08 '13 at 14:24
  • Wonder if it is thread safe? If not how to make it thread safe? – Amitd Feb 08 '13 at 19:21
  • 30
    I am surprised that no one has mentioned a serious bug with this code. You have a public property which I can set it from outside. If I set it to NULL, you will always create a new object and ignore my setter access. This could be a very serious bug. For private properties, this could be okie. Personally, I don't like to make such premature optimizations. Adds complexity for no additional benefit. – SolutionYogi Feb 08 '13 at 19:32
  • @SolutionYogi; The code is not in question. It is the code pattern. For instance, if `Bar` is a collection then you would not have a `Set` method ("setter"). If thread safety was important, you would add a `lock`. – AMissico Feb 08 '13 at 22:43
  • @Amitd; you would surround the `if` statement block with a `lock(_bar)` statement block. – AMissico Feb 08 '13 at 23:37
  • @AMissico As I mentioned already, if it's a private property or property without a setter, it is okie. But the code as listed in the question has a serious bug where you are discarding 'null' set by the calling code. – SolutionYogi Feb 08 '13 at 23:44
  • @SolutionYogi You are right, and the example is just that, an example. I should have considered it a bit better, because I'm aware of the bug that may arise. The properties in my library are never public and most don't have a setter at all. – John Willemse Feb 08 '13 at 23:55
  • 2
    Looking at your pro arguments, they are all wrong. Micro-optimizations: never optimize early, it's the root of all evil (specially clever ones like lazy init). Properties never return null: you can take care of that in the constructor a properly implemented setters, so this is not an argument. Delay or avoid heavy objects: if you're doing this as a habit then you're not even looking if they are heavy objects. If you think an object with 30 properties is heavy then you should look again. You got an upvote for an excellent question but I must downvote as well for a terrible answer you chose. – Alex Feb 09 '13 at 03:54
  • 5
    Not to mention the fact you're turning a simple single line declaration (auto property) into a 11 line code mogul which is 10 times more code that people have to maintain. Why would you ever do that to people? There are no pro arguments that can possibly overcome the huge list of cons for what you're doing. – Alex Feb 09 '13 at 04:00
  • 2
    Random observation: `if(foo == null) foo = new Foo()` can be simplified to `foo = foo ?? new Foo()` – JerKimball Feb 12 '13 at 22:35
  • Objective-C has a convention called "lazy initializer" and basically it initialize objects in getters as well. – Shane Hsu Feb 13 '13 at 02:05
  • You should only be optimizing the code if the code isn't fast enough. Don't make assumptions upfront. Have you used a profiling tool which showed this property to be a concern? Are there other areas of the code that could use improvement? Although Lazy initialization has its place, littering the code with if statements in get accessors in this fashion really makes for ugly code. Short answer? If your code has noticeably improved as a result, keep it, otherwise, remove it. – Razor Feb 13 '13 at 04:24
  • Because this question still receives traffic I revised my answer. You might want to look at it, to better understand why I am against using lazy initialization unconditionally. – Daniel Hilgarth Feb 13 '13 at 07:30
  • @DanielHilgarth After much consideration and reading your new addition, I have decided to pick your answer after all. Many of my colleagues with much more experience than me seem to agree with you and advise me to lose the pattern unless absolutely necessary. – John Willemse Feb 13 '13 at 08:34
  • @JohnWillemse: I am glad I could convince you that there is more to this pattern than the previously accepted answer showed. – Daniel Hilgarth Feb 13 '13 at 08:36
  • 1
    @JohnWillemse I'm so relieved you changed your mind :) – Alex Feb 15 '13 at 13:27
  • 1
    How is Micro-optimizations in the pros AND cons list? – hofnarwillie Aug 21 '13 at 10:26

9 Answers9

173

What you have here is a - naive - implementation of "lazy initialization".

Short answer:

Using lazy initialization unconditionally is not a good idea. It has its places but one has to take into consideration the impacts this solution has.

Background and explanation:

Concrete implementation:
Let's first look at your concrete sample and why I consider its implementation naive:

  1. It violates the Principle of Least Surprise (POLS). When a value is assigned to a property, it is expected that this value is returned. In your implementation this is not the case for null:

    foo.Bar = null;
    Assert.Null(foo.Bar); // This will fail
    
  2. It introduces quite some threading issues: Two callers of foo.Bar on different threads can potentially get two different instances of Bar and one of them will be without a connection to the Foo instance. Any changes made to that Bar instance are silently lost.
    This is another case of a violation of POLS. When only the stored value of a property is accessed it is expected to be thread-safe. While you could argue that the class simply isn't thread-safe - including the getter of your property - you would have to document this properly as that's not the normal case. Furthermore the introduction of this issue is unnecessary as we will see shortly.

In general:
It's now time to look at lazy initialization in general:
Lazy initialization is usually used to delay the construction of objects that take a long time to be constructed or that take a lot of memory once fully constructed.
That is a very valid reason for using lazy initialization.

However, such properties normally don't have setters, which gets rid of the first issue pointed out above.
Furthermore, a thread-safe implementation would be used - like Lazy<T> - to avoid the second issue.

Even when considering these two points in the implementation of a lazy property, the following points are general problems of this pattern:

  1. Construction of the object could be unsuccessful, resulting in an exception from a property getter. This is yet another violation of POLS and therefore should be avoided. Even the section on properties in the "Design Guidelines for Developing Class Libraries" explicitly states that property getters shouldn't throw exceptions:

    Avoid throwing exceptions from property getters.

    Property getters should be simple operations without any preconditions. If a getter might throw an exception, consider redesigning the property to be a method.

  2. Automatic optimizations by the compiler are hurt, namely inlining and branch prediction. Please see Bill K's answer for a detailed explanation.

The conclusion of these points is the following:
For each single property that is implemented lazily, you should have considered these points.
That means, that it is a per-case decision and can't be taken as a general best practice.

This pattern has its place, but it is not a general best practice when implementing classes. It should not be used unconditionally, because of the reasons stated above.


In this section I want to discuss some of the points others have brought forward as arguments for using lazy initialization unconditionally:

  1. Serialization:
    EricJ states in one comment:

    An object that may be serialized will not have it's contructor invoked when it is deserialized (depends on the serializer, but many common ones behave like this). Putting initialization code in the constructor means that you have to provide additional support for deserialization. This pattern avoids that special coding.

    There are several problems with this argument:

    1. Most objects never will be serialized. Adding some sort of support for it when it is not needed violates YAGNI.
    2. When a class needs to support serialization there exist ways to enable it without a workaround that doesn't have anything to do with serialization at first glance.
  2. Micro-optimization: Your main argument is that you want to construct the objects only when someone actually accesses them. So you are actually talking about optimizing the memory usage.
    I don't agree with this argument for the following reasons:

    1. In most cases, a few more objects in memory have no impact whatsoever on anything. Modern computers have way enough memory. Without a case of actual problems confirmed by a profiler, this is pre-mature optimization and there are good reasons against it.
    2. I acknowledge the fact that sometimes this kind of optimization is justified. But even in these cases lazy initialization doesn't seem to be the correct solution. There are two reasons speaking against it:

      1. Lazy initialization potentially hurts performance. Maybe only marginally, but as Bill's answer showed, the impact is greater than one might think at first glance. So this approach basically trades performance versus memory.
      2. If you have a design where it is a common use case to use only parts of the class, this hints at a problem with the design itself: The class in question most likely has more than one responsibility. The solution would be to split the class into several more focused classes.
Community
  • 1
  • 1
Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • Because there will be many instances of the same classes (which are a lot more complicated than what I showed as an example) and the use of the properties depends on the user input/request. – John Willemse Feb 08 '13 at 13:52
  • 4
    @JohnWillemse: That's a problem of your architecture. You should refactor your classes in a way that they are smaller and more focused. Don't create one class for 5 different things / tasks. Create 5 classes instead. – Daniel Hilgarth Feb 08 '13 at 13:53
  • 27
    @JohnWillemse Perhaps consider this a case of premature optimization then. Unless you have a _measured_ performance/memory bottleneck, I'd recommend against it as it increases complexity and introduces threading issues. – Chris Sinclair Feb 08 '13 at 13:53
  • The null check is trivial (and some would even consider it defensive programming). Depending on what goes on in the constructor however, it could take a substantial (compared to the null check) amount of time. – Joel B Feb 08 '13 at 17:46
  • If you don't follow this pattern but need to serialize your objects, you must add additional support for deserialization if you use a serializer that does not invoke the object's constructor (many common serializers behave like that). – Eric J. Feb 12 '13 at 19:38
  • 2
    +1, this is not a good design choice for 95% of classes. Lazy initialization has its pros, but shouldn't be generalized for ALL properties. It adds complexity, difficulty to read the code, thread safety issues... for no perceptible optimization in 99% of cases. Also, as SolutionYogi said as a comment, the OP's code is buggy, which proves this pattern is not trivial to implement and should be avoided unless lazy initialization is actually needed. – ken2k Feb 13 '13 at 08:07
  • -1 for thread safety issues. Instance members are by convention not guaranteed to be thread safe and it is a waste of time and thread locks to try to make them safe. – Ilia G Feb 13 '13 at 14:26
  • 2
    @DanielHilgarth Thanks for going all the way to write down (almost) everything wrong with using this pattern unconditionally. Great Job! – Alex Feb 15 '13 at 13:33
  • @DanielHilgarth Great answer. Even though I agree on the main line of argument, I do have some detail remarks. First remark is that POLS is important in this context since the class is Serializable (!) Second remark I have is that Lazy also violates POLS, as I also explained on http://stackoverflow.com/questions/2550925/singleton-by-jon-skeet-clarification (it violates this due to its strange locking and exception behavior, which is unfortunately not well known). Last is that both the Q/A and Lazy aren't a (design) pattern; however, if it all was implemented as a proxy it could be. – atlaste Feb 20 '13 at 07:48
  • @StefandeBruijn: Thanks for your comment. I will start at the back: I don't think I ever called that a design pattern... In my eyes a "pattern" and a "design pattern" are two different things. A "pattern" is just a certain way of writing some code. A "design pattern" is related to the architecture. Thanks for the hint of the problems with `Lazy`, I wasn't aware of them. Lastly, I don't understand your first remark. POLS is important, I agree, and I pointed that out in my answer. So I don't really see what you are trying to tell me here :) – Daniel Hilgarth Feb 20 '13 at 07:55
  • @DanielHilgarth Actually you call it a pattern, which is IMO easily mistaken for design pattern. But that can also be just my experience :-) As for POLS, the fact that Foo is serializable means he probably doesn't control when get and set are called; if you simply serialize and deserialize the class, you already get different a different object because of the 'null' case. Also adding lazy in a serialized class makes no sense at all: the property will almost always be called by the deserializer. POLS usually is just a netiquette - here it will yield unexpected behavior and doesn't make sense. – atlaste Feb 20 '13 at 08:03
  • So I'm not trying to say you're wrong; on the contrary: I'm trying to tell that it's more important than anyone noted in this particular case, **because** the class is marked Serializable. – atlaste Feb 20 '13 at 08:04
  • @StefandeBruijn: Ah, now I get it :) Very good point. About "design" vs "design pattern": I updated my original comment while you wrote yours, I guess. – Daniel Hilgarth Feb 20 '13 at 08:06
  • @StefandeBruijn: I think that the POLS violation in the serialization case is a sub case of the general problem that you will never get `null` from such a property. – Daniel Hilgarth Feb 20 '13 at 08:07
  • 1
    @DanielHilgarth Well yes and no. The violation is the issue here so yes. But also 'no' because POLS is strictly the principle that you *probably won't be surprised by the code*. If Foo was not exposed outside of your program, it's a risk you can take or not. In this case, I can almost guarantee that *you will eventually be surprised*, because you don't control the way the properties are accessed. The risk just became a bug, and your argument about the `null` case became much stronger. :-) – atlaste Feb 20 '13 at 08:16
50

It is a good design choice. Strongly recommended for library code or core classes.

It is called by some "lazy initialization" or "delayed initialization" and it is generally considered by all to be a good design choice.

First, if you initialize in the declaration of class level variables or constructor, then when your object is constructed, you have the overhead of creating a resource that may never be used.

Second, the resource only gets created if needed.

Third, you avoid garbage collecting an object that was not used.

Lastly, it is easier to handle initialization exceptions that may occur in the property then exceptions that occur during initialization of class level variables or the constructor.

There are exceptions to this rule.

Regarding the performance argument of the additional check for initialization in the "get" property, it is insignificant. Initializing and disposing an object is a more significant performance hit than a simple null pointer check with a jump.

Design Guidelines for Developing Class Libraries at http://msdn.microsoft.com/en-US/library/vstudio/ms229042.aspx

Regarding Lazy<T>

The generic Lazy<T> class was created exactly for what the poster wants, see Lazy Initialization at http://msdn.microsoft.com/en-us/library/dd997286(v=vs.100).aspx. If you have older versions of .NET, you have to use the code pattern illustrated in the question. This code pattern has become so common that Microsoft saw fit to include a class in the latest .NET libraries to make it easier to implement the pattern. In addition, if your implementation needs thread safety, then you have to add it.

Primitive Data Types and Simple Classes

Obvioulsy, you are not going to use lazy-initialization for primitive data type or simple class use like List<string>.

Before Commenting about Lazy

Lazy<T> was introduced in .NET 4.0, so please don't add yet another comment regarding this class.

Before Commenting about Micro-Optimizations

When you are building libraries, you must consider all optimizations. For instance, in the .NET classes you will see bit arrays used for Boolean class variables throughout the code to reduce memory consumption and memory fragmentation, just to name two "micro-optimizations".

Regarding User-Interfaces

You are not going to use lazy initialization for classes that are directly used by the user-interface. Last week I spent the better part of a day removing lazy loading of eight collections used in a view-model for combo-boxes. I have a LookupManager that handles lazy loading and caching of collections needed by any user-interface element.

"Setters"

I have never used a set-property ("setters") for any lazy loaded property. Therefore, you would never allow foo.Bar = null;. If you need to set Bar then I would create a method called SetBar(Bar value) and not use lazy-initialization

Collections

Class collection properties are always initialized when declared because they should never be null.

Complex Classes

Let me repeat this differently, you use lazy-initialization for complex classes. Which are usually, poorly designed classes.

Lastly

I never said to do this for all classes or in all cases. It is a bad habit.

Community
  • 1
  • 1
AMissico
  • 21,470
  • 7
  • 78
  • 106
  • 2
    I will try to find the reference in *Framework Design Guidelines* where this practice is recommended. – AMissico Feb 08 '13 at 14:18
  • Thanks, that's how I thought about it, before I read all the other answers and now I'm back to being confused ;) It's a class library in which I use this. I will just check on the thread safety issues that some have warned about. – John Willemse Feb 08 '13 at 14:20
  • 1
    @JohnWillemse, In this case I do not think thread safety is the responsibility of the class. – AMissico Feb 08 '13 at 14:45
  • 6
    If you can call foo.Bar multiple times in different threads without any intervening value setting but get different values, then you have a lousy poor class. – Lie Ryan Feb 08 '13 at 17:24
  • 26
    I think this is a bad rule of thumb without many considerations. Unless Bar is a know resource hog, this is a needless micro optimization. And in the case that Bar is resource intensive, there is the thread safe Lazy built into .net. – Andrew Hanlon Feb 08 '13 at 18:22
  • @ach, `Lazy` was created exactly for what the poster wants. If you have older versions of .NET, you have to use the code pattern illustrated in the question. This code pattern has become so common that Microsoft saw fit to include a class in the latest .NET libraries to make it easier to implement. – AMissico Feb 08 '13 at 19:19
  • 2
    @ach No, knowing whether or not `Bar` is a resource hog while working with `Foo` increases the mental coupling between them. Best to keep it simple and use this pattern (either as posted in the question or using `Lazy`; just don't do it in the constructor (which is what the question was about)). – Izkata Feb 08 '13 at 20:34
  • 10
    "it is easier to handle initialization exceptions that may occur in the property then exceptions that occur during initialization of class level variables or the constructor." - okay, this is silly. If an object can't be initialized for some reason, I want to know ASAP. I.e. immediately when it's constructed. There are good arguments to be made for using lazy initialisation but I don't think it's a good idea to use it *pervasively*. – millimoose Feb 08 '13 at 20:53
  • 1
    Also, re: "the resource only gets created if needed" and "you avoid garbage collecting an object that was not used" - it's not even remotely a given that the performance gain from this will outweigh the fact you complicate creating the object when it is needed. At least when you use the threadsafe (and thus probably more complex) `Lazy`. This is why premature microoptimisations are frowned upon; not just because they're too little benefit to be worth the bother, but also because you have no idea whether they'll help in the first place. – millimoose Feb 08 '13 at 20:56
  • @millimoose; >>exceptions...constructor" this is silly.<< Why? It depends on the class implementation. For example, I would want to handle any `Bar` constructor exceptions when accessing the propery. Not in the `Foo` constructor given that I may never access the `Bar` property. The hardest code to refactor, rework, maintain contains class constructors doing "heavy-work". Moreover, if is extremely difficult to unit test these kinds of classes, but you can easily unit test lazy-initialization methods/properties. – AMissico Feb 08 '13 at 22:57
  • 1
    @lzkata, thank you for pointing out what the question is about. It seems there are some who are really not reading the question. – AMissico Feb 08 '13 at 23:01
  • 20
    I'm really worried that other developers will see this answer and think this is indeed a good practice (oh boy). This is a very very bad practice if you are using it unconditionally. Besides what has already been said, you're making everybody's life so much harder (for client developers and for maintenance developers) for so little gain (if any gain at all). You should hear from the pros: Donald Knuth, in the series The Art of Computer Programming, famously said "premature optimization is the root of all evil.". What you're doing is not only evil, is diabolic! – Alex Feb 09 '13 at 03:40
  • 4
    There are so many indicators you're choosing the wrong answer (and the wrong programming decision). You have more cons than pros in your list. You have more people vouching against it than for it. The more experienced members of this site (@BillK and @DanielHilgarth) that posted in this question are against it. Your coworker already told you it's wrong. Seriously, it's wrong! If I catch one of the developers of my team (I'm a team leader) doing this, he'll take a 5 min timeout and then be lectured why he should never do this. – Alex Feb 09 '13 at 03:47
  • 3
    Another point on the Con list, and a counter argument to the 'library code' reasoning is that your consumer will not be aware that all of the properties are Lazy loaded. They may reasonably expect a property to return immediately (in UI binding for example) where in your code the lazy initialization of Bar can easily be non-trivial. You should really consider changing the accepted answer and practice. – Andrew Hanlon Feb 11 '13 at 18:18
  • An object that may be serialized will not have it's contructor invoked when it is deserialized (depends on the serializer, but many common ones behave like this). Putting initialization code in the constructor means that you have to provide additional support for deserialization. This pattern avoids that special coding. – Eric J. Feb 12 '13 at 19:37
  • 2
    Never seen so wrong answer with so many upvotes and accepted as an answer! – Piotr Perak Feb 12 '13 at 21:26
  • @EricJ. It's a good thing that the constructor is not called again. After all you're deserializing an object that **has already been constructed**. By definition the constructor should be called only once, if you want to call it twice then it's not a constructor anymore, is it? This pattern doesn't avoid that special coding, it actually makes it much more complicated. You have to know if a certain property was initialized prior to the serialization. Again a bunch of if statements all over the code to deal with the situation. You just proved another Con, this pattern makes serialization harder. – Alex Feb 12 '13 at 21:36
  • 3
    @Peri I'm baffled that people keep upvoting this answer without thinking of the consequences. The user clearly stated in his question "it's a strange habit". I feel for the poor souls of new developers which will learn the hard way why this is not only strange but indeed a **very bad habit**. – Alex Feb 12 '13 at 21:42
  • @Alex: Some serializers *do* call the constructor and some *do not*. It's not consistent. Some serializers only serialize the state of public properties (which is often *not* the entire state of the object) while others serialize everything. Using an object pattern that works well with any likely serializer adds to flexibility. – Eric J. Feb 12 '13 at 21:52
  • @EricJ. I guess that's a Pro then. I still don't see how this helps at all compared to all other Cons discussed in here. To me this is clearly the wrong answer and clearly the wrong message to send to other developers. I don't care how many small Pros are listed, early micro-optimizations like this shouldn't be praised for. – Alex Feb 13 '13 at 01:10
  • 1
    @Alex: I would not do it for the sake of micro-optimization. I would do it because I have been bitten initializing things like collections in a constructor, only to have the object (much) later serialized by a serializer that doesn't run the constructor, and initializes empty collections to null rather than a new collection instance. Indeed, if the property exposes an interface rather than a concrete collection implementation, serializers that do not consider private fields could not possibly do otherwise. – Eric J. Feb 13 '13 at 01:44
  • 3
    -1, this is not a good design choice for 95% of classes. Lazy initialization has its pros, but shouldn't be generalized for ALL properties. It adds complexity, difficulty to read the code, thread safety issues... for no perceptible optimization in 99% of cases. Also, as SolutionYogi said as a comment, the OP's code is buggy, which proves this pattern is not trivial to implement and should be avoided unless you actually needs lazy initialization. – ken2k Feb 13 '13 at 08:04
  • @EricJ. This is pointless. You might have several reasons to use lazy inits, I'm not saying they are bad. I'm saying using them without a good reason (as a habit) is! Whatever arguments you have are specific to your problem. Does it mean every time you write a new class you will use lazy init just in case the class is serialized? **NO!** Specially because the price for doing that is huge so you must have a very good reason to use it. The whole point here is this is not a pattern you should use without further consideration. So this is not a good overall habit and we shouldn't be teaching that. – Alex Feb 15 '13 at 13:23
  • Ignoring all the argument above the sentence *it is generally considered **by all** to be a good design choice.* is very misleading and the comments above prove that. – Liam Oct 26 '15 at 11:35
17

Do you consider implementing such pattern using Lazy<T>?

In addition to easy creation of lazy-loaded objects, you get thread safety while the object is initialized:

As others said, you lazily-load objects if they're really resource-heavy or it takes some time to load them during object construction-time.

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • Thanks, I understand it now and I will definitely look into `Lazy` now, and refrain from using the way I always used to do. – John Willemse Feb 08 '13 at 14:09
  • 1
    You don't get *magic* thread safety... you still have to think about it. From MSDN: `Making the Lazy object thread safe does not protect the lazily initialized object. If multiple threads can access the lazily initialized object, you must make its properties and methods safe for multithreaded access.` – Eric J. Feb 12 '13 at 19:39
  • @EricJ. Of course, of course. You only get thread-safety when initializing the object, but later you need to deal with synchronization as any other object. – Matías Fidemraizer Feb 12 '13 at 19:44
9

I think it depends on what you are initialising. I probably wouldn't do it for a list as the construction cost is quite small, so it can go in the constructor. But if it was a pre-populated list then I probably wouldn't until it was needed for the first time.

Basically, if the cost of construction outweighs the cost of doing an conditional check on each access then lazy create it. If not, do it in the constructor.

Colin Mackay
  • 18,736
  • 7
  • 61
  • 88
8

The downside that I can see is that if you want to ask if Bars is null, it would never be, and you would be creating the list there.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Luis Tellez
  • 2,785
  • 1
  • 20
  • 28
  • I don't think that's a downside. – Peter Porfy Feb 08 '13 at 13:52
  • Why is that a downside? Just check with any instead against null. if(!Foo.Bars.Any()) – s.meijer Feb 08 '13 at 13:54
  • 6
    @PeterPorfy: It violates [POLS](http://en.wikipedia.org/wiki/Principle_of_least_surprise). You put `null` in, but don't get it back. Normally, you assume you get the same value back that you put into a property. – Daniel Hilgarth Feb 08 '13 at 14:01
  • @DanielHilgarth Thanks again. That is a very valid argument which I hadn't considered before. – John Willemse Feb 08 '13 at 14:06
  • @DanielHilgarth that's true. I thought that the answer told that if something always return a value and never a null then that's wrong. What you say is completely valid. – Peter Porfy Feb 08 '13 at 14:12
  • POLS, are you kidding me. I think someone just made that up. – AMissico Feb 08 '13 at 14:18
  • @AMissico: You might want to click on the link, if you don't know POLS / POLA. That's a very important principle when designing user interfaces (which an API is). – Daniel Hilgarth Feb 08 '13 at 14:34
  • 6
    @AMissico: Its not a made up concept. In much the same way that pushing a button next to a front door is expected to ring a doorbell, things that look like properties are expected to behave like properties. Opening a trap door under your feet is a surprising behavior, especially if the button isn't labelled as such. – Bryan Boettcher Feb 08 '13 at 19:57
  • @insta, I am being sarcastic. – AMissico Feb 08 '13 at 23:04
8

Lazy instantiation/initialization is a perfectly viable pattern. Keep in mind, though, that as a general rule consumers of your API do not expect getters and setters to take discernable time from the end user POV (or to fail).

Tormod
  • 4,551
  • 2
  • 28
  • 50
  • 1
    I agree, and I have edited my question a little. I expect a full chain of underlying constructors to take more time than instantiating classes only when they are needed. – John Willemse Feb 08 '13 at 14:33
8

I was just going to put a comment on Daniel's answer but I honestly don't think it goes far enough.

Although this is a very good pattern to use in certain situations (for instance, when the object is initialized from the database), it's a HORRIBLE habit to get into.

One of the best things about an object is that it offeres a secure, trusted environment. The very best case is if you make as many fields as possible "Final", filling them all in with the constructor. This makes your class quite bulletproof. Allowing fields to be changed through setters is a little less so, but not terrible. For instance:

class SafeClass
{
    String name="";
    Integer age=0;

    public void setName(String newName)
    {
        assert(newName != null)
        name=newName;
    }// follow this pattern for age
    ...
    public String toString() {
        String s="Safe Class has name:"+name+" and age:"+age
    }
}

With your pattern, the toString method would look like this:

    if(name == null)
        throw new IllegalStateException("SafeClass got into an illegal state! name is null")
    if(age == null)
        throw new IllegalStateException("SafeClass got into an illegal state! age is null")

    public String toString() {
        String s="Safe Class has name:"+name+" and age:"+age
    }

Not only this, but you need null checks everywhere you might possibly use that object in your class (Outside your class is safe because of the null check in the getter, but you should be mostly using your classes members inside the class)

Also your class is perpetually in an uncertain state--for instance if you decided to make that class a hibernate class by adding a few annotations, how would you do it?

If you make any decision based on some micro-optomization without requirements and testing, it's almost certainly the wrong decision. In fact, there is a really really good chance that your pattern is actually slowing down the system even under the most ideal of circumstances because the if statement can cause a branch prediction failure on the CPU which will slow things down many many many more times than just assigning a value in the constructor unless the object you are creating is fairly complex or coming from a remote data source.

For an example of the brance prediction problem (which you are incurring repeatedly, nost just once), see the first answer to this awesome question: Why is it faster to process a sorted array than an unsorted array?

Community
  • 1
  • 1
Bill K
  • 62,186
  • 18
  • 105
  • 157
  • Thanks for your input. In my case, none of the classes have any methods that may need to check for null, so that's not an issue. I'll take your other objections into consideration. – John Willemse Feb 09 '13 at 00:15
  • I don't really understand that. It implies that you aren't using your members in the classes where they are stored--that you are just using the classes as data structures. If that's the case you might want to read http://www.javaworld.com/javaworld/jw-01-2004/jw-0102-toolbox.html which has a good description of how your code can be improved by avoiding externally manipulating object state. If you are manipulating them internally, how do you do so without null-checking everything repeatedly? – Bill K Feb 09 '13 at 00:46
  • Parts of this answer are good, but parts seem contrived. Normally when using this pattern, `toString()` would call `getName()`, not use `name` directly. – Izkata Feb 09 '13 at 04:35
  • @BillK Yes, the classes are a huge data structure. All the work is done in static classes. I will check out the article at the link. Thanks! – John Willemse Feb 09 '13 at 07:23
  • 1
    @izkata Actually inside a class it seems to be a toss-up as to weather you use a getter or not, most places I've worked at used the member directly. That aside, if you are always using a getter the if() method is even more harmful because the branch prediction failures will occur more often AND because of the branching the runtime will likely have more trouble inling the getter. It's all moot, however, with john's revelation that they are data structures and static classes, that is the thing I would be most concerned with. – Bill K Feb 11 '13 at 18:24
5

Let me just add one more point to many good points made by others...

The debugger will (by default) evaluate the properties when stepping through the code, which could potentially instantiate the Bar sooner than would normally happen by just executing the code. In other words, the mere act of debugging is changing the execution of the program.

This may or may not be a problem (depending on side-effects), but is something to be aware of.

Community
  • 1
  • 1
Branko Dimitrijevic
  • 50,809
  • 10
  • 93
  • 167
2

Are you sure Foo should be instantiating anything at all?

To me it seems smelly (though not necessarily wrong) to let Foo instantiate anything at all. Unless it is Foo's express purpose to be a factory, it should not instantiate it's own collaborators, but instead get them injected in its constructor.

If however Foo's purpose of being is to create instances of type Bar, then I don't see anything wrong with doing it lazily.

KaptajnKold
  • 10,638
  • 10
  • 41
  • 56