{"id":1143,"date":"2014-04-25T07:00:00","date_gmt":"2014-04-25T07:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2014\/04\/25\/a-discovered-quirk-is-just-few-steps-away-from-becoming-a-feature\/"},"modified":"2014-04-25T07:00:00","modified_gmt":"2014-04-25T07:00:00","slug":"a-discovered-quirk-is-just-few-steps-away-from-becoming-a-feature","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20140425-00\/?p=1143","title":{"rendered":"A discovered quirk is just few steps away from becoming a feature"},"content":{"rendered":"<p>\nCommenter Cherry wonders\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/10\/11\/10073890.aspx#10074245\">\nwho invented all those strange syntaxes<\/a>,\nlike <code>set \"<\/code> to show all environment variables,\nincluding the hidden ones.\n<\/p>\n<p>\nAn interesting historical note is\n<a HREF=\"https:\/\/plus.google.com\/u\/0\/101960720994009339267\/posts\/R58WgWwN9jp\">\nthe origin of the convention in unix that files whose names begin with a\ndot are hidden by default<\/a>\n(<a HREF=\"http:\/\/xahlee.info\/UnixResource_dir\/writ\/unix_origin_of_dot_filename.html\">here&#8217;s the relevant portion<\/a>).\nThat article highlights how a discovered quirk\nis just a few steps away from becoming a feature.\n<\/p>\n<p>\nAs\n<a HREF=\"https:\/\/www.youtube.com\/watch?v=kFnFr-DOPf8\">\nMaster Yoda<\/a> might put it:\nDiscovery leads to dissemination.\nDissemination leads to adoption.\nAdoption leads to entrenchment.\nEntrenchment creates a compatibility constraint.\n<\/p>\n<p>\nAs I&#8217;ve noted many times,\nthe batch language was not designed.\nIt simply evolved\nout of the old CP\/M program <code>SUBMIT<\/code>,\nwhich was an even more rudimentary batch processor.\n(The original\n<code>SUBMIT.COM<\/code> didn&#8217;t have conditional branches.\nIt merely ran every line in your batch file one after another.)\n<\/p>\n<p>\nOne of the consequences of something that old is that any quirk,\nonce discovered, can turn into a feature, and from there it becomes\na support burden and compatibility constraint.\nWe&#8217;ve seen this many times before:\nCounting the number of lines in a file by\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2011\/08\/25\/10200026.aspx\">\nexploiting a\nbuffer underflow bug in <code>FIND.COM<\/code><\/a>.\nUpdate the last-modified time of a file by\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2013\/07\/10\/10432879.aspx\">\nusing\na magic sequence of punctuation marks<\/a>.\nEchoing a blank line by\n<a HREF=\"http:\/\/blogs.msdn.com\/b\/oldnewthing\/archive\/2010\/10\/11\/10073890.aspx#10074507\">\ntyping <code>ECHO.<\/code><\/a>.\nAll of these were accidental discovered behaviors\n(just like unix dot files)\nwhich became entrenched.\nEven when the underlying program was completely rewritten,\nthese special quirks had to be\nspecifically detected and painstakingly reproduced because\nso many programs (<i>i.e.<\/i>, batch files) relied on them.\n<\/p>\n<p>\nFor\n<code>set \"<\/code>,\nit&#8217;s a case of taking advantage of two quirks in the implementation:\nThe first quirk is that a missing close-quotation mark is forgiven.\nThat means that <code>set \"<\/code> is logically equivalent to\n<code>set \"\"<\/code>.\n<\/p>\n<p>\nYou are therefore asking for a filtered\nlist of environment variables, but passing the\nlogical equivalent of no filter.\nSpecifically, you&#8217;re asking for all environment variables which\nbegin with the empty string, and it so happens that every string\nbegins with the empty string.\nThe second quirk is that when an explicit filter is applied,\nthe <code>set<\/code> command disables its default filter of\n&#8220;Hide environment variables whose names begin with an equals sign.&#8221;\n<\/p>\n<p>\nIn other words, the code goes like this:\n<\/p>\n<pre>\nforeach (var entry in Environment.GetEnvironmentVariables()) {\n if (prefixFilter != null ?\n     entry.Key.StartsWith(prefixFilter) :\n     !entry.Key.StartsWith(\"=\")) {\n  Console.WriteLine(\"{0}={1}\", entry.Key, entry.Value);\n }\n}\n<\/pre>\n<p>\nPerhaps this is a bug,\nand it should have been written like this:\n<\/p>\n<pre>\nforeach (var entry in Environment.GetEnvironmentVariables()) {\n if (!entry.Key.StartsWith(\"=\") &amp;&amp;\n     (prefixFilter == null || entry.Key.StartsWith(prefixFilter))) {\n  Console.WriteLine(\"{0}={0}\", entry.Key, entry.Value);\n }\n}\n<\/pre>\n<p>\nBut it&#8217;s too late to fix it now.\nPeople have discovered the quote trick,\nso it&#8217;s now a feature and therefore a compatibility constraint.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Commenter Cherry wonders who invented all those strange syntaxes, like set &#8221; to show all environment variables, including the hidden ones. An interesting historical note is the origin of the convention in unix that files whose names begin with a dot are hidden by default (here&#8217;s the relevant portion). That article highlights how a discovered [&hellip;]<\/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":[26],"class_list":["post-1143","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-other"],"acf":[],"blog_post_summary":"<p>Commenter Cherry wonders who invented all those strange syntaxes, like set &#8221; to show all environment variables, including the hidden ones. An interesting historical note is the origin of the convention in unix that files whose names begin with a dot are hidden by default (here&#8217;s the relevant portion). That article highlights how a discovered [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1143","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=1143"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/1143\/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=1143"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=1143"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=1143"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}