Lumea lui Kudzu

"Programarea este o formă de artă care ripostează"

Kudzu World  »  Blogspace  »  Kudzu's Tech Blog
English - Română - Русский - عربي

RSS Feed

If you want to more easily stay informed of updates etc you can subscribe to the RSS feed. Just point your RSS reader at this page, auto discovery is enabled.




Using PayPal?
Read this


Properties or Fields, which to access?

8/16/2007

There is a big debate that has been going on for years. If a property is backed by a field, is it safe to access the field instead for performance reasons? And if so, when is it safe to do so? There are a lot of opinions on this issue, but here is my take based on nearly 30 years of programming.

Example

protected int mSize = 2048;
public int Size {
    get { return mSize; }
    set { mSize = value; }
}

The Language is a Factor

Some try to create a simple answer to fit all object oriented systems. But language is a factor. For example, Delphi (native) implements properties a bit differently than C# or VB.NET. Java and C++ are different again. In this article, my advice applies to .NET. Also note that I am speaking purely about objects, and not structs. Structs are less used in object oriented programming, but are still a vital feature.

External Access

All external access should be through properties. By declaring all fields as private, it ensures that any consumer of your object must use properties. Make a rule that all fields initially are declared as private, and never as public. You will then be forced to make properties when it is desirable for external access. That is by declaring mSize as protected, any consumer must access the Size property instead. The class itself and descendant classes however can access Size, or mSize.

It has been cited by many that you should use fields and simply change them to properties later as needed. This is a poor practice for many reasons. The largest of these reasons is that such a change causes code breakage.

Internal Access

I will define internal access as access from within the class, or a descendant class. Do not confuse my use of internal access in this article with the internal directive in C#. When the access is internal, should you access Size or mSize?

Some say that you should always access Size, unless you need to by the functionality in the get/set methods of the property. Often to initialize a property the set method is bypassed. However accessing the Size instead of mSize is slower as it requires the set method to be called. There has been a lot of discussion around the point that most simple set/get methods will be inlined by .NET and thus the performance hit reduced. Even if it is inlined, code must be executed rather than a simply copy. I have not looked at the IL (Reader exercise, feedback appreciated), however I suspect that even if inlined the code is less efficient for accessing Size versus mSize. Is the difference important? In most cases, probably not.

Others say that internal access should use mSize, and Size should only be used if the set/get methods contain specific behavior that is desired during internal access.

I fully understand both points of view, but what usually ends up happening is developers end up mixing both and never really using one or the other. I advise to use the second method, access mSize internally unless Size contains some specific behavior that you need at that moment in time.

Private or Protected?

There is a general rule in object oriented programming:

"Use the least amount of access you anticipate needing, to make the best use of encapsulation"

I am not suggesting you violate that, only that you optimistically tune it up. In addition to my experience, this quote from a blog comment sums it up very well:

"That's the general OO wisdom - but that also means that either (a) the class has to be extremely well designed or (b) you need to be clairvoyant to the extent that you know beyond a shadow of a doubt what members may be needed by people using your classes."

Whether to declare fields as private or protected was always a point of struggle for me. Traditional theory said to declare all fields as private. However when working with Delphi, too many components (especially VCL components) declared many fields as private with no proper access for descendants. This of course was usually component authors not thinking forward enough, but none the less it was a sore spot for many developers. Because of this I made a rule that I would never use private, and instead always use protected for all fields. The same rule applied for methods that were not meant to be used externally, all were declared protected.

When moving to C# I instead stated a rule that all fields should initially be declared private. Most classes that are designed as bases have at least some descendants built either for examples, or testing by the base class author. My rule was then on a case by case basis to promote members to protected that descendant classes needed access to.

However recently I have changed my thinking. Instead I have reverted to my practice in Delphi. I never use private and instead only use protected for fields and non public methods. This allows complete interaction for descendant classes, and also relies on the assumption that descendant writers properly know your class or have access to source. There is also an option for a case by case basis to demote items to private, but generally I do not use this and do not recommend it except for well understood and rare cases. What? You do not want others messing around "inside" your component? C# has another way to deal with that. Simply seal your class with the sealed directive. Using sealed has other advantages as well, most notably the ability to perform many more compiler optimizations. I have not explored every aspect of this methodology change yet, and thus I am open to feedback. I am now implementing it in my projects and will see the results over time.

There is a small complication however. If you seal a class, the compiler will issue you a warning for each protected declaration you have, basically telling you that it is useless. I also have a rule to eliminate all warnings in code. So if you decide to seal a class, you either need to disable that warning, or then change the protected declarations to private in just the sealed classes.

I prefer the latter choice of disabling the warning. It is really more of a hint than a warning and ignoring it has no consequence that I can find. Doing this allows me to unseal the class at a later time, or seal an unsealed class very quickly. To do this you need to first find the warning number. One would expect visual studio to display the warning number. Visual Studio does not list the number, and even if you try to edit the columns shown, it is not an option either. Fortunately while not so obvious, there is an easy way to find the number. Right click on the warning and select "Show help for this warning".

After you find the warning number you can enter it in Suppress Warnings in project options. The warning for "new protected member declared in sealed class" is CS0628. To access the Suppress Warnings field, select Project Properties, Builder tab. Simply enter the warning number without the leading characters. That is 0628, and not CS0628. Now you can build and this warning will no longer be displayed.


Enter C# 3.0

The language becomes a factor yet again. In C# 3.0 (Visual Studio 2008) a new feature called automatic properties are available. This allows the previous example to be declared as follows.

public int Size { get; set; }

Where is mSize? The compiler generates a hidden variable for you. But you cannot access it. If you wish to use this syntax, then obviously you must access the property. This syntax is designed to allow a short cut declaration for most property types, yet allow them to be changed in the future without breaking source compatibility. It is important to note, this is merely a new short cut option - it does not add any new functionality and is more limited than the existing syntax. It cannot be used with read only properties for example. How would you initialize it?

Personally I generally do not use them, because it also forces you to initialize the property in the constructor rather than inline as part of the declaration. So instead of:

protected int mSize = 2048;
public int Size {
    get { return mSize; }
    set { mSize = value; }
}

One must use:

public int Size { get; set; }

public void MyClass() {
Size = 2048;
}

I prefer to keep them in the declarations rather than grouped in the constructor. This becomes more useful as the number of properties grows.

GetXXX() Methods

There is also another question. When should you implement a GetXXX() type method instead of a read only property? After all, do they not achieve the same effect? Generally they do, but to the user they have some implied significance. Because of this I suggest you heed this and meet the user's expectations. Users expect property calls to return quickly, and that property values generally need not be cached in local temporary variables. Thus you should ensure that any get functions of properties are quick, and access fields or other cached data. If you need to perform some kind of larger calculation or obtain the data, this is a good case for a GetXXX() type function. Users generally expect to cache function results if they need it repeatedly. In addition, such functions allow for arguments to be passed.

Be careful with read write properties as well. Just because you cannot implement read write functionality using a GetXXX() method, it does not free you to implement heavy GetXXX() type functionality in a property. If you require heavy type access, consider using a partner SetXXX() function to help the user understand that one or both of the operations might involve noticeable overhead.

Summary

  1. Declare all fields as protected. Demote items to private only in extreme cases.
  2. If you do not want descendants messing around with your fields, seal your class using the sealed keyword.
  3. Inside your class and its descendants it is safe to access fields directly and should be done in most cases for performance reasons.
  4. Create properties only for fields that need to be accessed externally.
  5. Use a GetXXX() method instead of a read only property when the overhead to return a value is significant.


<< Previous Entry  Next Entry >>

Comments: 


Add your comment: 

Name:    
E-Mail:  
URL:  
Comment:  
Please add 4 and 8 and type the answer here:



Use my contact form to contact me directly.