{"id":324,"date":"2024-08-27T19:41:36","date_gmt":"2024-08-27T19:41:36","guid":{"rendered":"https:\/\/permutationcity.co.uk\/bp\/?p=324"},"modified":"2024-08-26T08:40:05","modified_gmt":"2024-08-26T08:40:05","slug":"api-lock-in","status":"publish","type":"post","link":"https:\/\/permutationcity.co.uk\/bp\/2024\/08\/27\/api-lock-in\/","title":{"rendered":"API lock-in"},"content":{"rendered":"\n<p>When C# first came out it didn&#8217;t have <a href=\"https:\/\/en.wikipedia.org\/wiki\/Generic_programming\">generics<\/a>,\nthat didn&#8217;t come out until\n<a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/csharp\/whats-new\/csharp-version-history#c-version-20\">version 2.0<\/a>.\nThat meant that, say, the user interface APIs either had to deal with collections of unknown objects or\nbe use custom written collections.\nIf they did one you don&#8217;t know what object you have;\nif you do the other then you can&#8217;t process the collections with standard tools.\nI&#8217;d like to be more specific but Microsoft hasn&#8217;t kept all the documentation available that far back.\nIt&#8217;s probably somewhere on the <a href=\"https:\/\/web.archive.org\/\">Wayback Machine<\/a> but\nI couldn&#8217;t chase it down.\nThen generics <em>did<\/em> come out but the existing APIs were already written,\nwe were locked in to the old way of doing things.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"old-fashioned-find\">Old-fashioned find<\/h2>\n\n\n\n<p>I started on this track thinking about the interface of\n<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/algorithm\/find\"><code>std::find<\/code><\/a>.\nIf you want to search a collection in C++ you might well do something like this:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">    const auto i = std::ranges::find(numbers, 7);\n    if (i != numbers.end()) {\n        std::out &lt;&lt; &quot;Your lucky number was at position &quot; &lt;&lt;\n            std::distance(i - numbers.begin()) &lt;&lt; std::endl;\n    }<\/pre><\/div>\n\n\n\n<p>This works but I feel the <code>i != numbers.end()<\/code> is clunky.\nAnother language might do it differently:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C#&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">    int index = numbers.IndexOf(7);\n    if (index != -1) {\n        Console.WriteLine(&quot;Your lucky number was at position {0}&quot;, index);\n    }<\/pre><\/div>\n\n\n\n<p>That&#8217;s less clunky but you&#8217;re still left comparing the against magic number.\nIt&#8217;s what we&#8217;ve always done.\nHowever it leaves room for writing this:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C#&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">    int index = numbers.IndexOf(7);\n    Console.WriteLine(&quot;Your lucky number was at position {0}&quot;, index);<\/pre><\/div>\n\n\n\n<p>Which might work or it might not.\nIf the developer has thought everything through then the list always contains the lucky number.\nMaybe the list did always contain the lucky number until something else in the codebase changed.\nThe worst this will do is print out <code>-1<\/code> but\nif you&#8217;re accessing data then you&#8217;re out of bounds.<\/p>\n\n\n\n<p>In any case I thought the interface to <code>std::find<\/code> looked a bit old fashioned.\nWhat might it look like if they were writing it today:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">template &lt;typename Range, typename T&gt;\nstd::optional&lt;Range::iterator&gt; find(const Range&amp; range, const T&amp; value);<\/pre><\/div>\n\n\n\n<p>So rather than returning an iterator directly it returns an optional iterator.\nThat means you can know directly whether it was successful or not:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">    const auto i = std::ranges::find(numbers, 7);\n    if (i.has_value()) {\n        const auto index = std::distance(i.value() - numbers.begin());\n        std::out &lt;&lt; &quot;Your lucky number was at position &quot; &lt;&lt; index &lt;&lt; std::endl;\n    }<\/pre><\/div>\n\n\n\n<p>I think that&#8217;s less clunky than the original.\nWe&#8217;re not doing a mysterious comparison were asking a specific question about our result.\nThat example is overly wordy.\nToday I&#8217;d probably write it like this:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">    if (const auto i = std::ranges::find(numbers, 7)) {\n        std::out &lt;&lt; &quot;Your lucky number was at position &quot; &lt;&lt;\n            std::distance(i.value() - numbers.begin()) &lt;&lt; std::endl;\n    }<\/pre><\/div>\n\n\n\n<p>The optional type is automatically converted to a boolean when evaluating the if-statement. Of course there is still room to be careless:<\/p>\n\n\n\n<div class=\"wp-block-codemirror-blocks-code-block code-block\"><pre class=\"CodeMirror\" data-setting=\"{&quot;showPanel&quot;:true,&quot;languageLabel&quot;:&quot;language&quot;,&quot;fullScreenButton&quot;:true,&quot;copyButton&quot;:true,&quot;mode&quot;:&quot;clike&quot;,&quot;mime&quot;:&quot;text\/x-c++src&quot;,&quot;theme&quot;:&quot;material&quot;,&quot;lineNumbers&quot;:false,&quot;styleActiveLine&quot;:false,&quot;lineWrapping&quot;:true,&quot;readOnly&quot;:true,&quot;fileName&quot;:&quot;C++&quot;,&quot;language&quot;:&quot;C++&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;cpp&quot;}\">    const auto i = std::ranges::find(numbers, 7);\n    std::out &lt;&lt; &quot;Your lucky number was at position &quot; &lt;&lt;\n        std::distance(i.value() - numbers.begin()) &lt;&lt; std::endl;<\/pre><\/div>\n\n\n\n<p>But <code>i<\/code> isn&#8217;t a dumb iterator here, it&#8217;s an optional iterator.\nIt &#8220;knows&#8221; whether you found something or not.\nIt&#8217;s never going to print out <code>-1<\/code>, it&#8217;ll\n<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\/value\">throw an exception<\/a>\ninstead.\nYou <em>can<\/em> still shoot yourself in the foot using\n<a href=\"https:\/\/en.cppreference.com\/w\/cpp\/utility\/optional\/operator*\"><code>*i<\/code><\/a>\nwhich doesn&#8217;t perform any checks.<\/p>\n\n\n\n<p>Are there any downsides?\nI don&#8217;t know how <code>std::optional<\/code> is implemented but there&#8217;s probably a slight space overhead.\nIt probably stores an extra boolean to determine whether the value is present or not.\nWe&#8217;re probably going to use the iterator immediately so that&#8217;s not too much cost.\nHaving an extra check with every <code>value()<\/code> access might matter more.\nI tried to do\n<a href=\"https:\/\/quick-bench.com\/q\/UHJbtTeH8JxxpMgRdxXyJiPkkDE\">some performance tests<\/a>\nbut the old and new style seem neck and neck.\nIt could be that as long as the check is done once the optimiser can get rid of any repetitions.\nLooking at the assembly on <a href=\"https:\/\/godbolt.org\/\">Compiler Explorer<\/a> that seems to be right.<\/p>\n\n\n\n<p>This new style seems to have potential.\nI&#8217;ve added it to my own library of code so I can see how it works out long term.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"locked-in\">Locked in<\/h2>\n\n\n\n<p>This post isn&#8217;t really about a new-style <code>find<\/code>.\nIt&#8217;s about the more general problem fixed APIs.\nMaybe the <a href=\"https:\/\/isocpp.org\/std\/the-committee\">standards group for C++<\/a> had the same idea last year but\nthere are already millions of lines of code using the old-style <code>std::find<\/code>,\nthey can&#8217;t just change it.<\/p>\n\n\n\n<p>There are more traditional ways of extending APIs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Adding new functions &#8211; No problems there.<\/li>\n\n\n\n<li>Adding extended versions of existing functions &#8211; This brings to mind some Windows APIs which would be scattered with <code>Ex<\/code> versions of functions. It&#8217;s often means the function has too many parameters for easy reading as well.<\/li>\n\n\n\n<li>Overloading existing functions &#8211; If your language allows this it&#8217;s probably the easiest way to extend an existing function. In C++ you cannot overload functions purely on return type but can change the return type if they input arguments are different.<\/li>\n\n\n\n<li>Extending a structure which is an argument to the function &#8211; As long as the structure has default values this could be the cleanest way. Existing users are unaffected and new users can supply extra options for new behaviour.<\/li>\n<\/ul>\n\n\n\n<p>They&#8217;ve dealt with a similar situation recently.\nThe original <code>std::find<\/code> takes in a start and end point.\nThat&#8217;s flexible but most of the time I want to iterate over an entire collection.\nYou end up endlessly repeating yourself with <code>values.begin()<\/code> and <code>values.end()<\/code>.\nThey have finally introduced <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/algorithm\/ranges\/find\"><code>std::ranges::find<\/code><\/a>\nwhich means you can just use <code>values<\/code>.\nThank goodness.<\/p>\n\n\n\n<p>So, I suppose we could use a namespace to distinguish things, <code>std::optionally::find<\/code>?\nBut lets say I think that <code>std::optionally::find<\/code> or <code>std::ranges::find<\/code> are superior to the original.\nI&#8217;m stuck adding <code>optionally<\/code> and <code>ranges<\/code> all over my code.\nMaybe the standard library could have been designed with more\n<a href=\"https:\/\/permutationcity.co.uk\/bp\/2024\/05\/14\/forever-change\/\">change in mind<\/a>.<\/p>\n\n\n\n<p>What if, instead of <code>std<\/code>, they had used release based namespace.\nSo there would be a <code>std11<\/code> namespace, <code>std14<\/code>, <code>std17<\/code> and so on.\nAt the same time a using-statement, say <code>using std = std17;<\/code>, simplifies things most of the time.\nIf our new-style <code>find<\/code> comes it it can be <code>std26::find<\/code> but\nthe previous version, <code>std23::find<\/code>, is still available.\nIf you want to use just one version of <code>find<\/code> you can.\nIf you want or need to use both versions because of an existing codebase the conversion is just a search &amp; replace.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"in-the-end\">In the end<\/h2>\n\n\n\n<p>I don&#8217;t think <code>std26::find<\/code> is a perfect solution but change is going to happen and\nhaving <em>some<\/em> means of adapting things is a good idea.\nIf you have a file format then you, hopefully, use a version number.\nSame for a web API.\nMost people anticipate that an API might be <em>extended<\/em> but\nrealising that it might be good to <em>change<\/em> seems much rarer.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When C# first came out it didn&#8217;t have generics, that didn&#8217;t come out until version 2.0. That meant that, say, the user interface APIs either had to deal with collections of unknown objects or be use custom written collections. If they did one you don&#8217;t know what object you have; if you do the other [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[1],"tags":[11,8],"class_list":["post-324","post","type-post","status-publish","format-standard","hentry","category-general","tag-planning","tag-standards"],"_links":{"self":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/324","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/comments?post=324"}],"version-history":[{"count":3,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/324\/revisions"}],"predecessor-version":[{"id":328,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/324\/revisions\/328"}],"wp:attachment":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/media?parent=324"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/categories?post=324"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/tags?post=324"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}