Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Ruby Quiz (A Trick Question)

Pivotal Labs
Sunday, December 9, 2007

Here is a little Ruby trivium for you.

Type this into IRB:

def foo
  def bar
    1
  end
end

foo.bar
=> 1

Is this some magical lightweight object creation syntax so you can do cool method chaining? Let’s try another example:

def foo
  def foo
    1
  end
end

foo
=> nil

foo.foo
=> 1

So far so good. But now, type:

foo
=> 1

WTF? Is this a defect in Ruby?? Post your responses in the comments.

(Warning: this is a trick question)
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

19 Comments

  1. Tomtt says:

    My guess is that running foo overloads itself so that next time you run foo it runs the new def instead which returns 1. Do I get I prize? :)

    December 12, 2007 at 11:50 pm

  2. Dave Smith says:

    Hint: What does invoking “bar” yield before and after invoking “foo.bar”?

    December 12, 2007 at 11:50 pm

  3. Chris Anderson says:

    In the first context you also get:

    Array.bar #=> 1

    bar is just defined on Object. I don’t know what good foo is doing on the outside… or why it’s return value changes after the deeper call. defect? I dunno. Useful… doubt it.

    Ruby can be a little strange around the edges.

    December 12, 2007 at 11:50 pm

  4. Mark Wilden says:

    Here’s my go:

    The “outer” foo definition is a method that, when invoked, defines a method foo that returns 1. The definition itself returns nil, so calling foo the first time returns nil. But that replaces foo with another definition, so calling foo the second time returns 1.

    What I’m gathering from this is that methods defined at global scope can be called on nil, (or any object?)?

    ///ark

    December 12, 2007 at 11:50 pm

  5. Chris Anderson says:

    Ah thanks Dave. bar doesn’t get defined until foo runs. It makes some of the more verbose metaprogramming idioms look like overkill. I wonder if you can attach the inner method to an object. I’ll have to try the whole thing in a class context sometime.

    December 12, 2007 at 11:50 pm

  6. Tomtt says:

    You can build a silly iterate-then-repeat-last-value function using this principle as well:

    def fat_because
      def fat_because
        def fat_because
          def fat_because
            "when she sits around the house, she SITS AROUND THE HOUSE!"
           end
          "she had to go to Sea World to get baptized"
        end
        "whenever she goes to the beach the tide comes in!"
      end
      "she wakes up in sections!"
    end
    
    5.times do
      puts "Yo mama so fat %s" % fat_because
    end
    

    Produces:

    Yo mama so fat she wakes up in sections!
    Yo mama so fat whenever she goes to the beach the tide comes in!
    Yo mama so fat she had to go to Sea World to get baptized
    Yo mama so fat when she sits around the house, she SITS AROUND THE HOUSE!
    Yo mama so fat when she sits around the house, she SITS AROUND THE HOUSE!
    

    December 12, 2007 at 11:50 pm

  7. Tim Connor says:

    With apologies to eminem: “And all ya fools act like ya forgot about self.”

    Ya, the foo methods just defines the bar method on self, when called, right? More verbosely it’s roughly (not saying this syntax is correct, I suspect it might choke in rb, but for illustrative purposes)

    def foo
      self.define_method :bar proc(1)
    end
    

    December 12, 2007 at 11:50 pm

  8. Tim Connor says:

    damn, missed a comma as well.

    December 12, 2007 at 11:50 pm

  9. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  10. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  11. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  12. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  13. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  14. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  15. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  16. Garry says:

    Running ‘foo’ the first time runs ‘def foo; 1 end’, which now defines ‘foo’ to return 1. Running ‘foo’ at this point, without even doing ‘foo.foo’ will return 1. But why ‘foo.foo’ then also returns 1 is still a mystery to me. In fact, ‘foo.foo.foo.foo.foo’, ad infinitum, will still return 1. Interesting :)

    December 12, 2007 at 11:50 pm

  17. Garry says:

    OH JESUS, sorry for the million posts, the “Submit” button wasn’t doing anything for a while and I button mashed it!

    December 12, 2007 at 11:50 pm

  18. szeryf says:

    Garry, that’s because foo is defined on every object, including object 1:Fixnum, so foo.foo.foo.foo is just method chain. Each .foo is called on an object, that was returned from previous invocation. There’s nothing magical in it. In fact you can chain this way every method from object, like nil? or to_s.

    December 12, 2007 at 11:50 pm

  19. Milan says:

    In irb,
    self.class => Object, so that’s why foo gets defined as an instance method of Object. When executed inside a class, it gets defined as an instance method for that class.

    Oh, and Garry’s multiple comments re: multiple function calls are sort of accidentally hilarious.

    December 12, 2007 at 11:50 pm

Add New Comment Cancel reply

Your email address will not be published.

Pivotal Labs

Pivotal Labs

Recent Posts

  • Does the set of all sets contain itself?
  • Standup 3/8/2012
  • Standup 3/7/2012
Subscribe to Pivotal's Feed

Author Topics

riddles (1)
agile (167)
capistrano (2)
rails (26)
movember (1)
git (10)
railsdoc (1)
object-design (1)
bdd (3)
cucumber (3)
linkedin (1)
oauth (1)
ruby (17)
tdd (2)
lvh.me (1)
rails 3.1.1 (1)
selenium (6)
homebrew (1)
mysql (5)
rvm (1)
sproutcore (1)
paperclip (2)
pry (1)
amazon (1)
heroku (1)
rails3 (2)
jasmine (3)
design (3)
process (12)
productivity (8)
learning (1)
olin (1)
migrations (2)
mongodb (2)
devise (2)
javascript (13)
rubymine (4)
ipad (1)
whurl (1)
head.js (1)
pairing (2)
tools (4)
pair programming (1)
rspec (10)
rspec2 (1)
ruby19 (1)
incubation (3)
startup (5)
api (1)
presenter (1)
vanna (1)
pivotal tracker (5)
capybara (1)
fakeweb (1)
webmock (1)
intern (1)
ruby on rails (25)
meetup (1)
textmate (1)
testing (20)
solr (4)
nyc-standup (11)
community (1)
opensource (3)
activerecord (4)
chrome (1)
mp4 (1)
activeresource (1)
flash (3)
neo4j (1)
nginx (1)
rsoc (1)
meta programming (1)
agile standup (7)
government (3)
webos (4)
xss (1)
jquery (1)
bundler (2)
ci (3)
gems (5)
postgresql (1)
geminstaller (1)
gemcutter (1)
cloud (2)
rack (2)
refraction (1)
gem (5)
refactoring (1)
validations (1)
webrat (1)
engine-yard (1)
firefox (2)
jsunit (1)
mongrel (2)
thin (1)
unicorn (1)
facebook (1)
rubygems (5)
jruby (1)
actioncontroller (1)
rails 2.3 (1)
palmpre (1)
autotest (1)
mac (2)
hosting (1)
goruco (11)
database (3)
railsconf (11)
gogaruco (4)
deployment (4)
github (1)
ie (1)
ajax (1)
intellij (1)
json (1)
asset packaging (1)
polonium (1)
character encoding (1)
utf-8 (1)
test (3)
civics (1)
hpricot (1)
rake (3)
sms (1)
unicode (1)
iphone (1)
java (1)
safari (1)
memory leaks (1)
rr (3)
editor (1)
css (1)
nyc (3)
performance (5)
fun (5)
enterprise rails (1)
health (1)
new and cool (1)
general (2)
treetop (1)
errors (1)
stack (1)
trace (1)
cache (1)
cookies (1)
freesoftware (1)
conferences (1)
development (1)
driven (1)
proxy (1)
caching (1)
peertopatent (1)
languages (1)
rest (2)
rubyforge (1)
sake (1)
file (1)
upload (1)
constants (1)
osx (1)
terminal (1)
pairprogramming (2)
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >