
{"id":4492,"date":"2019-03-04T23:50:46","date_gmt":"2019-03-05T04:50:46","guid":{"rendered":"https:\/\/ikriv.com\/blog\/?p=4492"},"modified":"2019-03-04T23:53:01","modified_gmt":"2019-03-05T04:53:01","slug":"why-constructors-must-be-simple","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=4492","title":{"rendered":"Why constructors must be simple"},"content":{"rendered":"\n<p>Recently I&#8217;ve got another reminder why constructors should be simple. The situation in a nutshell: class <strong>BaseHandler&nbsp;<\/strong>subscribes to an observable in its constructor. The handler is virtual, class <strong>DerviedHandler&nbsp;<\/strong>adds incoming items ino a list initialized in <em>its <\/em>constructor. So, there is a potential virtual function call in constructor, but there is also a race condition. If there is nothing in the observable at the time of the construction, everything works. But if there is, virtual function gets called in the constructor, leading to the derived handler to operate on a non-initialized instance, and hilarity ensues.<\/p>\n\n\n\n<p>Complete code is below, and is also <a href=\"https:\/\/github.com\/ikriv\/VirtualFuncObservable\">on github<\/a>. If the conditions are right, the exception occurs in <strong>DerivedHandler.HandleItem()<\/strong>, because <strong>_list<\/strong> is null. What is especially annoying, <strong>_list <\/strong>is marked&nbsp;<strong>readonly,<\/strong> so we mentally block the idea that it may, in fact, change value over time.<\/p>\n\n\n\n<p>Yes, C++ has Resource Aquisition is Initialization paradigm, but C++ is a different language. C++ also does not allow virtual function calls in constructors: they blow up. C# does allow virtual function calls in constructors, which is probably fine, but combined with observables this leads to funny results.<\/p>\n\n\n\n<p>The moral of the story is that we are all better off if constructors do not attempt to do anything fancy. Perform the bare minimum initialization, and then leave the rest to the <strong>Start()<\/strong> or <strong>Connect() <\/strong>method. Yes, you&#8217;ll have to call that method explicitly, but this is a small price to pay for not having to hunt ridiculous race conditions.<\/p>\n\n\n\n<pre style=\"font-family:Consolas;font-size:14px;color:black;background:white\"><span style=\"color:green;\">\/\/&nbsp;Base&nbsp;class,&nbsp;provides&nbsp;virtual&nbsp;HandleItem()&nbsp;method&nbsp;called&nbsp;when&nbsp;new&nbsp;item&nbsp;is&nbsp;observed<\/span>\n<span style=\"color:blue;\">class<\/span>&nbsp;<span style=\"color:#2b91af;\">BaseHandler<\/span>&nbsp;:&nbsp;<span style=\"color:#2b91af;\">IDisposable<\/span>\n{\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">private<\/span>&nbsp;<span style=\"color:blue;\">readonly<\/span>&nbsp;<span style=\"color:#2b91af;\">IDisposable<\/span>&nbsp;_subscription;\n\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">public<\/span>&nbsp;BaseHandler(<span style=\"color:#2b91af;\">IObservable<\/span>&lt;<span style=\"color:blue;\">int<\/span>&gt;&nbsp;items)\n&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_subscription&nbsp;=&nbsp;items.Subscribe(HandleItem);\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">public<\/span>&nbsp;<span style=\"color:blue;\">void<\/span>&nbsp;Dispose()\n&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_subscription.Dispose();\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:green;\">\/\/&nbsp;default&nbsp;handler&nbsp;for&nbsp;observed&nbsp;item&nbsp;prints&nbsp;the&nbsp;value<\/span>\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">protected<\/span>&nbsp;<span style=\"color:blue;\">virtual<\/span>&nbsp;<span style=\"color:blue;\">void<\/span>&nbsp;HandleItem(<span style=\"color:blue;\">int<\/span>&nbsp;n)\n&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:#2b91af;\">Console<\/span>.WriteLine(n);\n&nbsp;&nbsp;&nbsp;&nbsp;}\n}\n\n<span style=\"color:green;\">\/\/&nbsp;Derived&nbsp;class&nbsp;handles&nbsp;observed&nbsp;items&nbsp;by&nbsp;adding&nbsp;them&nbsp;to&nbsp;a&nbsp;list<\/span>\n<span style=\"color:blue;\">class<\/span>&nbsp;<span style=\"color:#2b91af;\">DerivedHandler<\/span>&nbsp;:&nbsp;<span style=\"color:#2b91af;\">BaseHandler<\/span>\n{\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">private<\/span>&nbsp;<span style=\"color:blue;\">readonly<\/span>&nbsp;<span style=\"color:#2b91af;\">List<\/span>&lt;<span style=\"color:blue;\">int<\/span>&gt;&nbsp;_items;&nbsp;<span style=\"color:green;\">\/\/&nbsp;not&nbsp;initialized&nbsp;here&nbsp;on&nbsp;purpose<\/span>\n\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">public<\/span>&nbsp;DerivedHandler(<span style=\"color:#2b91af;\">IObservable<\/span>&lt;<span style=\"color:blue;\">int<\/span>&gt;&nbsp;items)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">base<\/span>(items)\n&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_items&nbsp;=&nbsp;<span style=\"color:blue;\">new<\/span>&nbsp;<span style=\"color:#2b91af;\">List<\/span>&lt;<span style=\"color:blue;\">int<\/span>&gt;();\n&nbsp;&nbsp;&nbsp;&nbsp;}\n\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">protected<\/span>&nbsp;<span style=\"color:blue;\">override<\/span>&nbsp;<span style=\"color:blue;\">void<\/span>&nbsp;HandleItem(<span style=\"color:blue;\">int<\/span>&nbsp;n)\n&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:#2b91af;\">Console<\/span>.WriteLine(<span style=\"color:#a31515;\">\"Adding&nbsp;item:&nbsp;<\/span><span style=\"color:mediumseagreen;\">{0}<\/span><span style=\"color:#a31515;\">\"<\/span>,&nbsp;n);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_items.Add(n);&nbsp;<span style=\"color:green;\">\/\/&nbsp;this&nbsp;causes&nbsp;NullReferenceExceptino&nbsp;if&nbsp;called&nbsp;from&nbsp;the&nbsp;base's&nbsp;constructor<\/span>\n&nbsp;&nbsp;&nbsp;&nbsp;}\n}\n\n<span style=\"color:blue;\">class<\/span>&nbsp;<span style=\"color:#2b91af;\">Program<\/span>\n{\n&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">static<\/span>&nbsp;<span style=\"color:blue;\">void<\/span>&nbsp;Main()\n&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">using<\/span>&nbsp;(<span style=\"color:blue;\">var<\/span>&nbsp;subject&nbsp;=&nbsp;<span style=\"color:blue;\">new<\/span>&nbsp;<span style=\"color:#2b91af;\">ReplaySubject<\/span>&lt;<span style=\"color:blue;\">int<\/span>&gt;())\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:green;\">\/\/&nbsp;Publish&nbsp;an&nbsp;item&nbsp;before&nbsp;constructing&nbsp;any&nbsp;handler&nbsp;objects;&nbsp;this&nbsp;will&nbsp;cause&nbsp;an&nbsp;exception&nbsp;in&nbsp;constructor<\/span>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:green;\">\/\/&nbsp;Comment&nbsp;this&nbsp;out&nbsp;to&nbsp;prevent&nbsp;the&nbsp;exception<\/span>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subject.OnNext(42);&nbsp;\n\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:blue;\">using<\/span>&nbsp;(<span style=\"color:blue;\">new<\/span>&nbsp;<span style=\"color:#2b91af;\">DerivedHandler<\/span>(subject))\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:green;\">\/\/&nbsp;publish&nbsp;a&nbsp;new&nbsp;item&nbsp;to&nbsp;process<\/span>\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;subject.OnNext(43);\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style=\"color:#2b91af;\">Console<\/span>.ReadLine();\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}\n&nbsp;&nbsp;&nbsp;&nbsp;}\n}\n\n<\/pre>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recently I&#8217;ve got another reminder why constructors should be simple. The situation in a nutshell: class BaseHandler&nbsp;subscribes to an observable in its constructor. The handler is virtual, class DerviedHandler&nbsp;adds incoming <a href=\"https:\/\/ikriv.com\/blog\/?p=4492\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[3,5],"tags":[],"class_list":["entry","author-ikriv","post-4492","post","type-post","status-publish","format-standard","category-dotnet","category-dev"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4492","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=4492"}],"version-history":[{"count":1,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4492\/revisions"}],"predecessor-version":[{"id":4496,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/4492\/revisions\/4496"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=4492"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=4492"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=4492"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}