Saturday, December 22, 2007

My Exploration of the Relationship Between C# Properties and Abstract Data Types

One of my goals for my time off from work is to read the 2nd Edition Code Complete by Steve McConnell.  I thought I would jot down some thoughts I'm having and realizations that I'm coming to as I read further.

I'm currently reading about Abstract Data Types and extrapolating how C# property language feature fits into the picture.  The purpose of the Abstract Data Type is to hide the details of the management of data within the class.   I'll use the example from the book.

If I have a class that represents a font, the user will likely need to be able to make the font bold.  A data type would represent this activity like so:

public class Font
{
    public bool Bold;
}

The Abstract Data Type would do it like this:

public class Font
{
    private bool _bold = false;
 
    public void SetBoldOn()
    {
        _bold = true;
    }
 
    public void SetBoldOff()
    {
        _bold = false;
    }
}

In C# field assignment and property assignment from a client perspective are semantically similar, however, a C# property certainly has the ability to hide the details of the data within the class.  As a C# property, the font would be represented as this:

public class Font
{
    private bool _bold = false;
 
    public bold Bold { get; set; }
}

The property language feature gives me the ability to hide what's going on under covers just as much as the method does.  Additionally, it seems a bit more efficient to have a single C# property that can turn bold on and off as opposed to two different methods, SetBoldOn and SetBoldOff, and likely another method that would return the current state of bold.  I could create a ToggleBold method, but then I'd still need a separate method to determine the current state of the font's boldness. 

What about in situations in which you need to provide more details about the data you are specifying?  For example, in the same font example, when you are setting the size of a font.  In that case, there may be different units that I am specifying the size to be in, pixels or points.  In this case, for the Abstract Data Type, I would have a couple methods:

public class Font
{
    //size is internally stored as pixels
    private int _size = 10;
 
    public void SetSizeInPixels(int size)
    {
        _size = size;
    }
 
    public void SetSizeInPoints(int size)
    {
        _size = SizeConverter.ConvertPointsToPixels(size);
    }
}

If I choose to abstract the data with C# properties, I would equivalently have:

public class Font
{
    //size is internally stored as pixels
    private int _size = 10;
 
    public int SizeInPixels
    {
        get { return _size; }
        set { _size = value; }
    }
 
    public int SizeInPoints
    {
        get
        {
            return SizeConverter.ConvertPixelsToPoints(_size);
        }
        set
        {
            _size = SizeConverter.ConvertPointsToPixels(value);
        }
    }
}

I feel like a C# property is certainly a reasonable construct for a class to use to be considered an Abstract Data Type in these simple cases.  Ultimately it all boils down to what you require and what your preference is.  You can probably just ask yourself these questions:

  • Do you need equivalent data retrieval functionality out of your class?  If so, you might want to take advantage of the C# property's get accessor.
  • If you need to provide additional information, do you also want your class to return that additional information with the data?  If so, maybe you want to use a C# property here too.  It seems reasonable in some cases that you would want your font formatted back into your preferred unit (the get accessor on the FontSizeInPoints).
  • How much logic do you need to perform on your data based upon the additional information provided?  Is it a complicated conversion between points and pixels?  I think that most programmers make assumptions about the complexity of properties vs. methods, and thus there's a threshold of logic in which a method is more appropriate than a property.
  • What is the data?  For instance, what if the font had a relative size property, and you had a fixed set of relative sizes, smaller, small, large, larger.  In this case, it might make more sense to hide this enumeration from the user, and provide the interface through methods, so that the data itself is hidden from the user.  What if you change the larger to translate into 16 pixels one day?  Much easier to change the method than a big switch statement in the property.

Now, as I type this all, it's such a rudimentary distinction, and I'm feeling a bit self-conscious about what I've written, like I'm way behind and have been missing the point.  But it's something I'd never thought too much about from this angle, and maybe there's some folks out there that haven't either (or just as ignorant as I am).