{"id":151,"date":"2024-04-23T18:32:00","date_gmt":"2024-04-23T18:32:00","guid":{"rendered":"https:\/\/permutationcity.co.uk\/bp\/?p=151"},"modified":"2024-04-28T09:08:13","modified_gmt":"2024-04-28T09:08:13","slug":"apples-vs-oranges","status":"publish","type":"post","link":"https:\/\/permutationcity.co.uk\/bp\/2024\/04\/23\/apples-vs-oranges\/","title":{"rendered":"Apples vs oranges"},"content":{"rendered":"\n<p>In some of my recent reading I&#8217;ve been frustrated at authors making poor comparisons.\nThe typical behaviour is to showcase an example of good coding with their preferred language \/ methodology\nagainst an example of bad coding with the competitor.\nIt&#8217;s not, say, the language which is making the difference.\nIt&#8217;s whether the code has been well written or not.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"rusts-enums\">Rust&#8217;s enums<\/h2>\n\n\n\n<p>I&#8217;m going to pick on <a href=\"https:\/\/www.oreilly.com\/library\/view\/programming-rust-2nd\/9781492052586\/\">Programming Rust<\/a>\nby O&#8217;Reilly as it&#8217;s been the most recent.\nRust allows an enum to hold a primary value and addition data relating to that value.\nThe book shows the start of a json processor implementation:<\/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;rust&quot;,&quot;mime&quot;:&quot;text\/x-rustsrc&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;Rust&quot;,&quot;language&quot;:&quot;Rust&quot;,&quot;maxHeight&quot;:&quot;400px&quot;,&quot;modeName&quot;:&quot;rust&quot;}\">enum Json {\n    Null,\n    Boolean(bool),\n    Number(f64),\n    String(String),\n    Array(Vec&lt;Json&gt;),\n    Object(Box&lt;HashMap&lt;string, Json&gt;),\n}<\/pre><\/div>\n\n\n\n<p>So if you have a <code>Number<\/code> then there is an associated floating point,\nif you have an <code>Array<\/code> there is an associated vector of <code>Json<\/code> values.\nThere is simple control flow available to use this to access the right data at the right time.\nComing from a C++ background this seems surprising but I can see the benefits.<\/p>\n\n\n\n<p>Next the book shows some C++ code to do the same thing:<\/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;}\">class JSON {\nprivate:\n    enum Tag {\n        Null, Boolean, Number, String, Array, Object\n    };\n    union Data {\n        bool boolean;\n        double number;\n        shared_ptr&lt;string&gt; str;\n        shared_ptr&lt;vector&lt;JSON&gt;&gt; array;\n        shared_ptr&lt;unordered_map&lt;string, JSON&gt;&gt; object;\n        \n        Data() {}\n        ~Data() {}\n        ...\n    };\n    \n    Tag tag;\n    Data data;\n\npublic:\n    bool is_null() const { return tag == Null; }\n    bool is_boolean() const { return tag == Boolean; }\n    bool get_boolean() const {\n        assert(is_boolean());\n        return data.boolean;\n    }\n    void set_boolean(bool value) {\n        this-&gt;~JSON(); \/\/ clean up string\/array\/object value\n        tag = Boolean;\n        data.boolean = value;\n    }\n    ...\n};<\/pre><\/div>\n\n\n\n<p>That&#8217;s bigger and is taking more code to do the same sort of thing.<\/p>\n\n\n\n<p>Is that really what someone writing good C++ would do?\nI would have been tempted to expose the <code>enum Tag<\/code> type and a getter for it.\nThat would allow a switch-statement to choose the right control pathway\nwithout having to both with individual methods to check each tag type.\nThe <code>std::shared_ptr<\/code> wrappers are probably unnecessary.\nI&#8217;m not sure how much space <code>std::string<\/code>, <code>std::vector<\/code> and <code>std::unordered_map<\/code> take up but\nmost of their data will be stored elsewhere.\nIt might have been done to give a uniform destructor behaviour.<\/p>\n\n\n\n<p>All that seems insignificant when you consider that C++17 introduced <code>std::variant<\/code>.\nThe code could have looked 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;}\">struct JSON {\n    using Data = std::variant&lt;\n        bool,\n        double,\n        std::string,\n        std::vector&lt;JSON&gt;,\n        std::unordered_map&lt;std::string, JSON&gt;\n    &gt;;\n\n    Data data;\n};<\/pre><\/div>\n\n\n\n<p>You can access the variant via type, e.g. <code>json.data.get&lt;std::string&gt;()<\/code>, or index.\nNo enum by default but you could add one and some helpers methods to facilitate things.\nOr, much like Rust, other flow control options are available:<\/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;}\">    std::visit(overloaded{\n        [](bool boolean) { std::cout &lt;&lt; boolean &lt;&lt; std::endl; },\n        [](double number) { std::cout &lt;&lt; number &lt;&lt; std::endl; },\n        [](const std::string&amp; string) { std::cout &lt;&lt; string &lt;&lt; std::endl; },\n        [](const std::vector&lt;JSON&gt;&amp; array) {\n            for (const auto&amp; json : array) {\n                output(json.data);\n            }\n        },\n        [](const std::unordered_map&lt;std::string, JSON&gt;&amp; object) {\n            for (const auto&amp; [key, json] : object) {\n                output(json.data);\n            }\n        },\n    }, data);<\/pre><\/div>\n\n\n\n<p>This isn&#8217;t as elegant as Rust can manage but it is a much closer match than the book presented.<\/p>\n\n\n\n<p>The first edition of this book was written in 2018 and the second edition in 2021.\n<code>std::variant<\/code> was introduced before either of these were published.\nMaybe it hadn&#8217;t been noticed when the first book was written and\nthen the sample was just reproduced for the second book.\nThe writers may well not have been as up to date with C++ as they are with Rust.\nMaybe they did know and just wanted to present a great contrast between the two languages.\nWas that necessary?\nRust would still manage to do the same thing with less code.<\/p>\n\n\n\n<p>If I spot something like this it just make me mistrust the rest of the book.\nI&#8217;m going to take everything else that&#8217;s said with a pinch of salt.\nEven things where the author does have a good point.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"lessons\">On balance<\/h2>\n\n\n\n<p>This could be taken as a lesson to avoid putting too much trust in what you read.\nJust because someone says one thing is good and one thing is bad doesn&#8217;t make it so.<\/p>\n\n\n\n<p>However I think this is about anyone, ourselves included, comparing apples with oranges:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>If you&#8217;ve got an old and new rendering algorithm for a game should they both be tested on the same scene? Is it an old or new test scene? Is there going to be an advantage for one algorithm or another. Should they each get a scene custom built according to their advantages and disadvantages.<\/li>\n\n\n\n<li>If you switch to a new language and your bug count goes up what does that mean? Maybe the new language has an inherent problem. Maybe you just aren&#8217;t as familiar with the language. Maybe it&#8217;s easier to do testing so the bugs are being found faster but still fixed at the same rate.<\/li>\n<\/ul>\n\n\n\n<p>If <em>have<\/em> to compare apples and oranges because that&#8217;s all there is then try to be aware of it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In some of my recent reading I&#8217;ve been frustrated at authors making poor comparisons. The typical behaviour is to showcase an example of good coding with their preferred language \/ methodology against an example of bad coding with the competitor. It&#8217;s not, say, the language which is making the difference. It&#8217;s whether the code has [&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":[20],"class_list":["post-151","post","type-post","status-publish","format-standard","hentry","category-general","tag-books"],"_links":{"self":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/151","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=151"}],"version-history":[{"count":3,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/151\/revisions"}],"predecessor-version":[{"id":195,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/posts\/151\/revisions\/195"}],"wp:attachment":[{"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/media?parent=151"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/categories?post=151"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/permutationcity.co.uk\/bp\/wp-json\/wp\/v2\/tags?post=151"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}