<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Object Mentor Blog: Tag Liskov Substitution Principle</title>
    <link>http://blog.objectmentor.com/articles/tag/liskovsubstitutionprinciple</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>Liskov Substitution Principle and the Ruby Core Libraries</title>
      <description>&lt;p&gt;There is a spirited discussion happening now on the ruby-talk list called &lt;a href="http://www.ruby-forum.com/topic/97965&lt;a href="""&gt;&amp;gt;Oppinions on &lt;span class="caps"&gt;RCR&lt;/span&gt; for dup on immutable classes&lt;/a&gt; (sic).&lt;/p&gt;


	&lt;p&gt;In the core Ruby classes, the &lt;code&gt;Kernel&lt;/code&gt; module, which is the root of everything, even &lt;code&gt;Object&lt;/code&gt;, defines a method called &lt;code&gt;dup&lt;/code&gt;, for duplicating objects. (There is also a &lt;code&gt;clone&lt;/code&gt; method with slightly different behavior that I won&amp;#8217;t discuss here.)&lt;/p&gt;


	&lt;p&gt;The problem is that some derived core classes throw an exception when &lt;code&gt;dup&lt;/code&gt; is called.&lt;/p&gt;


Specifically, as the ruby-talk discussion title says, it&amp;#8217;s the &lt;em&gt;immutable&lt;/em&gt; classes (&lt;code&gt;NilClass, FalseClass, TrueClass, Fixnum,&lt;/code&gt; and &lt;code&gt;Symbol&lt;/code&gt;) that do this. Consider, for example, the following &lt;strong&gt;irb&lt;/strong&gt; session: 
&lt;pre&gt;
irb 1:0&amp;gt; 5.respond_to? :dup
=&amp;gt; true
irb 2:0&amp;gt; 5.dup
TypeError: can't dup Fixnum
        from (irb):1:in `dup'
        from (irb):1
irb 3:0&amp;gt; 
&lt;/pre&gt;
If you don&amp;#8217;t know Ruby, the first line asks the &lt;code&gt;Fixnum&lt;/code&gt; object &lt;code&gt;5&lt;/code&gt; if it &lt;em&gt;responds to&lt;/em&gt; the method &lt;code&gt;dup&lt;/code&gt; (with the name expressed as a symbol, hence the&lt;/a&gt;). The answer is true, becuase this method is defined by the module &lt;code&gt;Kernel&lt;/code&gt;, which is included by the top-level class &lt;code&gt;Object&lt;/code&gt;, an ancestor of &lt;code&gt;Fixnum&lt;/code&gt;.

	&lt;p&gt;However, when you actually call &lt;code&gt;dup&lt;/code&gt; on &lt;code&gt;5&lt;/code&gt;, it raises &lt;code&gt;TypeError&lt;/code&gt;, as shown.&lt;/p&gt;


	&lt;p&gt;So, this looks like a classic &lt;a href="http://www.objectmentor.com/resources/articles/lsp.pdf"&gt;Liskov Substitution Principle&lt;/a&gt; violation. The term for this code smell is &lt;em&gt;Refused Bequest&lt;/em&gt; (&lt;em&gt;e.g.,&lt;/em&gt; see &lt;a href="http://www.soberit.hut.fi/mmantyla/BadCodeSmellsTaxonomy.htm"&gt;here&lt;/a&gt;) and it&amp;#8217;s typically fixed with the &lt;em&gt;refactoring&lt;/em&gt; &lt;a href="http://www.refactoring.com/catalog/replaceInheritanceWithDelegation.html"&gt;Replace Inheritance with Delegation&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;The email thread is about a proposal to change the library in one of several possible ways. One possibility is to remove &lt;code&gt;dup&lt;/code&gt; from the &lt;em&gt;immutable&lt;/em&gt; classes. This would eliminate the unexpected behavior in the example above, since &lt;code&gt;5.respond_to?(:dup)&lt;/code&gt; would return false, but it would still be an &lt;span class="caps"&gt;LSP&lt;/span&gt; violation, specifically it would still have the &lt;em&gt;Refused Bequest&lt;/em&gt; smell.&lt;/p&gt;


	&lt;p&gt;One scenario where the current behavior causes problems is doing a deep copy of an arbitrary object graph. For immutable objects, you would normally just want &lt;code&gt;dup&lt;/code&gt; to return the same object. It&amp;#8217;s immutable, right? Well, not exactly, since you can re-open classes and even objects to add and remove methods in Ruby (there are some limitations for the immutables&amp;#8230;).  So, if you thought you actually duplicated something and started messing with its methods, you would be surprised to find the original was &amp;#8220;also&amp;#8221; modified.&lt;/p&gt;


	&lt;p&gt;So, how serious is this &lt;span class="caps"&gt;LSP&lt;/span&gt; issue (one of several)? When I pointed out the problem in the discussion, one respondent, Robert Dober, said the following (edited slightly):&lt;/p&gt;


	&lt;p&gt;&lt;i&gt;
I would say that &lt;span class="caps"&gt;LSP&lt;/span&gt; does not apply here simply because in Ruby we do
not have that kind of contract. In order to apply &lt;span class="caps"&gt;LSP&lt;/span&gt; we need to say at a point we have an object of class &lt;code&gt;Base&lt;/code&gt;, for example. (let the gods forgive me that I use Java)&lt;/i&gt;
&lt;pre&gt;
void aMethod(final Base b){
   ....
}
&lt;/pre&gt;
&lt;i&gt;and we expect this to work whenever we call aMethod with an object
that is a Base.
Anyway the compiler would not really allow otherwise.&lt;/i&gt;
&lt;pre&gt;
SubClass sc;  // subclassing Base od course
aMethod( sc ); // this is expected to work (from the type POV).
&lt;/pre&gt;&lt;/p&gt;


	&lt;p&gt;&lt;i&gt;Such things just do not exist in Ruby, I believe that Ruby has
explained something to me:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;OO Languages are Class oriented languages&lt;/li&gt;
		&lt;li&gt;Dynamic Languages are Object oriented languages.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Replace Class with Type and you see what I mean.&lt;/p&gt;


	&lt;p&gt;This is all very much &lt;span class="caps"&gt;IMHO&lt;/span&gt; of course but I feel that the Ruby
community has made me evolve a lot away from &amp;#8220;Class oriented&amp;#8221;.&lt;/i&gt;&lt;/p&gt;


	&lt;p&gt;He&amp;#8217;s wrong that the compiler protects you in Java; you can still throw exceptions, &lt;em&gt;etc.&lt;/em&gt; The &lt;span class="caps"&gt;JDK&lt;/span&gt; Collection classes have &lt;em&gt;Refused Bequests&lt;/em&gt;. Besides that, however, he makes some interesting points.&lt;/p&gt;


	&lt;p&gt;As a long-time Java programmer, I&amp;#8217;m instinctively uncomfortable with &lt;span class="caps"&gt;LSP&lt;/span&gt; violations. Yet, the Ruby &lt;span class="caps"&gt;API&lt;/span&gt; is very nice to work with, so maybe a little &lt;span class="caps"&gt;LSP&lt;/span&gt; violation isn&amp;#8217;t so bad?&lt;/p&gt;


	&lt;p&gt;As Robert says, we approach our designs differently in dynamic &lt;em&gt;vs.&lt;/em&gt; static languages. In Ruby, you almost never use the &lt;code&gt;is_a?&lt;/code&gt; and &lt;code&gt;kind_of?&lt;/code&gt; methods to check for type. Instead, you follow the &lt;em&gt;duck typing&lt;/em&gt; philosophy (&amp;#8220;If it acts like a duck, it must be a duck&amp;#8221;); you rely on &lt;code&gt;respond_to?&lt;/code&gt; to decide if an object does what you want.&lt;/p&gt;


	&lt;p&gt;In the case of &lt;code&gt;dup&lt;/code&gt; for the immutable classes, I would prefer that they not implement the method, rather than throw an exception. However, that would still violate &lt;span class="caps"&gt;LSP&lt;/span&gt;.&lt;/p&gt;


	&lt;p&gt;So, can we still satisfy &lt;span class="caps"&gt;LSP&lt;/span&gt; and also have rich base classes and modules?&lt;/p&gt;


	&lt;p&gt;There are many examples of &lt;em&gt;traits&lt;/em&gt; that one object might or should support, but not another. (Those of you Java programmers might ask yourself why all objects support &lt;code&gt;toString&lt;/code&gt;, for example. Why not also &lt;code&gt;toXML&lt;/code&gt;...?)&lt;/p&gt;


	&lt;p&gt;Coming from an &lt;a href="http://aspectprogramming.com"&gt;&lt;span class="caps"&gt;AOP&lt;/span&gt;&lt;/a&gt; background, I would rather see an architecture where &lt;code&gt;dup&lt;/code&gt; is added only to those classes and modules that can support it. It shouldn&amp;#8217;t be part of the standard &amp;#8220;signature&amp;#8221; of &lt;code&gt;Kernel&lt;/code&gt;, but it should be present when code actually needs it.&lt;/p&gt;


In fact, Ruby makes this sort of &lt;span class="caps"&gt;AOP&lt;/span&gt; &lt;a href="c2.com/cgi/wiki?AspectsAndDynamicLanguages"&gt;easy&lt;/a&gt; to implement. Maybe &lt;code&gt;Kernel&lt;/code&gt;, &lt;code&gt;Module&lt;/code&gt;, and &lt;code&gt;Object&lt;/code&gt; should be refactored into smaller pieces and programmers should declaratively mixin the &lt;em&gt;traits&lt;/em&gt; they need. Imagine something like the following:
&lt;pre&gt;
irb 1:0&amp;gt; my_obj.respond_to? :dup
=&amp;gt; false
irb 2:0&amp;gt; include 'DupableTrait'  
irb 2:0&amp;gt; my_obj.respond_to? :dup
=&amp;gt; true
irb 4:0&amp;gt; def dup_if_possible items
irb 5:1&amp;gt;  items.map {|item| item.respond_to?(:dup) ? item.dup : item}
irb 6:1&amp;gt; end
...
&lt;/pre&gt;
In other words, &lt;code&gt;Kernel&lt;/code&gt; no longer &amp;#8220;exposes the &lt;code&gt;dup&lt;/code&gt; abstraction&amp;#8221;, by default, but the &lt;code&gt;DupableTrait&lt;/code&gt; module &amp;#8220;magically&amp;#8221; adds &lt;code&gt;dup&lt;/code&gt; to all the classes that can support it. This way, we preserve &lt;span class="caps"&gt;LSP&lt;/span&gt;, streamline the core classes and modules (&lt;a href="http://www.objectmentor.com/resources/articles/srp"&gt;&lt;span class="caps"&gt;SRP&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://www.objectmentor.com/resources/articles/isp.pdf"&gt;&lt;span class="caps"&gt;ISP&lt;/span&gt;&lt;/a&gt; anyone?), yet we have the flexibility we need, on demand.</description>
      <pubDate>Sat, 17 Feb 2007 14:20:00 -0600</pubDate>
      <guid isPermaLink="false">urn:uuid:767b95e8-95d2-45dd-8aa0-09dfb4fe92ec</guid>
      <author>Dean Wampler</author>
      <link>http://blog.objectmentor.com/articles/2007/02/17/liskov-substitution-principle-and-the-ruby-core-libraries</link>
      <category>Dean's Deprecations</category>
      <category>Dynamic Languages</category>
      <category>Design Principles</category>
      <category>Ruby</category>
      <category>object-oriented design</category>
      <category>Liskov Substitution Principle</category>
      <category>LSP</category>
      <trackback:ping>http://blog.objectmentor.com/articles/trackback/188</trackback:ping>
    </item>
  </channel>
</rss>
