On Saturday 20 March 2010 11:31:19 am Lars Gierth wrote:
> The other one, of which I have not thought that much
> yet, is that you can't be 100% sure that #const_missing gets hit.

That was mostly my point, and the examples I used are cases where 
const_missing isn't hit.

> What
> if a class/module that uses #autoload defines its own #const_missing?

If they don't do a proper alias_method_chain on it, that's their own problem.

Put another way: You're allowed to redefine Fixnum#+, or NilClass#nil?, or any 
number of other things. If you abuse this ability, you get to keep both 
pieces. Even the authors of irb don't plan for every contingency:

irb(main):001:0> class NilClass                                                    
irb(main):002:1> def nil?                                                          
irb(main):003:2> false                                                             
irb(main):004:2> end                                                               
irb(main):005:1> end                                                               
=>
irb(main):006:0> true
/usr/lib/ruby/1.9.1/irb/slex.rb:234:in `match_io': undefined method `call' for 
nil:NilClass (NoMethodError)
        from /usr/lib/ruby/1.9.1/irb/slex.rb:75:in `match'
        from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:287:in `token'
        from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:263:in `lex'
        from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:234:in `block (2 levels) in 
each_top_level_statement'
        from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:230:in `loop'
        from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:230:in `block in 
each_top_level_statement'
        from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `catch'
        from /usr/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in 
`each_top_level_statement'
        from /usr/lib/ruby/1.9.1/irb.rb:145:in `eval_input'
        from /usr/lib/ruby/1.9.1/irb.rb:69:in `block in start'
        from /usr/lib/ruby/1.9.1/irb.rb:68:in `catch'
        from /usr/lib/ruby/1.9.1/irb.rb:68:in `start'
        from /home/ruby19/bin/irb:12:in `<main>'

> Btw, what's this second braindead decision? I would be very interested
> in it :)

The behavior of UnboundMethod -- you can only bind an UnboundMethod to an 
object of an appropriate class. So, for example:

class Foo
  def bar
    :whatever
  end
end
umeth = Foo.instance_method(:bar)

What do you do with an UnboundMethod? Well, this is roughly how things like 
BlankSlate can hide/unhide methods -- it removes all methods from an object 
and stuffs them into a hash, but you can have it re-apply those methods again, 
kind of like this:

bmeth = umeth.bind(Foo.new)

Once it's bound, you can call it:

bmeth.call

Or shortcut the process:

umeth.bind(Foo.new).call

Here's the problem: In my mind, one of the cooler things about being able to 
unbind methods like this is to allow the kind of free-for-all that you have in 
JavaScript, where you can pull methods out of one object, leave them around in 
the closure to reapply to the same object, or apply them directly to a 
different object... Yes, you could do prototypal inheritance, but you could 
also do ad-hoc code reuse.

As an example, in Ruby, Object#extend and Module#include either are or depend 
on very low-level constructs that aren't really accessible to you. In 
JavaScript, there is no Object.extend, but you can easily write it yourself, 
using the fact that methods are just functions that you apply to (or attach 
to) a given object, and functions are themselves first-class objects.

In Ruby, this isn't quite the case. Try something like this instead:

umeth.bind(Object.new).call

You get a TypeError. That's very Java-like behavior. That's anal-retentively-
strict type-checking sneaking into an otherwise beautiful, dynamic, duck-typed 
language. It's the polar opposite of duck-typing.

There may be performance reasons to do it this way, I'm not sure. (A 
counterargument: How is Ruby doing versus Google's v8 interpreter for 
JavaScript?) When I've brought it up before, people essentially argued that 
it's never sane to do that, so I shouldn't be able to. Erm, I can redefine 
Fixnum#+, you've got open classes, define_method, and eval, and you won't let 
me re-bind an existing method? Sorry, not buying it -- I thought the whole 
point is that it's up to the programmer to decide what's sane, and if you do 
something insane, you get to keep both pieces.

I thought it was only languages like Java that try to keep you from shooting 
yourself in the foot by limiting your possibilities.

But I digress -- I did find an ugly workaround for the project I needed that 
on, and that project has stagnated for awhile anyway. Still, it's one of very 
few things that still bother me about Ruby.

(Another is that I really like Python's significant indentation, and much 
prefer it to Ruby's end-end-end-end. However, that's a dead horse, and there 
seem to be entirely too many Ruby people who don't want to see that even 
become an option, and there's too many other things I like about Ruby for that 
one feature to send me back to Python.)