CSC/ECE 517 Fall 2011/ch3 3i ws: Difference between revisions

From Expertiza_Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 2: Line 2:
==Examples==
==Examples==
===Roman Numerals===
===Roman Numerals===
The classic example for missing_method, given in the Ruby Docs [http://ruby-doc.org/docs/ProgrammingRuby/html/ref_c_object.html#Object.method_missing]:
The classic example for missing_method, given in the Ruby Docs:<ref>Ruby Docs: Object.missing_method http://ruby-doc.org/docs/ProgrammingRuby/html/ref_c_object.html#Object.method_missing </ref>
   class Roman
   class Roman
     def romanToInt(str)
     def romanToInt(str)
Line 22: Line 22:


===method_missing in Rails===
===method_missing in Rails===
Rails, like many domain specific languages of Ruby, makes heavy use of the method_missing function.  A prominent example is ActiveRecord, where dynamic finders are implemented using method_missing. When a call like find_by_username is called from an ActiveRecord object, the method does not explicitly exist, rather the message is picked apart in [https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L1053 ActiveRecord's Base::method_missing] method. The variable part of the message, in this case "username" is turned into an argument to the find method, which is defined. The code below is not exactly what is in the method itself, but outlines what actually happens after calls to helper other methods:
Rails, like many domain specific languages of Ruby, makes heavy use of the method_missing function.  A prominent example is ActiveRecord, where dynamic finders are implemented using method_missing. When a call like find_by_username is called from an ActiveRecord object, the method does not explicitly exist, rather the message is picked apart in [https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L1053 ActiveRecord's Base::method_missing] method. The variable part of the message, in this case "username" is turned into an argument to the find method, which is defined. The code below is not exactly what is in the method itself, but outlines what actually happens after calls to helper other methods:<ref>How dynamic finders work http://blog.hasmanythrough.com/2006/8/13/how-dynamic-finders-work </ref>


   def method_missing(method_id, *arguments)
   def method_missing(method_id, *arguments)
Line 39: Line 39:
===Drawbacks===
===Drawbacks===


All else being equal, method_missing is less efficient at runtime than normally defined methods. Besides the fact that the missing_method will need additional checks to determine the next course of action, method_missing is always the last place the ruby interpreter looks. [http://www.alef1.org/ruby/method_missing/]
All else being equal, method_missing is less efficient at runtime than normally defined methods. Besides the fact that the missing_method will need additional checks to determine the next course of action, method_missing is always the last place the ruby interpreter looks. <ref> method_missing: price to pay you http://www.alef1.org/ruby/method_missing/ </ref>


Method_missing can make the code more difficult for humans to follow. It is also does not work well with autocomplete and other features of IDE's or editors.   
Method_missing can make the code more difficult for humans to follow. It is also does not work well with autocomplete and other features of IDE's or editors.   
Line 61: Line 61:
The method_missing class is defined in the Object class, so it is inherited by all objects. It raises a NoMethodError by default.
The method_missing class is defined in the Object class, so it is inherited by all objects. It raises a NoMethodError by default.


There are no similar methods in statically typed languages like Java or C++. Python does not have an equivalent method either, though it can be simulated using the __getattr__ method [http://langexplr.blogspot.com/2008/02/handling-call-to-missing-method-in_06.html].  Firefox's JavaScript implementation now supports a similar __noSuchMethod__ object [https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/noSuchMethod] method, but it is not a JavaScript standard.
There are no similar methods in statically typed languages like Java or C++. Python does not have an equivalent method either, though it can be simulated using the __getattr__ method <ref>Various imlementations in other languages http://langexplr.blogspot.com/2008/02/handling-call-to-missing-method-in_06.html </ref>.  Firefox's JavaScript implementation now supports a similar __noSuchMethod__ object <ref>Javascript documentation https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/noSuchMethod</ref> method, but it is not a JavaScript standard.
==References==
<references/>
==External Links==
==External Links==
[[http://www.thirdbit.net/articles/2007/08/01/10-things-you-should-know-about-method_missing/ 10 Things you should know about method-missing]]
[[http://www.thirdbit.net/articles/2007/08/01/10-things-you-should-know-about-method_missing/ 10 Things you should know about method-missing]]


[[http://www.alef1.org/ruby/method_missing/ method_missing, the price to pay]]
[[http://www.alef1.org/ruby/method_missing/ method_missing, the price to pay]]

Revision as of 23:16, 6 October 2011

Introduction

Examples

Roman Numerals

The classic example for missing_method, given in the Ruby Docs:<ref>Ruby Docs: Object.missing_method http://ruby-doc.org/docs/ProgrammingRuby/html/ref_c_object.html#Object.method_missing </ref>

 class Roman
   def romanToInt(str)
     # ...
   end
   def method_missing(methId)
     str = methId.id2name
     romanToInt(str)
   end
 end

Usage:

 r = Roman.new
 r.iv	»	4
 r.xxiii	»	23
 r.mm	»	2000

The Roman class has no .iv or .xxiii methods, but the method_missing method turns the message into a string with id2name (which takes symbols and returns them as strings), and passes it to the romanToInt. This example shows how method_missing can make the Ruby language very flexible.

method_missing in Rails

Rails, like many domain specific languages of Ruby, makes heavy use of the method_missing function. A prominent example is ActiveRecord, where dynamic finders are implemented using method_missing. When a call like find_by_username is called from an ActiveRecord object, the method does not explicitly exist, rather the message is picked apart in ActiveRecord's Base::method_missing method. The variable part of the message, in this case "username" is turned into an argument to the find method, which is defined. The code below is not exactly what is in the method itself, but outlines what actually happens after calls to helper other methods:<ref>How dynamic finders work http://blog.hasmanythrough.com/2006/8/13/how-dynamic-finders-work </ref>

 def method_missing(method_id, *arguments)
   if match = /find_(all_by|by)_([_a-zA-Z]\w*)/.match(method_id.to_s)
     # find...
   elsif match = /find_or_create_by_([_a-zA-Z]\w*)/.match(method_id.to_s)
     # find_or_create...
   else
     super
   end
 end


Considerations

Drawbacks

All else being equal, method_missing is less efficient at runtime than normally defined methods. Besides the fact that the missing_method will need additional checks to determine the next course of action, method_missing is always the last place the ruby interpreter looks. <ref> method_missing: price to pay you http://www.alef1.org/ruby/method_missing/ </ref>

Method_missing can make the code more difficult for humans to follow. It is also does not work well with autocomplete and other features of IDE's or editors.

All of these things should be considered when deciding whether to rely on method_missing.

Relationship to respond_to?

Ruby objects also have a method called respond_to? which checks to see that a given message corresponds to a method of the class. By default, it will only look for explicitly defined methods. If none are found, it has no mechanism to check whether it is handled by method_missing. This issue is important to consider if the class or its children ever need the respond_to? method. It is good practice to always override the respond_to? method when using method_missing in a class that might be subclassed. In the stub below, we add a respond_to to the Roman Numerals class.

 class Roman
   def respond_to?
     if method_sym.to_s =~ ... // regex to see if it's a valid roman numeral
       true
     else
       super
     end
   end 
 end

Similar functionality in other languages

The method_missing class is defined in the Object class, so it is inherited by all objects. It raises a NoMethodError by default.

There are no similar methods in statically typed languages like Java or C++. Python does not have an equivalent method either, though it can be simulated using the __getattr__ method <ref>Various imlementations in other languages http://langexplr.blogspot.com/2008/02/handling-call-to-missing-method-in_06.html </ref>. Firefox's JavaScript implementation now supports a similar __noSuchMethod__ object <ref>Javascript documentation https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/noSuchMethod</ref> method, but it is not a JavaScript standard.

References

<references/>

External Links

[10 Things you should know about method-missing]

[method_missing, the price to pay]