# Caveats with #method\_missing

**URL:** <https://www.ruby-forum.com/t/caveats-with-method-missing/70660>\
**Category:** Ruby\
**Created:** [October 1, 2006, 6:27pm UTC](https://www.ruby-forum.com/t/caveats-with-method-missing/70660 "2006-10-01T18:27:00Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Trans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/dfb087/32.png) [@Trans](https://www.ruby-forum.com/u/Trans)\
**Post date:** [October 1, 2006, 6:27pm UTC](https://www.ruby-forum.com/t/caveats-with-method-missing/70660/1 "2006-10-01T18:27:00Z")

</div>

Even after the public/private send issue is resolved with #funcall,  
#send!, #instance\_send or what ever is method decided upon, how will we  
be ablesto distinguish between a private and a public method call in  
method\_missing?

Also when delaing with writers, the need to do things like:

def method\_missing( sym, \*args, &blk )  
if sym.to\_s =~ /=$/  
@data[sym.to\_s.chomp(’=’).to\_sym] = args[0]

Is, well… Blech! I’d like to see something like:

def writer\_missing( name, value )  
@data[name] = value  
end

Thoughts?  
T.

---

<div class="post-metadata">

**Author:** ![Trans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/dfb087/32.png) [@Trans](https://www.ruby-forum.com/u/Trans)\
**Post date:** [October 1, 2006, 6:51pm UTC](https://www.ruby-forum.com/t/caveats-with-method-missing/70660/2 "2006-10-01T18:51:15Z")

</div>

/what ever is method decided upon, how will we be ablesto distinguish/  
whichever method is decided upon, how will we be able to distinguish

T.

---

<div class="post-metadata">

**Author:** ![Trans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/dfb087/32.png) [@Trans](https://www.ruby-forum.com/u/Trans)\
**Post date:** [October 1, 2006, 7:07pm UTC](https://www.ruby-forum.com/t/caveats-with-method-missing/70660/3 "2006-10-01T19:07:18Z")

</div>

On 10/1/06, Trans [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Is, well… Blech! I’d like to see something like:
> 
> def writer\_missing( name, value )  
> @data[name] = value  
> end
> 
> Thoughts?  
> T.

I’ve thought of proposing something like define\_method but for missing  
methods:

# Just some rough ideas…

class Example  
define\_missing\_method /^find\_\w+$/ do |sym, \*args, &block|  
puts “Handling #{sym}”  
end  
end

ex1 = Example.new

ex1.respond\_to? :find\_something #=\> true  
ex1.respond\_to? :not\_found #=\> false

We could probably extend a few methods around this as well:

ex1.missing\_methods # Maybe return patterns/strings  
ex1.methods # We could possibly return something here… big change  
ex1.all\_methods # This might be a better alternative for a combined list

Both of these ideas should be simple enough to implement prototypes in  
pure Ruby. I’ll have to spend time on this and get some code that we  
can play with.

I do like the simpler method definition but I don’t really like the  
idea of having magically connected names. It would also mean we would  
have problems around “method\_missing” as a name. I would rather get  
some nice helpers that hook into a much smarter method\_missing system.

Brian.

---

<div class="post-metadata">

**Author:** ![Trans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/dfb087/32.png) [@Trans](https://www.ruby-forum.com/u/Trans)\
**Post date:** [October 1, 2006, 8:21pm UTC](https://www.ruby-forum.com/t/caveats-with-method-missing/70660/4 "2006-10-01T20:21:25Z")

</div>

Brian M. wrote:

> > ```
> > @data[sym.to_s.chomp('=').to_sym] = args[0]
> > 
> > ```
> 
> I’ve thought of proposing something like define\_method but for missing methods:
> 
> pure Ruby. I’ll have to spend time on this and get some code that we  
> can play with.
> 
> I do like the simpler method definition but I don’t really like the  
> idea of having magically connected names. It would also mean we would  
> have problems around “method\_missing” as a name. I would rather get  
> some nice helpers that hook into a much smarter method\_missing system.
> 
> Brian.

Roll your own (or use mine). I decided here to pass the matchinfo,  
rather than the symbol, so that you could take advantage of match  
groups. Modify to suit.

module MissingMethod  
def method\_missing symbol,\*args  
matchinfo=nil  
code=nil  
if self.class.methods\_missing.any? do |pattern,code|  
matchinfo= pattern.match(symbol.to\_s)  
end  
code.call(matchinfo,\*args) { |\*args| yield \*args}  
else  
super  
end  
end

module ClassMethods  
def define\_missing\_method pattern,&code  
methods\_missing \<\< [pattern,code]  
end  
def methods\_missing  
@methods\_missing ||= []  
end  
end  
def self.included(other)  
other.extend(ClassMethods)  
end  
end

class A  
include MissingMethod  
define\_missing\_method /^(._)=/ do |matchinfo,newval|  
 @data ||= Hash.new  
 @data[matchinfo[1]] = newval  
end  
define\_missing\_method /^(._)/ do |matchinfo|  
@data[matchinfo[1]]  
end  
end

a=A.new  
a.myfunc=“a”  
p a.myfunc

---

<div class="post-metadata">

**Author:** ![Trans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/dfb087/32.png) [@Trans](https://www.ruby-forum.com/u/Trans)\
**Post date:** [October 1, 2006, 10:01pm UTC](https://www.ruby-forum.com/t/caveats-with-method-missing/70660/5 "2006-10-01T22:01:34Z")

</div>

On 10/1/06, Trans [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Even after the public/private send issue is resolved with #funcall,  
> #send!, #instance\_send or what ever is method decided upon, how will we  
> be ablesto distinguish between a private and a public method call in  
> method\_missing?

I have an modest proposal - can’t we just get rid of private methods  
completely in Ruby 2 ?

They are very ugly and not very useful.

- You don’t get a separate namespace for them (unlike C++), so they  
aren’t really that private
- In most other object-oriented systems, public/private distinction is  
useful to protect instance variables. In Ruby instance variables are  
private anyway. And how often private methods are actually useful ?
- Private methods are counterproductive. People just keep finding new  
ways of using objects. A random example - Class#define\_method is  
private but shouldn’t be. And unit testing becomes more difficult  
(every method should be tested, whether marked private or not).
- It complicates mental model of Ruby. Instead of having only a single  
operation “send message to an object” it needs two - “send message to  
an object” and “send message to self”, which are very similar but just  
different enough to cause confusion.
- Having private methods causes all sorts of ugly problems. We need  
two versions of send (and **send** ), two versions of method\_missing,  
two versions of define\_method, etc. It all goes away if all methods  
are private.

There’s still a problem with global functions, as they are going to  
pollute method namespace. However the method namespace is already  
getting  
polluted that way, but only for “send message to self” operation, not  
for  
generic “send message to an object”. So it’s not that bad.

For cases where we really need to avoid this polution (and want to  
catch everything by method\_missing), we have BasicObject.  
Reflection becomes a bit uglier as Class#methods now returns  
“real” methods and global functions on a single list.  
That’s the only problems I see.

This proposal is radical. Maybe too radical.  
But wouldn’t Ruby be nicer this way ?

---

<div class="post-metadata">

**Author:** ![Trans](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/dfb087/32.png) [@Trans](https://www.ruby-forum.com/u/Trans)\
**Post date:** [October 1, 2006, 10:25pm UTC](https://www.ruby-forum.com/t/caveats-with-method-missing/70660/6 "2006-10-01T22:25:35Z")

</div>

On Mon, 2006-10-02 at 05:00 +0900, Tomasz W. wrote:

> I have an modest proposal - can’t we just get rid of private methods  
> completely in Ruby 2 ?  
> [snip justification]

The private modifier in Ruby is usually more advisory than anything  
else. That’s why #define\_method is private, for example. Just like  
private instance variables indicate data that clients of the class  
shouldn’t touch, private methods indicate operations clients of the  
class shouldn’t touch. Note “shouldn’t” as opposed to “can’t”. Certainly  
clients of a class have no business redefining its methods on a regular  
basis - if that was intended, the class would be engineered for  
inheriting and clients could create their own customized versions. Using  
metaprogramming for this is more of an emergency measure when the author  
of the modified code didn’t foresee the need for this and code  
accordingly.

In my code, I use private methods for helper operations to dissect an  
algorithm into separate steps - these serve only to give fragments of  
code a name, not encapsulate any standalone functionality. Calling them  
out-of-order from client code would usually clobber an object’s  
internals beyond repair.

In all OO systems, the private / public distinction is to hide  
information about the inner workings of a class. While instance  
variables are obviously such information, often also how a class  
achieves what it does qualifies.

If you have to call **methods** directly, that’s one more indication  
that you’re Doing Something Weird.

The difficulty in unit-testability is more of a failure on the side of  
the test framework. Including a “whitebox” mode in Test::Unit  
(generating public wrappers for private methods of tested classes) would  
be a more concise solution to this problem.

The feature of private methods in Ruby is one I like. It’s an  
encapsulation safety net as opposed to a roadblock in Ruby, but makes it  
more apparent in code that something out-of-the-ordinary is being done.

I might be biased, since I’m opposed to strong usage of Ruby’s  
metaprogramming capacities in “serious” code, at least without  
encapsulating such code very tightly. But removing all method-level  
encapsulation to facilitate meta hacks or get rid of some scenarios when  
they are necessary seems just overkill.

David V.
