Eric recently posted a blog: “Property or backing store from inside a class?”, and I responded in a way that skirted the issue entirely.  I want to discuss them in a little more detail.

 

Part 1: Why bother?

 

First, why do we use properties?  The most common answer I hear is “future-proofing”.  Specifically, people are concerned that they may need to change the behavior of a property, and don’t want to break existing consumers. 

 

I understand the concern, but I don’t subscribe to the practice 100%:

  • YAGNI – Most of the properties I write, I won’t need.  They just go to waste.  It’s PrematureGeneralization.
  • I’ll probably build some other part of my API in a way that I have to break the contract when I update, so the properties won’t help.
  • If my class has default accessibility (internal), then it’s trivial to recompile every consumer, so no future proofing is necessary.
  • It takes a simple idea (a field in a class) and makes it take 6 lines.  This clutters my code.
  • It’s not the Simplest Thing That Could Possibly Work.

 

If you’re a library vendor, things are a bit different.  You’re selling upgradeability, as well as functionality.

 

Most of this is inspired by a blurb in Ron Jeffries’ article, Adventures in C#: Contiguous Owners, at the very bottom of the document.  He, in turn, was inspired by Ward Cunningham.

 

Part 2: a simple approach

 

Just use public fields.

 

Wait, doesn’t that violate Encapsulation?  Only a little bit.  If you say “I have a public property call Foo, and its type is int”, that’s not much different than “I have a public field call Foo, and its type is int”.  What are you encapsulating, exactly?

 

Wait, doesn’t that open a risk that someone might set the value, when they shouldn’t?  Yeah, but it doesn’t scare me much.  I rarely find myself writing code that manipulates the values in other objects.  It’s bad behavior on my part, and rarely necessary.  If it does happen, and it’s a problem later, I will fix it then.

 

Wait, I’m still worried about rogue setters.  Fine, use ‘readonly’.  I do:

 

        public readonly int Foo; // note that it's named like a property.

 

        public C(int foo)

        {

            this.Foo = foo;

        }

 

Now Foo acts like a property with only a getter, and has the same syntax.  If, someday, I decide it needs to be a property, I don’t have to modify my consumers. (I do have to rebuild them if they’re in a different assembly.)

 

I now don’t have to worry about accidentally changing a value, even in my own code.

 

Also, I’ve noticed a certain pattern.  Typically my fields are either “identity of the class” or “working data of the class”.  I can see which is which by marking the “identity” fields readonly. 

 

Part 3: lazy load

 

Sometimes you want to calculate something on-demand, and then cache the value.  For example, you might write:

 

    class Size

    {

        public readonly uint Width;

        public readonly uint Height;

 

        bool _haveCalculatedArea = false;

        uint _area;

 

        public Size(uint width, uint height)

        {

            this.Width = width;

            this.Height = height;

 

        }

 

        public uint Area

        {

            get

            {

                if (!this._haveCalculatedArea)

                {

                    this._area = this.Height * this.Width;

                    this._haveCalculatedArea = true;

                }

 

                return this._area;

            }

        }

 

If you take this approach, you now need to be careful to use the property inside your class, to work with the correct semantics. 

 

I had said I would extract a new class encapsulate this behavior.  Here’s what that might look like:

 

    class Size

    {

        public readonly uint Width;

        public readonly uint Height;

 

        public readonly LazyArea Area;

 

        public Size(uint width, uint height)

        {

            this.Width = width;

            this.Height = height;

 

            this.Area = new LazyArea(this);

        }

    }

 

    class LazyArea

    {

        readonly Size _size;

 

        bool _haveCalculated = false;

        uint _value;

 

        public LazyArea(Size size) { this._size = size; }

 

        public uint Value

        {

            get

            {

                if (!this._haveCalculated)

                {

                    this._value = this._size.Height * this._size.Width;

                    this._haveCalculated = true;

                }

 

                return this._value;

            }

        }

    }

 

Note: I’m violating the Law of Demeter by exposing the Area as public.  Consumers must use “mySize.Area.Value”.  I think I should probably make it private, and use a public field:

 

        readonly LazyArea _area;

        public uint Area { get { return this._area.Value; } }

 

Part 4: Lazy<T>

 

I’m thinking I could write a generic class to implement this type of caching in a general way.  Do you want to take a stab at it, and post your result in a comment or on your own blog?