<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Jon Skeet: Coding Blog : Wacky Ideas, General, C#</title><link>http://msmvps.com/blogs/jon_skeet/archive/tags/Wacky+Ideas/General/C_2300_/default.aspx</link><description>Tags: Wacky Ideas, General, C#</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Breaking Liskov</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/03/16/breaking-liskov.aspx</link><pubDate>Mon, 16 Mar 2009 17:48:04 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1678395</guid><dc:creator>skeet</dc:creator><slash:comments>32</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1678395</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1678395</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/03/16/breaking-liskov.aspx#comments</comments><description>&lt;p&gt;Very recently, &lt;a href="http://news.bbc.co.uk/1/hi/technology/7937010.stm"&gt;Barbara Liskov won the Turing award&lt;/a&gt;, which makes it a highly appropriate time to ponder when it&amp;#39;s reasonable to ignore her most famous piece of work, the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov Substitution (or Substitutability) Principle&lt;/a&gt;. This is not idle speculation: I&amp;#39;ve had a feature request for &lt;a href="http://pobox.com/~skeet/csharp/miscutil"&gt;MiscUtil&lt;/a&gt;. The request makes sense, simplifies the code, and is good all round - but it breaks substitutability &lt;em&gt;and&lt;/em&gt; documented APIs.&lt;/p&gt; &lt;p&gt;The substitutability principle is in some ways just common sense. It says (in paraphrase) that if your code works for some base type T, it should be able to work with subtype of T, S. If it doesn&amp;#39;t, S is breaking substitutability. This principle is at the heart of inheritance and polymorphism - I should be able to use a Stream without knowing the details of what its underlying storage is, for example.&lt;/p&gt; &lt;p&gt;Liskov&amp;#39;s formulation is:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;i&gt;Let &lt;i&gt;q&lt;/i&gt;(&lt;i&gt;x&lt;/i&gt;) be a property provable about objects &lt;i&gt;x&lt;/i&gt; of type &lt;i&gt;T&lt;/i&gt;. Then &lt;i&gt;q&lt;/i&gt;(&lt;i&gt;y&lt;/i&gt;) should be true for objects &lt;i&gt;y&lt;/i&gt; of type &lt;i&gt;S&lt;/i&gt; where &lt;i&gt;S&lt;/i&gt; is a subtype of &lt;i&gt;T&lt;/i&gt;.&lt;/i&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;So, that&amp;#39;s the rule. Sounds like a good idea, right?&lt;/p&gt; &lt;h3&gt;Breaking BinaryReader&amp;#39;s contract&lt;/h3&gt; &lt;p&gt;My case in point is EndianBinaryReader (and EndianBinaryWriter, but the arguments will all be the same - it&amp;#39;s better to focus on a single type). This is simply an equivalent to &lt;a href="http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx"&gt;System.IO.BinaryReader&lt;/a&gt;, but it lets you specify the endianness to use when converting values.&lt;/p&gt; &lt;p&gt;Currently, EndianBinaryReader is a completely separate class to BinaryReader. They have no inheritance relationship. However, as it happens, BinaryReader isn&amp;#39;t sealed, and all of the appropriate methods are virtual. So, can we make EndianBinaryReader derive from BinaryReader and use it as a drop-in replacement? Well... that&amp;#39;s where the trouble starts.&lt;/p&gt; &lt;p&gt;There&amp;#39;s no difficulty &lt;em&gt;technically&lt;/em&gt; in doing it. The implementation is fairly straightforward - indeed, it means we can drop a bunch of methods from EndianBinaryReader and let BinaryReader handle it instead. (This is particularly handy for text, which is fiddly to get right.) I currently have the code in another branch, and it works fine.&lt;/p&gt; &lt;h3&gt;And I would have gotten away with it if it weren&amp;#39;t for that pesky inheritance...&lt;/h3&gt; &lt;p&gt;The problem is whether or not it&amp;#39;s the right thing to do. To start with, it breaks Liskov&amp;#39;s substitutability principle, if the &amp;quot;property&amp;quot; we consider is &amp;quot;the result of calling ReadInt32 when the next four bytes of the underlying stream are 00, 00, 00, 01&amp;quot; for example. Not having read Liskov&amp;#39;s paper for myself (I really should, some time) I&amp;#39;m not sure whether this is the intended kind of use or not. More on that later.&lt;/p&gt; &lt;p&gt;The second problem is that it contradicts the documentation for BinaryReader. For example, the &lt;a href="http://msdn.microsoft.com/en-us/library/system.io.binaryreader.readint32.aspx"&gt;docs for ReadInt32&lt;/a&gt; state: &amp;quot;&lt;a href="http://msdn.microsoft.com/en-us/library/system.io.binaryreader.aspx"&gt;BinaryReader&lt;/a&gt; reads this data type in little-endian format.&amp;quot; That&amp;#39;s a tricky bit of documentation to understand precisely - it&amp;#39;s correct for BinaryReader itself, but does that mean it should be true for all subclasses too?&lt;/p&gt; &lt;p&gt;When I&amp;#39;ve written in various places about the problems of inheritance, and why if you design a class to be unsealed that means doing more design work, this is the kind of thing I&amp;#39;ve been talking about. How much detail does it make sense to specify here? How much leeway is there for classes overriding ReadInt32? Could a different implementation read a &amp;quot;compressed&amp;quot; Int32 instead of always reading four bytes, for example? Should the client care, if they make sure they&amp;#39;ve obtained an appropriate BinaryReader for their data source in the first place? This is basically the same as asking how strictly we should apply Liskov&amp;#39;s substitutability principle. If two types are the same in &lt;em&gt;every&lt;/em&gt; property, surely we can&amp;#39;t distinguish between them at all.&lt;/p&gt; &lt;p&gt;I wonder whether most design questions of inheritance basically boil down to defining which properties should obey Liskov&amp;#39;s substitutability principle and which needn&amp;#39;t, for the type you&amp;#39;re designing. Of course, it&amp;#39;s not just black and white - there will always be exceptions and awkward points. Programming is often about nuance, even if we might wish that not to be the case.&lt;/p&gt; &lt;h3&gt;Blow it, let&amp;#39;s do it anyway...&lt;/h3&gt; &lt;p&gt;Coming back to BinaryReader, I &lt;em&gt;think&lt;/em&gt; (unless I can be persuaded otherwise) that the benefits from going against the documentation (and strict substitutability) outweigh the downsides. In particular, BinaryReaders don&amp;#39;t tend to be passed around in my experience - the code which creates it is usually the code which uses it too, or it&amp;#39;s at least closely related. The risk of breaking code by passing it a BinaryReader using an unexpected endianness is therefore quite low, even though it&amp;#39;s theoretically possible.&lt;/p&gt; &lt;p&gt;So, am I miles off track? This is for a class library, after all - should I be more punctilious about playing by the rules? Or is pragmatism the more important principle here?&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1678395" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/General/default.aspx">General</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Wacky+Ideas/default.aspx">Wacky Ideas</category></item><item><title>Quick rant: why isn't there an Exception(string, params object[]) constructor?</title><link>http://msmvps.com/blogs/jon_skeet/archive/2009/01/23/quick-rant-why-isn-t-there-an-exception-string-params-object-constructor.aspx</link><pubDate>Fri, 23 Jan 2009 21:42:52 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1665160</guid><dc:creator>skeet</dc:creator><slash:comments>26</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1665160</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1665160</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2009/01/23/quick-rant-why-isn-t-there-an-exception-string-params-object-constructor.aspx#comments</comments><description>&lt;p&gt;This &lt;a href="http://stackoverflow.com/questions/474564"&gt;Stack Overflow question&lt;/a&gt; has reminded me of something I often wish existed in common exception constructors - an overload taking a format string and values. For instance, it would be really nice to be able to write:&lt;/p&gt; &lt;div class="code"&gt;&lt;span class="Statement"&gt;throw&lt;/span&gt;&amp;nbsp;&lt;span class="Keyword"&gt;new&lt;/span&gt; IOException(&lt;span class="String"&gt;&amp;quot;Expected to read {0} bytes but only {1} were available&amp;quot;&lt;/span&gt;,&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; requiredSize, bytesRead); &lt;/div&gt; &lt;p&gt;Of course, with no way of explicitly inheriting constructors (which I almost always want for exceptions, and almost never want for anything else) it would mean yet another overload to copy and paste from another exception, but the times when I&amp;#39;ve actually written it in my own exceptions it&amp;#39;s been &lt;em&gt;hugely&lt;/em&gt; handy, particularly for tricky cases where you&amp;#39;ve got a lot of data to include in the message. (You&amp;#39;d also want an overload taking a nested exception first as well, adding to the baggage...)&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1665160" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/General/default.aspx">General</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Wacky+Ideas/default.aspx">Wacky Ideas</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Stack+Overflow/default.aspx">Stack Overflow</category></item><item><title>Refactris</title><link>http://msmvps.com/blogs/jon_skeet/archive/2007/12/12/refactris.aspx</link><pubDate>Wed, 12 Dec 2007 23:45:09 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1394555</guid><dc:creator>skeet</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/rsscomments.aspx?PostID=1394555</wfw:commentRss><wfw:comment xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/jon_skeet/commentapi.aspx?PostID=1394555</wfw:comment><comments>http://msmvps.com/blogs/jon_skeet/archive/2007/12/12/refactris.aspx#comments</comments><description>&lt;p&gt;This post is in lieu of writing a proper one, either on the generic maths operators which Marc Gravell has been hard at work on, or on C# 4 which I have a number of opinions about (no surprise there). I &lt;em&gt;will&lt;/em&gt; write about both of those topics, but I really ought to do some more work on the manuscript for chapter 2 of the book before I go to bed. Posting a blog entry is a reward for finishing indexing chapters 2 and 13, but both of the serious posts will take longer than I really have time for right now.&lt;/p&gt; &lt;p&gt;So, Refactris. This is a silly idea born a couple of weeks ago, at work. You see, several months ago, I had run out of work on a Friday afternoon at 4pm. My then-team-leader, Rohan, foolishly challenged me to write console-mode Tetris in an hour. I had great fun, and had a demonstrable game of Tetris working precisely one hour later. Now combine that with refactoring, one of the ideas of which is that you can remove lines of code by finding code duplication etc. Put the two together, and you get Refactris.&lt;/p&gt; &lt;p&gt;Letters, digits and symbols would fall from the top, and whenever they landed (in a normal Tetris manner) the game would try to compile the code in the bucket, finding as much to compile as possible. It would try the top line, then the top two lines, then the top three lines, etc, until it reached the bottom - then try the second line, the second and third lines together, etc. Code which compiled would be removed.&lt;/p&gt; &lt;p&gt;Clearly it&amp;#39;s a stupid idea, and I haven&amp;#39;t actually tried to implement it or anything silly like that. Funny enough to share though, and if any of you wish to give it a go, I&amp;#39;d love to see the results.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1394555" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/General/default.aspx">General</category><category domain="http://msmvps.com/blogs/jon_skeet/archive/tags/Wacky+Ideas/default.aspx">Wacky Ideas</category></item></channel></rss>