# Kernel#autoload ignores custom monkey patched Kernel#require

**URL:** <https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768>\
**Category:** Ruby\
**Created:** [March 8, 2010, 11:25am UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768 "2010-03-08T11:25:23Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![lgierth](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/d6d6ee/32.png) [@lgierth](https://www.ruby-forum.com/u/lgierth)\
**Post date:** [March 8, 2010, 11:25am UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768/1 "2010-03-08T11:25:23Z")

</div>

Hi,

I’m playing with FakeFS and want to fake Kernel#require. That’s working  
quite well now, but somehow Kernel#autoload doesn’t recognize my custom  
#require. The documentation says that #autoload would try to load the  
file via Kernel::require, which is contradictory, as there’s only  
Kernel#require.

The following snippet doesn’t print “foo/bar”, as I would expect.

module Kernel  
def require fn  
puts fn  
end  
end

module Foo  
autoload :Bar, “foo/bar”  
end

Foo::Bar

Does anyone have an idea on this?

Best regards,  
Lars

---

<div class="post-metadata">

**Author:** ![lgierth](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/d6d6ee/32.png) [@lgierth](https://www.ruby-forum.com/u/lgierth)\
**Post date:** [March 8, 2010, 2:58pm UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768/2 "2010-03-08T14:58:02Z")

</div>

Hi,

thanks a lot for pointing me on this discussion, quite interesting 😉

Best regards,  
Lars

Luis L. wrote:

> [ruby-core:20190]  
> [http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/20190?20046-21072+split-mode-vertical](http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/20190?20046-21072+split-mode-vertical)

---

<div class="post-metadata">

**Author:** ![lgierth](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/d6d6ee/32.png) [@lgierth](https://www.ruby-forum.com/u/lgierth)\
**Post date:** [March 8, 2010, 1:45pm UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768/3 "2010-03-08T13:45:57Z")

</div>

On Mar 8, 11:25 am, Lars G. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> Hi,
> 
> I’m playing with FakeFS and want to fake Kernel#require. That’s working  
> quite well now, but somehow Kernel#autoload doesn’t recognize my custom  
> #require. The documentation says that #autoload would try to load the  
> file via Kernel::require, which is contradictory, as there’s only  
> Kernel#require.

[ruby-core:20190]  
[http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/20190?20046-21072+split-mode-vertical](http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/20190?20046-21072+split-mode-vertical)

---

<div class="post-metadata">

**Author:** ![lgierth](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/d6d6ee/32.png) [@lgierth](https://www.ruby-forum.com/u/lgierth)\
**Post date:** [March 19, 2010, 5:23pm UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768/4 "2010-03-19T17:23:35Z")

</div>

Lars G. wrote:

> I’m playing with FakeFS and want to fake Kernel#require.

Hi again, I git this working by overwriting #const\_missing?, #autoload?  
and #autoload.

Source is on GitHub:  
[http://github.com/lgierth/fakefs/blob/topic/fake-require/lib/fakefs/require.rb](http://github.com/lgierth/fakefs/blob/topic/fake-require/lib/fakefs/require.rb)

---

<div class="post-metadata">

**Author:** ![lgierth](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/d6d6ee/32.png) [@lgierth](https://www.ruby-forum.com/u/lgierth)\
**Post date:** [March 20, 2010, 5:31pm UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768/5 "2010-03-20T17:31:14Z")

</div>

Hi David,

thanks a lot for pointing this out. It’s indeed one more limitation of  
FakeFS::Require. 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. What  
if a class/module that uses #autoload defines its own #const\_missing?  
I’ll think about this when I have some time for it, but for now - and  
for my usecase - it’s fine: testing a library that loads ruby source  
files by configuration, assisted by libraries that autoload files (Rack)  
or load files from stdlib during runtime (Usher).

Btw, what’s this second braindead decision? I would be very interested  
in it 🙂

Best regards,  
Lars

---

<div class="post-metadata">

**Author:** ![lgierth](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/d6d6ee/32.png) [@lgierth](https://www.ruby-forum.com/u/lgierth)\
**Post date:** [March 19, 2010, 8:33pm UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768/6 "2010-03-19T20:33:47Z")

</div>

On Friday 19 March 2010 11:23:37 am Lars G. wrote:

> Lars G. wrote:
> 
> > I’m playing with FakeFS and want to fake Kernel#require.
> 
> Hi again, I git this working by overwriting #const\_missing?, #autoload?  
> and #autoload.

You probably didn’t.

One example I know where Kernel#autoload works and const\_missing doesn’t  
is  
when defining a const. For example:

irb(main):001:0\> autoload :CSV, ‘csv’  
=\> nil  
irb(main):002:0\> module CSV  
irb(main):003:1\> end  
TypeError: CSV is not a module  
from (irb):2  
from /home/ruby19/bin/irb:12:in `’

The obvious danger here is when you try monkeypatching something first,  
and  
then using it:

autoload :CSV, ‘csv’  
class CSV  
def foo  
# …  
end  
end

With a real Kernel#autoload, that class definition will be referring to  
CSV,  
and actually autoload the file first, so you’ll be extending CSV. With  
this  
one, it won’t, because neither of the examples above will ever hit  
const\_missing, or anything else I know of that the application can  
override.

This is why we need to actually need to have Kernel#autoload behave  
properly  
with an overridden Kernel#require, or at least have enough primitives  
exposed  
that we can redefine Kernel#autoload. At the moment, the _only_ option  
is to  
override $:, which only makes sense if you’re _always_ going to autoload  
a  
file, as opposed to a URL, an expression, or anything else.

This has apparently been known about for years. It’s one of two fairly  
brain-  
dead decisions I’ve seen the Ruby language make, and unfortunately, is  
the  
kind of problem that can really only be fixed by hacking on the  
interpreter  
itself.

---

<div class="post-metadata">

**Author:** ![lgierth](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/d6d6ee/32.png) [@lgierth](https://www.ruby-forum.com/u/lgierth)\
**Post date:** [March 20, 2010, 11:35pm UTC](https://www.ruby-forum.com/t/kernel-autoload-ignores-custom-monkey-patched-kernel-require/184768/7 "2010-03-20T23:35:36Z")

</div>

On Saturday 20 March 2010 11:31:19 am Lars G. 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 `’

> 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.)
