21

Should properties in C# have side effects beside notifying of a change in it's states?

I have seen properties used in several different ways. From properties that will load the value the first time they are accessed to properties that have massive side effects like causing a redirect to a different page.

4

6 Answers 6

42

I assume you're talking about read-only properties, or at least property getters, since a property setter is, in almost every instance, going to have side-effects. Otherwise it's not very useful.

In general, a good design follows the principle of least surprise. Don't do things that callers aren't expecting you to do, especially if those things might change future outcomes.

In general, that means that property getters should not have side effects.

However, let's be careful about what we mean by "side effect".

A side effect is, technically, any modification of state. That might be publicly-accessible state, or... it might be totally private state.

Lazy/deferred loaders are one example of state that is almost exclusively private. As long as it's not the caller's responsibility to free that resource, then you are actually reducing the surprise and the complexity in general by using deferred initialization. A caller does not normally expect to have to explicitly signal the initialization of an internal structure. So, lazy initialization does not violate the above principle.

Another example is a synchronized property. In order for a method to be thread-safe, it will often have to be protected by critical section or mutex. Entering a critical section or acquiring a mutex is a side effect; you are modifying state, usually global state. However, this side effect is necessary in order to prevent a much worse kind of surprise - the surprise of data being modified (or worse, partially modified) by another thread.

So I would loosen the restriction a bit to the following: Property reads should not have visible side effects or side effects which change their semantics.

If there is no possible way for a caller to ever be affected by, or even aware of a side effect, then that side effect is not doing any harm. If it would be impossible for you to write a test to verify the existence of a particular side-effect, then it's localized enough to label as a private implementation detail, and thus of no legitimate concern to the outside world.

But do be careful; as a rule of thumb, you should try to avoid side effects, because often what you may think to be a private implementation detail can unexpectedly leak and become public.

2
  • 2
    +1 - a nice complete answer including the more complicated cases that turn a "shall" into a "should... except when...." Jun 8, 2011 at 5:43
  • Another example of an acceptable side effect on a getter: A logging function. Sep 21, 2013 at 18:36
7

I'll answer your question with a question: What happens when you modify the Width property of a form?

Just off the top of my head, this will:

  • Change the value of the backing field.
  • Fire an event.
  • Change the dimensions of the form, report the change to the window manager, and request a repaint.
  • Notify the controls on the form of the change so that any of them that need to change size or position when the form is resized can do so.
  • Cause all the controls that changed to fire events and tell the window manager that they need to be redrawn.
  • Probably other stuff as well.

(Disclaimer: I'm a Delphi developer, not a .NET developer. This may not be 100% accurate for C#, but I bet it's pretty close, especially considering how much of the original .NET framework was based on Delphi.)

All of these "side effects" happen when you change the Width property on a form. Do any of them seem inappropriate or incorrect somehow?

1
  • as long as it does not go into an infinite loop calling itself. To avoid this, each "change" will be mapped to at least three events: one fired before the change, one fired during the change, and one fired after it's finished.
    – rwong
    Jun 8, 2011 at 5:08
5

Take a look at Microsoft Design Rules, especially one of them:

CA1024: Use properties where appropriate

...A method is a good candidate to become a property if one of these conditions is present:

  • Takes no arguments and returns the state information of an object.
  • Accepts a single argument to set some part of the state of an object.

Properties should behave as if they are fields; if the method cannot, it should not be changed to a property. Methods are better than properties in the following situations:

  • The method performs a time-consuming operation. The method is perceivably slower than the time that is required to set or get the value of a field.
  • The method performs a conversion. Accessing a field does not return a converted version of the data that it stores.
  • The Get method has an observable side effect. Retrieving the value of a field does not produce any side effects.
  • The order of execution is important. Setting the value of a field does not rely on the occurrence of other operations.
  • Calling the method two times in succession creates different results.
  • The method is static but returns an object that can be changed by the caller. Retrieving the value of a field does not allow the caller to change the data that is stored by the field.
  • The method returns an array...
2

I believe properties should not have side effects. There is however one exception to this rule: lazy loading. If you want to lazy-load something in a property, that's fine, because the client can't tell the lazy loading is going, and generally doesn't care.

EDIT: Oh, one more thing -- firing an event saying "PropertyXYZ Changed!" (e.g. INotifyPropertyChanged) -- is fine on setters.

2

In addition to the lazy loading mentioned earlier there is also the case of logging functions. These would be rare but not out of the question.

2

There are almost no absolutes in programming, in order to answer your question we need to look at some desirable properties of objects and see if that's something to applies to our case

  1. We want classes to be easily testable.
  2. We want classes to support concurrency
  3. We want classes to be easy to reason about for third-parties

If we answer yes yo some of these questions then it's probably a good idea to think very carefully about properties and their side effects. I assume that when you say side effects you mean secondary side effects since updating the value is an side effect in itself.

The more side effects in general the more difficult a class will be to test. The more secondary side effects the more difficult concurrency will be to handle, but that's a hard issue that probably requires some major design thought anyway.

The big gotcha is probably for people who treat your class as a "black box", it would not be readily available that some state has changed just because they've read a property or that some other property changes because another changes (which might lead to cascading updates).

So in general no, we want properties to be as easy to reason about and simple as possible, that's kinda implied in the design decision otherwise it would be a method. A good programmer can always break the rules however, just be sure you have a really really good reason :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.