One of the design principles of the Windows Runtime is that if an object has multiple writable properties, then you can set them in any order and the effect will be the same.
For example, consider an object with three properties: Minimum, Maximum, and Value. Suppose the rule is that you must, at all times, maintain Minimum ≤ Value ≤ Maximum. This rule would create problems if you wanted to change all three values, because you have to tiptoe around the possibility that an intermediate state will be momentarily illegal.
// Naïve version that doesn't work.
void ChangeRangeAndValue(Widget w, int min, int max, int v)
{
w.Minimum = min;
w.Maximum = max;
w.Value = v;
}
The above code doesn’t work if, say, the old range was [0, 100] with a value of 50, and you want to change it to [500, 600] with a value of 550. You can’t set the minimum to 500 because that would result in Minimum > Maximum because the new minimum 500 is greater than the old maximum 100.
You would have to do a careful dance to make sure that at no point is the Minimum ≤ Value ≤ Maximum requirement violated.
void ChangeRangeAndValue(Widget w, int min, int max, int v)
{
w.Minimum = Math.Min(w.Minimum, min);
w.Maximum = Math.Max(w.Maximum, max);
w.Value = v;
w.Minimum = min;
w.Maximum = max;
}
I think the above code works. We first have to expand the range to something that encloses both the old and new ranges, so that the old value remains valid. Then we can update the value to the new value, and only then can we shrink to the desired range.
This is annoying and not the most obvious code to write, much less realize that you need to write.²
Furthermore, you might not even control the order in which the properties are set. They might be set by binding, or they might be set indirectly through a JSON configuration file.
To avoid these problems, the Windows Runtime has a policy of allowing properties to be set in any order. Temporarily inconsistent values are permitted, as long as things become consistent again at some established point in the future, such as “when you call the Start method” or “when the next layout pass occurs.”
A similar problem occurs when properties have overlapping effects. For example, the Windows. has two properties which both provide the suggested name for the file being saved. The SuggestedÂFileÂName provides just the file name, like “Document.txt”. The SuggestedÂSaveÂFile provides a full path, including the enclosing directory.² Both of these try to set the name that appears by default when the dialog is opened, so what happens if you set both?
Again, the “properties can be set in any order” principle means that it’s not “last writer wins”. Rather, the rule is that if there is a conflict between the two properties, then the SuggestedÂSaveÂFile takes precedence.
Note that the insensitivity to order applies only to properties. The order of method calls is significant both with respect to other method calls, as well as with respect to properties. For example, the following two sequences are allowed to behave differently because there is a method call in between:
| Sequence 1 | Sequence 2 |
|---|---|
| m.Property1 = value1; m.Method(); m.Property2 = value2; |
m.Property2 = value2; m.Method(); m.Property1 = value1; |
Bonus chatter: There is one exception to this rule: If two properties are aliases for each other, then setting one property immediately updates the other (since they are just two different names for the same property), and therefore the last-writer-wins principle applies. This exception doesn’t arise often; usually, it happens when a property is renamed, and the old name remains for backward compatibility.
¹ And even that isn’t sufficient if there is some other constraint like “The value of Maximum − Minimum may not exceed 100.”
² I suspect that the reason both properties exist is in the case where you are doing a “Save As”, because that is saving as a new file, so you can’t get a StorageÂFile to a file that doesn’t exist, so SuggestedÂFileÂName and SuggestedÂStartÂLocation are the best you can do.
0 comments
Be the first to start the discussion.