23

In Ruby, objects have a handy method called method_missing which allows one to handle method calls for methods that have not even been (explicitly) defined:

Invoked by Ruby when obj is sent a message it cannot handle. symbol is the symbol for the method called, and args are any arguments that were passed to it. By default, the interpreter raises an error when this method is called. However, it is possible to override the method to provide more dynamic behavior. The example below creates a class Roman, which responds to methods with names consisting of roman numerals, returning the corresponding integer values.

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

r = Roman.new
r.iv      #=> 4
r.xxiii   #=> 23
r.mm      #=> 2000

For example, Ruby on Rails uses this to allow calls to methods such as find_by_my_column_name.

My question is, what other languages support an equivalent to method_missing, and how do you implement the equivalent in your code?

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284

15 Answers15

16

Smalltalk has the doesNotUnderstand message, which is probably the original implementation of this idea, given that Smalltalk is one of Ruby's parents. The default implementation displays an error window, but it can be overridden to do something more interesting.

John Topley
  • 113,588
  • 46
  • 195
  • 237
  • Cool! But is there an example anywhere of how you would use this message? – Justin Ethier May 19 '10 at 14:02
  • 2
    "Combined with #become:, which causes two objects to trade places in memory, this capability of #doesNotUnderstand: is very useful for implementing ProxyObjects such as are needed in Object Relational Mapping frameworks" http://c2.com/cgi/wiki?DoesNotUnderstand – Joe Koberg May 19 '10 at 19:45
12

PHP objects can be overloaded with the __call special method.

For example:

<?php
class MethodTest {
    public function __call($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');
?>
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
tylermac
  • 499
  • 2
  • 8
11

Some use cases of method_missing can be implemented in Python using __getattr__ e.g.

class Roman(object):
  def roman_to_int(self, roman):
    # implementation here

  def __getattr__(self, name):
    return self.roman_to_int(name)

Then you can do:

>>> r = Roman()
>>> r.iv
4
mikej
  • 65,295
  • 17
  • 152
  • 131
  • `roman_to_int` has empty implementation, so why does r.iv return 4? – Tim Jul 08 '17 at 01:09
  • @Tim You're suppose to fill in the blank with code that would return a value. He just decided not to show all the details. This could be implemented with a roman numeral to number converter. – Christian Dean Jul 08 '17 at 01:21
10

I was looking for this before, and found a useful list (quickly being overtaken here) as part of the Merd project on SourceForge.


 Construct                          Language
-----------                        ----------
 AUTOLOAD                           Perl
 AUTOSCALAR, AUTOMETH, AUTOLOAD...  Perl6
 __getattr__                        Python
 method_missing                     Ruby
 doesNotUnderstand                  Smalltalk
 __noSuchMethod__(17)               CoffeeScript, JavaScript
 unknown                            Tcl
 no-applicable-method               Common Lisp
 doesNotRecognizeSelector           Objective-C
 TryInvokeMember(18)                C#
 match [name, args] { ... }         E
 the predicate fail                 Prolog
 forward                            Io

With footnotes:

  • (17) firefox
  • (18) C# 4, only for "dynamic" objects
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
9

Perl has AUTOLOAD which works on subroutines & class/object methods.

Subroutine example:

use 5.012;
use warnings;

sub AUTOLOAD {
    my $sub_missing = our $AUTOLOAD;
    $sub_missing =~ s/.*:://;
    uc $sub_missing;
}

say foo();   # => FOO

Class/Object method call example:

use 5.012;
use warnings;

{
    package Shout;

    sub new { bless {}, shift }

    sub AUTOLOAD {
        my $method_missing = our $AUTOLOAD;
        $method_missing =~ s/.*:://;
        uc $method_missing;
    }
}

say Shout->bar;         # => BAR

my $shout = Shout->new;
say $shout->baz;        # => BAZ
draegtun
  • 22,441
  • 5
  • 48
  • 71
muhmuhten
  • 3,313
  • 1
  • 20
  • 26
9

JavaScript has noSuchMethod, but unfortunately this is only supported by Firefox/Spidermonkey.

Here is an example:

wittyProjectName.__noSuchMethod__ = function __noSuchMethod__ (id, args) {
   if (id == 'errorize') {
    wittyProjectName.log("wittyProjectName.errorize has been deprecated.\n" +
                         "Use wittyProjectName.log(message, " +
                         "wittyProjectName.LOGTYPE_ERROR) instead.",
                         this.LOGTYPE_LOG);
    // just act as a wrapper for the newer log method
    args.push(this.LOGTYPE_ERROR);
    this.log.apply(this, args);
  }
}
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
8

Objective-C supports the same thing and calls it forwarding.

Edward Dale
  • 29,597
  • 13
  • 90
  • 129
8

This is accomplished in Lua by setting the __index key of a metatable.

t = {}
meta = {__index = function(_, idx) return function() print(idx) end end}
setmetatable(t, meta)

t.foo()
t.bar()

This code will output:

foo
bar
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
5

In Common Lisp, no-applicable-method may be used for this purpose, according to the Common Lisp Hyper Spec:

The generic function no-applicable-method is called when a generic function is invoked and no method on that generic function is applicable. The default method signals an error.

The generic function no-applicable-method is not intended to be called by programmers. Programmers may write methods for it.

So for example:

(defmethod no-applicable-method (gf &rest args)
  ;(error "No applicable method for args:~% ~s~% to ~s" args gf)
  (%error (make-condition 'no-applicable-method :generic-function gf :arguments args) '()
        ;; Go past the anonymous frame to the frame for the caller of the generic function
        (parent-frame (%get-frame-ptr))))
Community
  • 1
  • 1
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
  • 3
    I don't think this gives you the same kind of syntactic sugar you get from it in Ruby, though. In the `r.xxiii` example, to invoke NO-APPLICABLE-METHOD from (XXIII R), you'd need to first define a generic function called XXIII, right? – Kragen Javier Sitaker Jul 14 '11 at 04:13
5

C# now has TryInvokeMember, for dynamic objects (inheriting from DynamicObject)

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 4
    DynamicObject even has some more methods in this regard, though TryInvokeMember is the direct equivalent of method_missing. And there's also ExpandoObject, which allows to add properties at runtime. Depending on what you actually want to solve, these may be good ways too. – OregonGhost May 20 '10 at 10:39
3

Actionscript 3.0 has a Proxy class that can be extended to provide this functionality.

dynamic class MyProxy extends Proxy {
  flash_proxy override function callProperty(name:*, ...rest):* {
    try {
      // custom code here
    }
    catch (e:Error) {
      // respond to error here
    }
}  
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
tylermac
  • 499
  • 2
  • 8
2

Tcl has something similar. Any time you call any command that can't be found, the procedure unknown will be called. While it's not something you normally use, it can be handy at times.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
2

In CFML (ColdFusion, Railo, OpenBD), the onMissingMethod() event handler, defined within a component, will receive undefined method calls on that component. The arguments missingMethodName and missingMethodArguments are automatically passed in, allowing dynamic handling of the missing method call. This is the mechanism that facilitated the creation of implicit setter/getter schemes before they began to be built into the various CFML engines.

Ken Redler
  • 23,863
  • 8
  • 57
  • 69
2

Its equivalent in Io is using the forward method.

From the docs:

If an object doesn't respond to a message, it will invoke its "forward" method if it has one....

Here is a simple example:

Shout := Object clone do (
    forward := method (
        method_missing := call message name
        method_missing asUppercase
    )
)

Shout baz println     # => BAZ

/I3az/

draegtun
  • 22,441
  • 5
  • 48
  • 71
1

Boo has IQuackFu - there is already an excellent summary on SO at how-can-i-intercept-a-method-call-in-boo

Here is an example:

class XmlObject(IQuackFu):
_element as XmlElement 

def constructor(element as XmlElement):
    _element = element 

def QuackInvoke(name as string, args as (object)) as object:
    pass # ignored 

def QuackSet(name as string, parameters as (object), value) as object:
    pass # ignored 

def QuackGet(name as string, parameters as (object)) as object:
    elements = _element.SelectNodes(name)
    if elements is not null:
        return XmlObject(elements[0]) if elements.Count == 1
        return XmlObject(e) for e as XmlElement in elements 

override def ToString():
    return _element.InnerText 
Community
  • 1
  • 1
Justin Ethier
  • 131,333
  • 52
  • 229
  • 284