{"id":111664,"date":"2025-10-09T07:00:00","date_gmt":"2025-10-09T14:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111664"},"modified":"2025-10-09T08:36:09","modified_gmt":"2025-10-09T15:36:09","slug":"20251009-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20251009-00\/?p=111664","title":{"rendered":"The self-assignment principle for Windows Runtime properties applies to default values"},"content":{"rendered":"<p>Last time, I introduced <a title=\"Windows Runtime API design principles around read-write properties: Idempotence and self-assignment\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20251008-00\/?p=111660\"> the self-assignment principle for Windows Runtime properties<\/a>:<\/p>\n<ul>\n<li>Setting a property to its current value is legal and has no effect.<\/li>\n<\/ul>\n<p>One corollary to this was that setting a property twice to the same value has no effect.<\/p>\n<p>A more interesting corollary is this one:<\/p>\n<ul>\n<li>The default value of a property must be a legal value.<\/li>\n<\/ul>\n<p>If the property value has never been changed from the default, then a self-assignment will assign the default value, and that must succeed.<\/p>\n<p>This second corollary can catch some people who submit API designs in which they propose something like this:<\/p>\n<blockquote class=\"q\"><p>The <code>Doodad\u00adFinder<\/code> class contains a collection of properties that you can set to narrow the search that occurs when you call <code>Find()<\/code>. If you want to find Doodads with a specific partner widget, you can set the <code>Doodad\u00adOptions.<wbr \/>Partner\u00adWidget<\/code> property to the handle of that partner widget. You may not set the <code>Partner\u00adWidget<\/code> property to null.<\/p><\/blockquote>\n<p>I ask them, &#8220;So if I create a brand new <code>Doodad\u00adFinder<\/code> object and immediately read the <code>Partner\u00adWidget<\/code> property, what do I get?&#8221;<\/p>\n<p>&#8220;Oh, since this is a brand new <code>Doodad\u00adFinder<\/code> object, no partner widget has been specified, so the <code>Partner\u00adWidget<\/code> is null.&#8221;<\/p>\n<p>I pointed out that this violates the &#8220;allow self-assignment&#8221; rule:<\/p>\n<pre>var finder = new DoodadFinder();\r\nfinder.PartnerWidget = finder.PartnerWidget; \/\/ throws InvalidArgumentException?\r\n<\/pre>\n<p>You can say that a property may not be null, but you can&#8217;t say that and simultaneously default the value to null. You&#8217;re saying that the default value is illegal.<\/p>\n<p>The <code>Doodad\u00adFinder<\/code> should allow the <code>Partner\u00adWidget<\/code> to be set to null if it is already null.<\/p>\n<p>Indeed, I think that they should allow it to be set <i>back<\/i> to null, so that there&#8217;s a way to undo a prior set. As long as you undo it before calling <code>Find()<\/code>, then it should behave as if it had never been set.<\/p>\n<pre>var finder = new DoodadFinder();\r\nConfigureFinder(finder); \/\/ might set PartnerWidget\r\nfinder.PartnerWidget = null; \/\/ cancel the partner widget filter\r\n<\/pre>\n<p>or even<\/p>\n<pre>void ConfigureFinderButPreservePartnerWidget(DoodadFinder finder)\r\n{\r\n    var originalPartner = finder.PartnerWidget;\r\n    try {\r\n        ConfigureFinder(finder); \/\/ might set the PartnerWidget\r\n    } finally {\r\n        finder.PartnerWidget = originalPartner;\r\n    }\r\n}\r\n<\/pre>\n<p>Next time, we&#8217;ll look at another perhaps-surprising corollary to the self-assignment principle.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The default value must be legal.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-111664","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The default value must be legal.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111664","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=111664"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111664\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=111664"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111664"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111664"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}