{"id":2281,"date":"2014-03-03T13:00:56","date_gmt":"2014-03-03T13:00:56","guid":{"rendered":"http:\/\/writeasync.net\/?p=2281"},"modified":"2018-01-16T03:52:58","modified_gmt":"2018-01-16T03:52:58","slug":"problematic-parameters","status":"publish","type":"post","link":"http:\/\/writeasync.net\/?p=2281","title":{"rendered":"Problematic parameters"},"content":{"rendered":"<p>Parameterization can be a very good thing. It is an oft-employed antidote to unfortunate <a href=\"http:\/\/en.wikipedia.org\/wiki\/Hard_coding\">hard-coded<\/a> values:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ BAD... we can't specify the file name!\r\npublic async Task SaveAsync()\r\n{\r\n    using (FileStream stream = this.GetAsyncStream(&quot;OutputFile.txt&quot;))\r\n    {\r\n        byte&#x5B;] buffer = this.Deserialize();\r\n        await stream.WriteAsync(buffer, buffer.Length);\r\n    }\r\n}\r\n\r\n\/\/ Good! Now I can save to a different folder.\r\npublic async Task SaveAsync(string path)\r\n{\r\n    using (FileStream stream = this.GetAsyncStream(path))\r\n    {\r\n        byte&#x5B;] buffer = this.Deserialize();\r\n        await stream.WriteAsync(buffer, buffer.Length);\r\n    }\r\n}\r\n<\/pre>\n<p><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/0zk36dx2.aspx\">Generic type parameters<\/a> can transform truly type-independent code without <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/yz2be5wk.aspx\">boxing penalties<\/a> or <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms173105.aspx\">casting<\/a> woes:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/ BAD... calling Max(1, 2) implicitly boxes the parameters\r\n\/\/ and the return value must be explicitly cast to int.\r\npublic static IComparable Max(IComparable a, IComparable b)\r\n{\r\n    return (a.CompareTo(b) &gt; 0) ? a : b;\r\n}\r\n\r\n\/\/ Good! No boxing or casting. (Bonus use of the curiously recurring\r\n\/\/ template pattern &lt;http:\/\/en.wikipedia.org\/wiki\/Curiously_recurring_template_pattern&gt;.)\r\npublic static TComparable Max(TComparable a, TComparable b) where TComparable : IComparable&lt;TComparable&gt;\r\n{\r\n    return (a.CompareTo(b) &gt; 0) ? a : b;\r\n}\r\n<\/pre>\n<p>Despite all their benefits, parameters also have penalties and pitfalls. Consider this base class representing a worker thread with a typed state object:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic abstract class WorkerThread&lt;TState&gt;\r\n{\r\n    protected WorkerThread()\r\n    {\r\n    }\r\n\r\n    public void Start(TState state)\r\n    {\r\n        \/* ... *\/\r\n    }\r\n\r\n    public void Cancel()\r\n    {\r\n        \/* ... *\/\r\n    }\r\n\r\n    protected abstract void Run(TState state);\r\n}\r\n<\/pre>\n<p>Conveniently, an implementer of this class can directly and safely refer to the state object without needing to cast:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class CompressionWorkerThread : WorkerThread&lt;byte&#x5B;]&gt;\r\n{\r\n    \/* ... *\/\r\n\r\n    protected override void Run(byte&#x5B;] state)\r\n    {\r\n        \/\/ . . . Compress the bytes here . . .\r\n    }\r\n}\r\n\r\npublic class ParserThread : WorkerThread&lt;string&gt;\r\n{\r\n    \/* ... *\/\r\n\r\n    protected override void Run(string state)\r\n    {\r\n        \/\/ . . . Parse the string here . . .\r\n    }\r\n}\r\n<\/pre>\n<p>But what is convenient for the implementer is a pain for someone who has to deal with many such objects. Because of the generic type parameter, we <em>cannot<\/em> do this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate void CancelAll(IEnumerable&lt;WorkerThread&lt;???&gt;&gt; threads)\r\n{\r\n    foreach (WorkerThread&lt;???&gt; thread in threads)\r\n    {\r\n        thread.Cancel();\r\n    }\r\n}\r\n<\/pre>\n<p>There is no way to make this code compile since we must replace the <code>???<\/code> with a real type name. There is, however, a simple modification that will solve this problem. Let&#8217;s introduce a base interface which defines the <code>Cancel<\/code> method and have our <code>WorkerThread&lt;TState&gt;<\/code> derive from it:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic interface ICancellable\r\n{\r\n    void Cancel();\r\n}\r\n\r\npublic abstract class WorkerThread&lt;TState&gt; : ICancellable\r\n{\r\n    \/* ... *\/\r\n}\r\n<\/pre>\n<p>Now we can implement <code>CancelAll<\/code> in terms of <code>ICancellable<\/code> instead:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate void CancelAll(IEnumerable&lt;ICancellable&gt; items)\r\n{\r\n    foreach (ICancellable item in items)\r\n    {\r\n        item.Cancel();\r\n    }\r\n}\r\n<\/pre>\n<p>This technique is sometimes referred to as type erasure. Check out <a href=\"http:\/\/akrzemi1.wordpress.com\/\">Andrzej Krzemie\u0144ski<\/a>&#8216;s <a href=\"http:\/\/akrzemi1.wordpress.com\/2013\/11\/18\/type-erasure-part-i\/\">posts<\/a> <a href=\"http:\/\/akrzemi1.wordpress.com\/2013\/12\/06\/type-erasure-part-ii\/\">on<\/a> <a href=\"http:\/\/akrzemi1.wordpress.com\/2013\/12\/11\/type-erasure-part-iii\/\">the<\/a> <a href=\"http:\/\/akrzemi1.wordpress.com\/2014\/01\/13\/type-erasure-part-iv\/\">topic<\/a> for much more detail, albeit from a C++ perspective.<\/p>\n<p>Embedded in this example is one additional parametric problem. Take a look at that <code>Start<\/code> method again:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic void Start(TState state)\r\n{\r\n    \/* ... *\/\r\n}\r\n<\/pre>\n<p>Yet again, if we needed to start a heterogeneous group of threads together, we would have difficulty due to the generically typed <code>state<\/code> parameter. But even if all threads were of the <em>same<\/em> type, we still wouldn&#8217;t be able to deal with them nicely. Here is an illustration of the problem:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static void InitializeAndStart()\r\n{\r\n    List&lt;CompressionWorkerThread&gt; threads = new List&lt;CompressionWorkerThread&gt;()\r\n    {\r\n        new CompressionWorkerThread(),\r\n        new CompressionWorkerThread(),\r\n        \/* ... *\/\r\n    };\r\n\r\n    List&lt;byte&#x5B;]&gt; dataValues = new List&lt;byte&#x5B;]&gt;()\r\n    {\r\n        new byte&#x5B;] { \/* ... *\/ },\r\n        new byte&#x5B;] { \/* ... *\/ },\r\n        \/* ... *\/\r\n    };\r\n\r\n    StartCompressionThreads(threads, dataValues);\r\n}\r\n\r\nprivate static void StartCompressionThreads(IList&lt;CompressionWorkerThread&gt; threads, IList&lt;byte&#x5B;]&gt; dataValues)\r\n{\r\n    for (int i = 0; i &lt; threads.Count; ++i)\r\n    {\r\n        threads&#x5B;i].Start(dataValues&#x5B;i]);\r\n    }\r\n}\r\n<\/pre>\n<p>Yuck, <a href=\"http:\/\/en.wikipedia.org\/wiki\/Parallel_array\">parallel arrays<\/a>! This is a breeding ground for bugs. We would have to be very careful that the lists are of the same length, that all data values are properly matched with a thread at the same index, and so on.<\/p>\n<p>It is often of no use to allow this type of parameterization, especially when the expected use case calls for exactly one value to be passed. Instead, we should pass the values <em>upon construction<\/em>. We are already forced to be aware of the static type name here, so we don&#8217;t really lose anything by also directly associating the state object. The modified base class now looks like this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic interface IWorker : ICancellable\r\n{\r\n    void Start();\r\n}\r\n\r\npublic abstract class WorkerThread&lt;TState&gt; : IWorker\r\n{\r\n    protected WorkerThread(TState state)\r\n    {\r\n        \/* ... *\/\r\n    }\r\n\r\n    public void Start()\r\n    {\r\n        \/* ... *\/\r\n    }\r\n\r\n    public void Cancel()\r\n    {\r\n        \/* ... *\/\r\n    }\r\n\r\n    protected abstract void Run(TState state);\r\n}\r\n<\/pre>\n<p>The derived classes simply need to call the base constructor and pass along the state object:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic class CompressionWorkerThread : WorkerThread&lt;byte&#x5B;]&gt;\r\n{\r\n    public CompressionWorkerThread(byte&#x5B;] state)\r\n        : base(state)\r\n    {\r\n    }\r\n\r\n    \/* ... *\/\r\n}\r\n<\/pre>\n<p>The initialization code can now pass the state objects and return a collection of <code>IWorker<\/code> references:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static IWorker&#x5B;] CreateWorkers()\r\n{\r\n    return new IWorker&#x5B;]\r\n    {\r\n        new CompressionWorkerThread(GetData1()),\r\n        new CompressionWorkerThread(GetData2()),\r\n        new ParserThread(GetString1()),\r\n        \/\/ ...\r\n    };\r\n}\r\n<\/pre>\n<p>Finally, the manager is rewarded with a much simpler way to interact with workers:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nprivate static void StartWorkers(IEnumerable&lt;IWorker&gt; workers)\r\n{\r\n    foreach (IWorker worker in workers)\r\n    {\r\n        worker.Start();\r\n    }\r\n}\r\n<\/pre>\n<p>Parameters have their place, but be cautious about the issues described above. Sometimes the best value is <a href=\"http:\/\/en.wikipedia.org\/wiki\/Void_type\"><code>void<\/code><\/a>!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Parameterization can be a very good thing. It is an oft-employed antidote to unfortunate hard-coded values: \/\/ BAD&#8230; we can&#8217;t specify the file name! public async Task SaveAsync() { using (FileStream stream = this.GetAsyncStream(&quot;OutputFile.txt&quot;)) { byte&#x5B;] buffer = this.Deserialize(); await&hellip; <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[91],"tags":[],"class_list":["post-2281","post","type-post","status-publish","format-standard","hentry","category-design"],"_links":{"self":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/2281","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=2281"}],"version-history":[{"count":1,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/2281\/revisions"}],"predecessor-version":[{"id":5387,"href":"http:\/\/writeasync.net\/index.php?rest_route=\/wp\/v2\/posts\/2281\/revisions\/5387"}],"wp:attachment":[{"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=2281"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=2281"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/writeasync.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=2281"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}