October 10th, 2025
0 reactions

The self-assignment principle for Windows Runtime properties: Don’t change behavior based on whether a property has been written to

For the past few days, I’ve been investigating the self-assignment principle for Windows Runtime properties:

  • Setting a property to its current value is legal and has no effect.

One corollary to this was that setting a property twice to the same value has no effect. Another is that the default value of a property must be a legal value.

Another corollary of this principle is this:

  • The fact that a property has been set does not by itself trigger a change in behavior.

Consider the following API design proposal:

The Widget­Update­Options class is a parameter passed to the Widget.Update method, and it describes how you want to update a widget. The Widget­Update­Options class has two properties:

runtimeclass WidgetUpdateOptions
{
    Windows.UI.Color BackgroundColor;
    Windows.Foundation.Point Position;
}
  • BackgroundColor: If you set this property, then the widget’s background color is updated to the color specified.
  • Position: If you set this property, then the widget’s position is updated to the position specified.

This design violates the self-assignment principle.

Suppose we have this code fragment:

var options = new WidgetUpdateOptions();
options.BackgroundColor = Color.Blue;
widget.Update(options);

The above fragment updates the widget background color and leaves the position unchanged.

We then introduce a harmless self-assignment:

var options = new WidgetUpdateOptions();
options.BackgroundColor = Color.Blue;
options.Position = options.Position;
widget.Update(options);

This time, since there was an assignment to options.Position, the call to widget.Update(options) updates not just the background color, but it also updates the position, probably to (0,0). Oops.

One way to fix this is to have a special “no change” sentinel value. For example, you might say that a color of Transparent means “do not change the color” and a position of (NaN, NaN) means “do not change the position”. Those special values would also be the default values for the properties.

One downside of sentinel values is that there might not be a good choice of sentinel value. For example, what if you want a Widget to have a transparent background? Another is that there may not be an obvious choice for sentinel value. We sort of had to invent a weird sentinel value of (NaN, NaN) for the “no point” point. And it might be hard to generate a NaN value in some languages.

The Windows Runtime supports nullable types, so you can make the properties nullable, where the null value means “leave unchanged.” This is more natural and discoverable.

runtimeclass WidgetUpdateOptions
{
    Windows.Foundation.IReference<Windows.UI.Color> BackgroundColor;
    Windows.Foundation.IReference<Windows.Foundation.Point> Position;
}
  • BackgroundColor: If you set this property to a non-null value, then the widget’s background color is updated to the color specified.
  • Position: If you set this property to a non-null value, then the widget’s position is updated to the position specified.

Another solution is to change the properties to methods. Methods are allowed to have side effects.

runtimeclass WidgetUpdateOptions
{
    void UpdateBackgroundColor(Windows.UI.Color backgroundColor);
    void UpdatePosition(Windows.Foundation.Point position);
}

Related reading: API design principle: Reading a property or adding an event handler should not alter observable behavior.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

2 comments

Sort by :
  • GL 2 hours ago · Edited

    Just wondering… Does a typical component save the incoming IReference interface, or does it use an embedded representation of nullable values (bool, T) by trying calling get_Value?

  • Michael Taylor 5 hours ago

    If I understand your principle here then it sounds like a good academic goal but it is not at all practical. Most of the time there are a large number of options and therefore having separate methods for each one is just unmanageable and potentially slow. For example supposed you need to adjust something that is managed by multiple properties (e.g. alpha and background color and opacity) then you either need to create separate methods for each one or group them together. If you group them together you're mostly back in the same state as if you just exposed an...

    Read more