<?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>The Sorensens: Final methods in ruby (prevent method override)</title>
    <link>http://www.thesorensens.org/2006/10/06/final-methods-in-ruby-prevent-method-override</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>Final methods in ruby (prevent method override)</title>
      <description>&lt;p&gt;In a reversal of fortune, I recently found myself wishing Ruby was more like Java.  Java has the ideas of &lt;a href="http://en.wikipedia.org/wiki/Classes_(computer_science)#Abstract_and_concrete_classes"&gt;abstract base classes&lt;/a&gt; and &lt;em&gt;final&lt;/em&gt; methods (methods which should not be overridden in child classes).  Such ideas don&amp;#8217;t really exist in Ruby.&lt;/p&gt;


	&lt;p&gt;My problem was this.  I had a base class Cronjob which represented some job which was going to run under cron.  This class managed stuff like setting up logging, db connections, etc.  I then wanted other jobs to be able to extend Cronjob and take advantage of the base class:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Cronjob&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="comment"&gt;# do useful stuff here, setting up db connections, logging, etc.&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;   &lt;span class="comment"&gt;# method which no child class should override&lt;/span&gt;
    &lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;starting at &lt;span class="expr"&gt;#{start}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="ident"&gt;run_job&lt;/span&gt;    &lt;span class="comment"&gt;# method which child class should override&lt;/span&gt;
    &lt;span class="ident"&gt;stop&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;finished at &lt;span class="expr"&gt;#{stop}&lt;/span&gt;, took &lt;span class="expr"&gt;#{stop-start}&lt;/span&gt; seconds&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

This then allowed me to write a child class that did the real work:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;MyJob&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Cronjob&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run_job&lt;/span&gt;
    &lt;span class="comment"&gt;# real work goes here&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

And then call:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;job&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;MyJob&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="ident"&gt;job&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;All well and good.  If people use the base class correctly, they get some nice bits of functionality.  However, I eventually noticed that someone had written this class:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;TheirJob&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Cronjob&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;
    &lt;span class="comment"&gt;# real work goes here&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

This is bad!  The author thinks they are taking full advantage of the base class, but they are not.  In reality they are overriding the &lt;em&gt;run&lt;/em&gt; method, and Ruby does not complain a bit.  This is where if I were in Java I could use the &lt;em&gt;final&lt;/em&gt; keyword to say that a method should not be overriden by any child classes.  What I wanted was to be able to write:&lt;/pre&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Cronjob&lt;/span&gt;
  &lt;span class="ident"&gt;final&lt;/span&gt; &lt;span class="symbol"&gt;:run&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
So, how can we make this work?  Here is my solution that does the job.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Object&lt;/span&gt;
  &lt;span class="attribute"&gt;@@final_methods&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{}&lt;/span&gt;

  &lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;
    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;prevent_override?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="attribute"&gt;@@final_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;class_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;final_methods&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
        &lt;span class="ident"&gt;ancestors&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ancestors&lt;/span&gt;
        &lt;span class="ident"&gt;ancestors&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;shift&lt;/span&gt; &lt;span class="comment"&gt;# remove myself from the list&lt;/span&gt;
        &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;ancestors&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;include?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;class_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;and&lt;/span&gt;
           &lt;span class="ident"&gt;final_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;include?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
          &lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Child class '&lt;span class="expr"&gt;#{self}&lt;/span&gt;' should not override parent class method '&lt;span class="expr"&gt;#{class_name}&lt;/span&gt;.&lt;span class="expr"&gt;#{method_name}&lt;/span&gt;'.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
        &lt;span class="keyword"&gt;end&lt;/span&gt;
      &lt;span class="keyword"&gt;end&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;method_added&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="ident"&gt;prevent_override?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;final&lt;/span&gt;&lt;span class="punct"&gt;(*&lt;/span&gt;&lt;span class="ident"&gt;names&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="attribute"&gt;@@final_methods&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;names&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

Now if someone tries to override the method in a child class they get an exception:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;in&lt;/span&gt; `&lt;span class="ident"&gt;prevent_override?&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;: Child class &lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="constant"&gt;TheirJob&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt; should not
override parent class method &lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="constant"&gt;Cronjob&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;.(RuntimeError)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;How does it work?  The magic is possible because Ruby has a method called &lt;em&gt;method_added.&lt;/em&gt;  This gets called when a method is added to a class. So, when a source code file is being processed, if a method is defined with &amp;#8220;def foo&amp;#8221;, after the method has been added to the class this &lt;em&gt;method_added&lt;/em&gt; method gets fired with &amp;#8220;foo&amp;#8221; as the argument.  We can then implement the method with our desired behavior.  In my case, I just wanted to blow up with an exception which is easy enough to do.&lt;/p&gt;


Ruby also has a method to get an object&amp;#8217;s &amp;#8220;ancestors&amp;#8221;.
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="punct"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="constant"&gt;true&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ancestors&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;TrueClass&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Object&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Kernel&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="punct"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[].&lt;/span&gt;&lt;span class="ident"&gt;class&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ancestors&lt;/span&gt;
&lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;Array&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Enumerable&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Object&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Kernel&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;So, the logic becomes simple.  The &lt;em&gt;final&lt;/em&gt; method just stores a hash of class =&amp;gt; [methods which you cannot override].  Then, on &lt;em&gt;method_added&lt;/em&gt; we do a check to see if the method being added is in this hash, and Bob&amp;#8217;s your uncle!&lt;/p&gt;


	&lt;p&gt;So, while it was mildly surprising to find Ruby missing a language feature that I wanted, the language is powerful enough that you can &amp;#8220;add to&amp;#8221; the language!  I&amp;#8217;m also half expecting people to weigh in with suggestions of a better way to do this.  I would be pleased to hear better variations.  This solution definitely doesn&amp;#8217;t make it impossible to override the method in a child class; a determined person could get around it.  But it does solve my problem of someone inadvertently overriding the method.&lt;/p&gt;


	&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt;  Now available via gems, thanks to Dr. Nic&amp;#8217;s &lt;a href="http://drnicwilliams.com/2006/10/11/generating-new-gems/"&gt;newgem magic&lt;/a&gt;:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;gem&lt;/span&gt; &lt;span class="ident"&gt;install&lt;/span&gt; &lt;span class="ident"&gt;finalizer&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 06 Oct 2006 14:10:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:c94a06d9-8168-417a-9e61-c9da561a1a24</guid>
      <author>haakon</author>
      <link>http://www.thesorensens.org/2006/10/06/final-methods-in-ruby-prevent-method-override</link>
      <category>tech</category>
      <category>tech</category>
      <trackback:ping>http://www.thesorensens.org/articles/trackback/16</trackback:ping>
    </item>
  </channel>
</rss>
