SlideShare a Scribd company logo
The revenge of method_missing()




       Paolo “Nusco” Perrotta
Should I use method_missing()
  to remove duplication from
my code, or should I avoid it
       like the plague?

      Paolo “Nusco” Perrotta
The Revenge of method_missing()
disclaimer
Person.find_by_user_name_and_password name, pwd
class NilClass
  # ...

  def method_missing(method, *args, &block)
    if klass = METHOD_CLASS_MAP[method]
      raise_nil_warning_for klass, method, caller
    else
      super
    end
  end
end
end of disclaimer
class InfoDesk
  def flights
    # ...
  end

  def trains
    # ...
  end

  def hotels
    # ...
  end

  # ...
end
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  def flights
    return “Out for lunch” if Clock.lunch_time?
    @desk.flights
  end

  def trains
    return “Out for lunch” if Clock.lunch_time?
    @desk.local_transports
  end

  def hotels
    return “Out for lunch” if Clock.lunch_time?
    @desk.local_transports
  end

  # ...
end
The Revenge of method_missing()
The Revenge of method_missing()
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  def method_missing(name, *args)
    return “Out for lunch” if Clock.lunch_time?
    @desk.send(name, *args)
  end
end

# At 12:30...
Sign.new.flights    # => “Out for lunch”
Ghost Methods
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  InfoDesk.public_instance_methods.each do |m|
    define_method(m) do
      return “Out for lunch” if Clock.lunch_time?
      @desk.send(m)
    end
  end
end
Ghost Methods
      vs.
Dynamic Methods
the four pitfalls
of method_missing()
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  def method_missing(name, *args)
    return “Out for lunch” if Clock.lunch_time?
    @desk.send(name, *args)
  end
end
we have a problem
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  def is_it_lunch_time_yet?
    Clock.lunch_time?
  end

  def method_missing(name, *args)
    return “Out for lunch” if is_it_lunchtime_yet?
    @desk.send(name, *args)
  end
end

# At 12:30...
Sign.new.flights   # => ?
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  def is_it_lunch_time_yet?
    Clock.lunch_time?
  end

  def method_missing(name, *args)
    return “Out for lunch” if is_it_lunchtime_yet?
    @desk.send(name, *args)
  end
end

# At 12:30...
Sign.new.flights   # => ?
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  def is_it_lunch_time_yet?
    Clock.lunch_time?
  end

  def method_missing(name, *args)
    return “Out for lunch” if is_it_lunchtime_yet?
    @desk.send(name, *args)
  end
end

# At 12:30...
Sign.new.flights   # => SystemStackError: stack level too deep
the first pitfall:




 the Ghost House
class Sign
  def initialize
    @desk = InfoDesk.new
  end

  def method_missing(name, *args)
    return super unless @desk.respond_to? name

    return “Out for lunch” if Clock.lunch_time?
    @desk.send(name, *args)
  end
end
we have a problem
Sign.new.respond_to? :flights   # => false
the second pitfall:




  the Liar Object
class Sign
  def initialize
    @desk = ::InfoDesk.new
  end

  def method_missing(name, *args)
    return super unless @desk.respond_to? name

    return “Out for lunch” if Clock.lunch_time?
    @desk.send(name, *args)
  end

  def respond_to?(method)
    @desk.respond_to?(method) || super
  end
end

Sign.new.respond_to? :flights   # => true
we have a problem
class InfoDesk
  def flights
    # ...
  end

  def local_transports
    # ...
  end

  # ...

  def display
    # ...
  end
end
Sign.new.display   # => #<Sign:0x000001008451b0>
The Revenge of method_missing()
The Revenge of method_missing()
the third pitfall:




  the Fake Ghost
class Sign
  instance_methods.each do |m|
    undef_method m unless m.to_s =~ /^__|object_id/
  end

  def initialize
    @desk = InfoDesk.new
  end

  def method_missing(name, *args)
    return super unless @desk.respond_to? name

    return "Out for lunch" if Clock.lunch_time?
    @desk.send(name, *args)
  end

  def respond_to?(method)
    @desk.respond_to? method || super
  end
end

Sign.new.display   # => InfoDesk#display() called
class Sign < BasicObject
  def initialize
    @desk = ::InfoDesk.new
  end

  def method_missing(name, *args)
    return super unless @desk.respond_to? name

    return “Out for lunch” if ::Clock.lunch_time?
    @desk.send(name, *args)
  end

  def respond_to?(method)
    @desk.respond_to? method || super
  end
end

Sign.new.display   # => InfoDesk#display() called
we have a problem
    (this is getting old already)
The Revenge of method_missing()
the fourth pitfall:




  the Snail Ghost
class Sign < BasicObject
  def initialize
    @desk = ::InfoDesk.new
  end

  def method_missing(name, *args)
    return super unless @desk.respond_to? name

    singleton_class.send :define_method, name do
      return “Out for lunch” if ::Clock.lunch_time?
      @desk.send name
    end
    send name
  end

  def respond_to?(method)
    @desk.respond_to? method || super
  end
end

# At 12:30...
Sign.new.flights # => ?
class Sign < BasicObject
  def initialize
    @desk = ::InfoDesk.new
  end

  def method_missing(name, *args)
    return super unless @desk.respond_to? name

    singleton_class.send :define_method, name do
      return “Out for lunch” if ::Clock.lunch_time?
      @desk.send name
    end
    send name
  end

  def respond_to?(method)
    @desk.respond_to? method || super
  end
end

# At 12:30...
Sign.new.flights # => SystemStackError: stack level too deep
class Sign < BasicObject
  def initialize
    @desk = ::InfoDesk.new
  end

  def method_missing(name, *args)
    return super unless @desk.respond_to? name

    singleton_class.send :define_method, name do
      return “Out for lunch” if ::Clock.lunch_time?
      @desk.send name
    end
    send name
  end

  def respond_to?(method)
    @desk.respond_to? method || super
  end
end

# At 12:30...
Sign.new.flights # => SystemStackError: stack level too deep
The Revenge of method_missing()
The Revenge of method_missing()
should I use method_missing()
   to remove duplication in
           my code?
not if you can use
define_method() instead
just a rule of thumb
remember the four pitfalls:
         the Ghost House

         the Liar Object

         the Fake Ghost

         the Snail Ghost
thank you.
The Revenge of method_missing()

More Related Content

PDF
Ruby Refinements: the Worst Feature You Ever Loved
paoloperrotta
 
PDF
Declarative Thinking, Declarative Practice
Kevlin Henney
 
PDF
Python Functions (PyAtl Beginners Night)
Rick Copeland
 
PDF
Functions in python
Ilian Iliev
 
PPTX
Python
Sameeksha Verma
 
PDF
Introduction to python
Marian Marinov
 
PPTX
Python programing
hamzagame
 
ODP
Python quickstart for programmers: Python Kung Fu
climatewarrior
 
Ruby Refinements: the Worst Feature You Ever Loved
paoloperrotta
 
Declarative Thinking, Declarative Practice
Kevlin Henney
 
Python Functions (PyAtl Beginners Night)
Rick Copeland
 
Functions in python
Ilian Iliev
 
Introduction to python
Marian Marinov
 
Python programing
hamzagame
 
Python quickstart for programmers: Python Kung Fu
climatewarrior
 

What's hot (16)

PDF
Coding Guidelines - Crafting Clean Code
Ganesh Samarthyam
 
KEY
Ruby on rails presentation
Synbioz
 
PPTX
Python Programming Essentials - M16 - Control Flow Statements and Loops
P3 InfoTech Solutions Pvt. Ltd.
 
PPTX
Rust Intro
Arthur Gavkaluk
 
PDF
The Error of Our Ways
Kevlin Henney
 
PPT
Refactoring
nkaluva
 
PDF
Lucio Floretta - TensorFlow and Deep Learning without a PhD - Codemotion Mila...
Codemotion
 
PDF
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Codemotion
 
PDF
Fog City Ruby - Triple Equals Black Magic with speaker notes
Brandon Weaver
 
PPTX
Python data structures
Harry Potter
 
PPT
Unit vii wp ppt
Bhavsingh Maloth
 
PDF
Ruby Topic Maps Tutorial (2007-10-10)
Benjamin Bock
 
PDF
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Mario Fusco
 
PPTX
R Debugging
Nilesh Borade
 
PPTX
Python basics
NexThoughts Technologies
 
PDF
Python Modules, Packages and Libraries
Venugopalavarma Raja
 
Coding Guidelines - Crafting Clean Code
Ganesh Samarthyam
 
Ruby on rails presentation
Synbioz
 
Python Programming Essentials - M16 - Control Flow Statements and Loops
P3 InfoTech Solutions Pvt. Ltd.
 
Rust Intro
Arthur Gavkaluk
 
The Error of Our Ways
Kevlin Henney
 
Refactoring
nkaluva
 
Lucio Floretta - TensorFlow and Deep Learning without a PhD - Codemotion Mila...
Codemotion
 
Davide Cerbo - Kotlin: forse è la volta buona - Codemotion Milan 2017
Codemotion
 
Fog City Ruby - Triple Equals Black Magic with speaker notes
Brandon Weaver
 
Python data structures
Harry Potter
 
Unit vii wp ppt
Bhavsingh Maloth
 
Ruby Topic Maps Tutorial (2007-10-10)
Benjamin Bock
 
Laziness, trampolines, monoids and other functional amenities: this is not yo...
Mario Fusco
 
R Debugging
Nilesh Borade
 
Python Modules, Packages and Libraries
Venugopalavarma Raja
 
Ad

Similar to The Revenge of method_missing() (20)

PDF
Metaprogramming 101
Nando Vieira
 
PDF
A limited guide to intermediate and advanced Ruby
Vysakh Sreenivasan
 
PDF
Ruby Intro {spection}
Christian KAKESA
 
KEY
Desarrollando aplicaciones web en minutos
Edgar Suarez
 
PPTX
Professional-grade software design
Brian Fenton
 
PDF
Postobjektové programovanie v Ruby
Jano Suchal
 
KEY
Can't Miss Features of PHP 5.3 and 5.4
Jeff Carouth
 
PDF
Monads in Ruby - Victor Zagorodny
Ruby Meditation
 
PDF
Functional Programming with Groovy
Arturo Herrero
 
PDF
Damn Fine CoffeeScript
niklal
 
KEY
Tres Gemas De Ruby
Leonardo Soto
 
KEY
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
PPTX
Intro to ruby
Heather Campbell
 
PDF
Java VS Python
Simone Federici
 
KEY
Dsl
phoet
 
PDF
The Great Scala Makeover
Garth Gilmour
 
PDF
PHP Technical Questions
Pankaj Jha
 
ODP
Introduction to Scala
Lorenzo Dematté
 
PPTX
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
PDF
Ruby basic3
Ho Yin Liu
 
Metaprogramming 101
Nando Vieira
 
A limited guide to intermediate and advanced Ruby
Vysakh Sreenivasan
 
Ruby Intro {spection}
Christian KAKESA
 
Desarrollando aplicaciones web en minutos
Edgar Suarez
 
Professional-grade software design
Brian Fenton
 
Postobjektové programovanie v Ruby
Jano Suchal
 
Can't Miss Features of PHP 5.3 and 5.4
Jeff Carouth
 
Monads in Ruby - Victor Zagorodny
Ruby Meditation
 
Functional Programming with Groovy
Arturo Herrero
 
Damn Fine CoffeeScript
niklal
 
Tres Gemas De Ruby
Leonardo Soto
 
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
Intro to ruby
Heather Campbell
 
Java VS Python
Simone Federici
 
Dsl
phoet
 
The Great Scala Makeover
Garth Gilmour
 
PHP Technical Questions
Pankaj Jha
 
Introduction to Scala
Lorenzo Dematté
 
Groovy puzzlers по русски с Joker 2014
Baruch Sadogursky
 
Ruby basic3
Ho Yin Liu
 
Ad

Recently uploaded (20)

PDF
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
PDF
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
PPTX
Agile Chennai 18-19 July 2025 Ideathon | AI Powered Microfinance Literacy Gui...
AgileNetwork
 
PDF
Unlocking the Future- AI Agents Meet Oracle Database 23ai - AIOUG Yatra 2025.pdf
Sandesh Rao
 
PDF
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
PDF
GDG Cloud Munich - Intro - Luiz Carneiro - #BuildWithAI - July - Abdel.pdf
Luiz Carneiro
 
PDF
Brief History of Internet - Early Days of Internet
sutharharshit158
 
PPTX
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
PDF
Accelerating Oracle Database 23ai Troubleshooting with Oracle AHF Fleet Insig...
Sandesh Rao
 
PDF
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
PDF
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
PDF
AI-Cloud-Business-Management-Platforms-The-Key-to-Efficiency-Growth.pdf
Artjoker Software Development Company
 
PDF
The Future of Artificial Intelligence (AI)
Mukul
 
PDF
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
PDF
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
PPTX
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
PDF
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PDF
Software Development Methodologies in 2025
KodekX
 
PDF
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
Agile Chennai 18-19 July 2025 Ideathon | AI Powered Microfinance Literacy Gui...
AgileNetwork
 
Unlocking the Future- AI Agents Meet Oracle Database 23ai - AIOUG Yatra 2025.pdf
Sandesh Rao
 
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
GDG Cloud Munich - Intro - Luiz Carneiro - #BuildWithAI - July - Abdel.pdf
Luiz Carneiro
 
Brief History of Internet - Early Days of Internet
sutharharshit158
 
Applied-Statistics-Mastering-Data-Driven-Decisions.pptx
parmaryashparmaryash
 
Accelerating Oracle Database 23ai Troubleshooting with Oracle AHF Fleet Insig...
Sandesh Rao
 
OFFOFFBOX™ – A New Era for African Film | Startup Presentation
ambaicciwalkerbrian
 
The Future of Mobile Is Context-Aware—Are You Ready?
iProgrammer Solutions Private Limited
 
AI-Cloud-Business-Management-Platforms-The-Key-to-Efficiency-Growth.pdf
Artjoker Software Development Company
 
The Future of Artificial Intelligence (AI)
Mukul
 
CIFDAQ's Market Wrap : Bears Back in Control?
CIFDAQ
 
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
New ThousandEyes Product Innovations: Cisco Live June 2025
ThousandEyes
 
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
Software Development Methodologies in 2025
KodekX
 
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 

The Revenge of method_missing()

  • 1. The revenge of method_missing() Paolo “Nusco” Perrotta
  • 2. Should I use method_missing() to remove duplication from my code, or should I avoid it like the plague? Paolo “Nusco” Perrotta
  • 6. class NilClass # ... def method_missing(method, *args, &block) if klass = METHOD_CLASS_MAP[method] raise_nil_warning_for klass, method, caller else super end end end
  • 8. class InfoDesk def flights # ... end def trains # ... end def hotels # ... end # ... end
  • 9. class Sign def initialize @desk = InfoDesk.new end def flights return “Out for lunch” if Clock.lunch_time? @desk.flights end def trains return “Out for lunch” if Clock.lunch_time? @desk.local_transports end def hotels return “Out for lunch” if Clock.lunch_time? @desk.local_transports end # ... end
  • 12. class Sign def initialize @desk = InfoDesk.new end def method_missing(name, *args) return “Out for lunch” if Clock.lunch_time? @desk.send(name, *args) end end # At 12:30... Sign.new.flights # => “Out for lunch”
  • 14. class Sign def initialize @desk = InfoDesk.new end InfoDesk.public_instance_methods.each do |m| define_method(m) do return “Out for lunch” if Clock.lunch_time? @desk.send(m) end end end
  • 15. Ghost Methods vs. Dynamic Methods
  • 16. the four pitfalls of method_missing()
  • 17. class Sign def initialize @desk = InfoDesk.new end def method_missing(name, *args) return “Out for lunch” if Clock.lunch_time? @desk.send(name, *args) end end
  • 18. we have a problem
  • 19. class Sign def initialize @desk = InfoDesk.new end def is_it_lunch_time_yet? Clock.lunch_time? end def method_missing(name, *args) return “Out for lunch” if is_it_lunchtime_yet? @desk.send(name, *args) end end # At 12:30... Sign.new.flights # => ?
  • 20. class Sign def initialize @desk = InfoDesk.new end def is_it_lunch_time_yet? Clock.lunch_time? end def method_missing(name, *args) return “Out for lunch” if is_it_lunchtime_yet? @desk.send(name, *args) end end # At 12:30... Sign.new.flights # => ?
  • 21. class Sign def initialize @desk = InfoDesk.new end def is_it_lunch_time_yet? Clock.lunch_time? end def method_missing(name, *args) return “Out for lunch” if is_it_lunchtime_yet? @desk.send(name, *args) end end # At 12:30... Sign.new.flights # => SystemStackError: stack level too deep
  • 22. the first pitfall: the Ghost House
  • 23. class Sign def initialize @desk = InfoDesk.new end def method_missing(name, *args) return super unless @desk.respond_to? name return “Out for lunch” if Clock.lunch_time? @desk.send(name, *args) end end
  • 24. we have a problem
  • 26. the second pitfall: the Liar Object
  • 27. class Sign def initialize @desk = ::InfoDesk.new end def method_missing(name, *args) return super unless @desk.respond_to? name return “Out for lunch” if Clock.lunch_time? @desk.send(name, *args) end def respond_to?(method) @desk.respond_to?(method) || super end end Sign.new.respond_to? :flights # => true
  • 28. we have a problem
  • 29. class InfoDesk def flights # ... end def local_transports # ... end # ... def display # ... end end
  • 30. Sign.new.display # => #<Sign:0x000001008451b0>
  • 33. the third pitfall: the Fake Ghost
  • 34. class Sign instance_methods.each do |m| undef_method m unless m.to_s =~ /^__|object_id/ end def initialize @desk = InfoDesk.new end def method_missing(name, *args) return super unless @desk.respond_to? name return "Out for lunch" if Clock.lunch_time? @desk.send(name, *args) end def respond_to?(method) @desk.respond_to? method || super end end Sign.new.display # => InfoDesk#display() called
  • 35. class Sign < BasicObject def initialize @desk = ::InfoDesk.new end def method_missing(name, *args) return super unless @desk.respond_to? name return “Out for lunch” if ::Clock.lunch_time? @desk.send(name, *args) end def respond_to?(method) @desk.respond_to? method || super end end Sign.new.display # => InfoDesk#display() called
  • 36. we have a problem (this is getting old already)
  • 38. the fourth pitfall: the Snail Ghost
  • 39. class Sign < BasicObject def initialize @desk = ::InfoDesk.new end def method_missing(name, *args) return super unless @desk.respond_to? name singleton_class.send :define_method, name do return “Out for lunch” if ::Clock.lunch_time? @desk.send name end send name end def respond_to?(method) @desk.respond_to? method || super end end # At 12:30... Sign.new.flights # => ?
  • 40. class Sign < BasicObject def initialize @desk = ::InfoDesk.new end def method_missing(name, *args) return super unless @desk.respond_to? name singleton_class.send :define_method, name do return “Out for lunch” if ::Clock.lunch_time? @desk.send name end send name end def respond_to?(method) @desk.respond_to? method || super end end # At 12:30... Sign.new.flights # => SystemStackError: stack level too deep
  • 41. class Sign < BasicObject def initialize @desk = ::InfoDesk.new end def method_missing(name, *args) return super unless @desk.respond_to? name singleton_class.send :define_method, name do return “Out for lunch” if ::Clock.lunch_time? @desk.send name end send name end def respond_to?(method) @desk.respond_to? method || super end end # At 12:30... Sign.new.flights # => SystemStackError: stack level too deep
  • 44. should I use method_missing() to remove duplication in my code?
  • 45. not if you can use define_method() instead
  • 46. just a rule of thumb
  • 47. remember the four pitfalls: the Ghost House the Liar Object the Fake Ghost the Snail Ghost

Editor's Notes

  • #2: aka...\n
  • #3: I&amp;#x2019;m assuming you know what m_m() is, but I&amp;#x2019;m also going to show a basic example\n
  • #4: - question at RubyKaigi\n- blog post on RubyLearning\n- disclaimer: this is about using method_missing() even when there are alternate techniques\n- there are cases where there is no alternative\n
  • #5: \n
  • #6: \n
  • #7: (accessors, writing a DSL - think hard before you do this!)\nnot just for cutesy\n
  • #8: example: whiny nils\n
  • #9: \n
  • #10: \n
  • #11: \n
  • #12: \n
  • #13: \n
  • #14: \n
  • #15: ghost methods\n
  • #16: \n
  • #17: ghost methods\n
  • #18: my own experiment\n
  • #19: back to our original solution\nlet&amp;#x2019;s do some refactoring\n
  • #20: \n
  • #21: \n
  • #22: \n
  • #23: \n
  • #24: - any method you can call is a ghost\n - fix: always select the methods you&apos;re using\n\n\n
  • #25: - fix: always remember to call super\n\n
  • #26: \n
  • #27: \n
  • #28: no respond_to?\n(also, breaks the IDE and searches)\n\n
  • #29: - fix: always implement respond_to?)\n- limitations of fix (methods(), etc)\n\n
  • #30: \n
  • #31: \n
  • #32: \n
  • #33: \n
  • #34: \n
  • #35: - fix: inherit from a Blank Slate\n\n
  • #36: the &amp;#x201C;scary&amp;#x201D; solution\nwhich methods should I remove exactly?\n
  • #37: \n
  • #38: \n
  • #39: \n
  • #40: \n
  • #41: - fix: (Reincarnation) lazily define methods with define_method() in method_missing()\n\n\n
  • #42: ...but it doesn&amp;#x2019;t work!\n
  • #43: why it breaks\nwhat a mess! the experiment is over...\n
  • #44: talking to jake scruggs\n
  • #45: \n
  • #46: \n
  • #47: \n
  • #48: \n
  • #49: \n
  • #50: \n
  • #51: \n