6 ms·
It's painful to see method_missing called out as a first class solution in the first creature https://www.exceptionalcreatures.com/bestiary/NoMethodError.html#6
by stevebmark 3y ago
It's painful to see method_missing called out as a first class solution in the first creature https://www.exceptionalcreatures.com/bestiary/NoMethodError.html#6-a-method-to-find-missing-methods https://www.exceptionalcreatures.com/bestiary/NoMethodError.... . "Practical Ruby" has three chapters dedicated to method_missing. "define_method" is more common these days and also painful to see.
Ruby gets a lot of criticism for embracing magic and indirection ("Ruby, the bad parts of Perl"). It has some good parts (no function colors, for example), but the ecosystem is the biggest problem by promoting magic. method_missing is not a good part of Ruby, it's a very bad part that you should only use if you know it's bad _and_ you know you still have to use it. I wish all tutorials would say this. "You can do this with Ruby, but don't, because your coworkers debugging an outage for an hour will hate you once they find out the bug is caused by method_missing".
- p_l 3y agomethod_missing is a tiny offense compared to what was getting popular at one point - creating classes by forking metaclass and injecting methods into... without knowing you're doing so (something IIRC got lost between people there...) Result was objects that shared no structure, no field
- pantulis 3y agoDo you mean the class << self pattern?
- matheusmoreira 3y agoThat's what I thought as well. If someone's opening metaclasses to define singleton methods they probably know all about the Ruby object model. I don't see how it could be done "without knowing you're doing so".
- p_l 3y agoThe people who did it first did understand the meta model. Unfortunately some people started following without full understanding. I wasn't at forefront of things back then, so I only noticed when the people who did know better started to writing about abuse of this technique.
- deleted 3y ago[deleted]
- nf3 3y agoThe page you linked to discusses NoMethodError, which is raised when a method is not found. Among other things it shows how method_missing is involved in searching for a method. Nowhere in the text is it promoted.
- RangerScience 3y agoRespectfully mostly disagree. Ruby is full of sharp knives. Other languages have dull knives. Writing code without thinking will cut you either way. Things like method missing are exactly the right solution for a certain set of problems. If used thoughtfully, they’re amazing. If used thoughtlessly, bloody mess. But this is true in every language.
- busterarm 3y agoIf you want to be wowed by how incredible method_missing and define_method are, read through ActiveSupport and ActiveRecord's source code. Early in my career I made my own toy ActiveRecord implementation and it's full of define_method and was literally the first time in my life that programming felt like a real superpower.
- Groxx 3y agoWhere other languages have footguns, I've often described Ruby as offering footchainsaws, while tempting you to juggle them for fun. Far more damaging if you aim it at the wrong thing, but also far better at cutting down things that stand in your way. I think it's the most enjoyable language I've used. With care and feeding it's amazing. I would absolutely not want to use it in a large company, that would be a walking nightmare.
- vlz 3y agoYes, I want to highlight what you say about large companies. ruby really shines, I think, if you are a solo dev or a small team, where everybody is on the same page and the codebase is completely understood. It is also good for libraries with a clear focus. For larger projects, it might work too, but you would need some good culture of "keep it simple" around it. A few ego-trips of supposedly smart devs and things can get hard to understand and hard to work with fast.
- cutler 3y agoHere we go again with the Ruby isn't suitable for large projects nonsense. Github, Shopify and Stripe seem to be managing perfectly fine with Ruby, thank you very much.
- AlchemistCamp 3y agoI definitely prefer Clojure/Elixir-style macros to Ruby’s meta-programming features. They’re still better than nothing, though. Method-mossing and friends played a critical role in making a framework like Rails possible in Ruby. In contrast, languages like Python and JavaScript just aren’t quite expressive enough to do it. A lot of energy went into attempts over the years, too! At best, something like Sails could get 2/3 off the way there and offer significant advantages on another axis, like making websockets first class.
- Lutger 3y agopython has `__getattr__` (and a lot of other dunder magic), what is still missing? With named arguments and (kw)args, there is even more ergonomic magic I think. And django's orm also has similar magical abilities as activerecord. I think a lot of the metaprogramming abilities Python has are just used less often than in Ruby. Not because it is less expressive, but because it has a culture of simplicity whereas brevity and generality are more valued in Ruby (Rails) culture.
- AlchemistCamp 3y agoWhat Django doesn’t have and will never have is router or testing DSLs that are similarly ergonomic as Rails’s. https://stackoverflow.com/questions/7079855/are-there-technical-reasons-a-ruby-dsl-like-rspec-couldnt-be-rewritten-in-pytho https://stackoverflow.com/questions/7079855/are-there-techni...
- empthought 3y agoAnd thank goodness for that. It is impossible to reason about types in such monstrosities.
- AlchemistCamp 3y agoIf when looking at the pile of regexes which is Django’s router, your thought is “good, this way I can reason about types!”, then Ruby is definitely not the language for you.
- deleted 3y ago[deleted]
- deleted 3y ago[deleted]
- groggo 3y agoOne rule I try to go by, and I feel like this should be a pretty moderate take but isn't actually that commonly stated: If we're talking about Rails at least, then meta-programming/magic/indirection, all that should be very rare in application code. It makes sense sometimes in more abstract libraries, where you have to handle flexible problems, but in application code it's really worthwhile to just be straightforward and verbose.
- seattle_spring 3y agoEvery Rails app I’ve ever been introduced to had layers upon layers of “before_filter” and “after_filter”, deeply nested into 6+ subclasses of stuff. Whether or not this “should” or “should not” be in application code is beside the reality that it absolutely is all over application code. Makes it a fucking nightmare to debug.
- groggo 3y agoOh yeah, I guess it's better to limit the use of that. But I actually don't count using those as metaprogramming. It's just part of the framework, and you have to know about those features. Rails has a lot of magic and I think a lot of it is annoying and unnecessary. Using those features is one thing, but defining your own is too far imo, unless you're making a library.
- vidarh 3y agoRails, to me as someone who loves Ruby and use it for "everything" (including my editor, terminal, window manager), is a poster-child for poorly written Ruby. It creates code bases that seems to have a tendency to turn into sprawling messes. I appreciate that it has driven a lot of people to Ruby, and in that way it's an amazing and impressive success, but recruiters get it somewhat right for the wrong reason when they sometimes list Rails as a "language". I'm very happy to use "magic" in Ruby, but it should be high-impact, low code, and contained. E.g. I'm very comfortable with the "magic" in my window manager that turns event classes received from the X11 binding into method call on a target class, so that MotionNotify turns into target.on_motion_notify(event) without me having to specify every event class. It's simple, small, and let me cut a lot of code. A lot of non-Rubyists would hate it, though. The irony, though, about your complaint is that Rails code is some of the most verbose Ruby code you'll find, because it's geared at making cookie cutter creation of sites easy, and so a lot of patterns involve an excessive separation into vast amounts of low-impact, verbose classes that do way too little (the obsession with some Rails devs of writing "service classes" for things that should just have been a single method, for example, drives me crazy - yes there are valid uses of service classes, no almost no uses of them in Rails apps are reasonable)
- matheusmoreira 3y agoYou keep saying method_missing is "bad" but what exactly is so bad about it? The main complaint about method_missing has always been the inefficiency. The class hierarchy is walked every single time and only then is method_missing called. The use of define_method is a pretty neat solution to that problem. The method that wasn't found gets defined and it doesn't rely on method_missing again. Like a cache.
- nomilk 3y agoThe docs are just explaining how method resolution order works in ruby (i.e. explaining method_missing but not saying you should rush out and use it). Personally, I've never used method_missing. Might have missed opportunities to write clever code, but I'm super happy being boring and explicit. Tangentially, I've only used meta programming twice. Both where the alternative was cumbersome, and it was unlikely to cause confusion. Ruby gives some exotic tools but doesn't force you to use them if you prefer not to.
- vidarh 3y agoIn every language without method_missing or equivalent, people end up writing custom dispatch based on message values sooner or later, sometimes re-implementing full method dispatch, and occasionally a full inheritance mechanism in the process. If the set of messages you need to handle dynamically is to only ever be small, define_method() is the better choice, but when it is not, I'll take careful use of method_missing over some monstrosity that ends up emulating the same machinery with lots of extra code any day. If you struggle with debugging due to method_missing, consider reviewing how you debug code, as it wouldn't even make my top ten of debugging challenges in the Ruby code I've worked on in the last 17 years of daily Ruby use.
- sabellito 3y agoI have no idea what you're talking about in your first paragraph. I've put code in production in half a dozen languages, and ruby is, by a immense marging, the biggest offender on this. The only thing that comes close would be AOP in Java, that is bad but at least it's compile time magic with decent IDE support. All the most heinous bugs I've had to deal with in my life were about magic in ruby. I've worked in 3 of the biggest rails codebases in the world, and in the end we had build checks to deny code with magic. Software code should be optmised for reading and debugging, not looking nice for first time writes.
- vidarh 3y agoPretty much any switch/case or multipronged if is dispatch in disguise. Sometimes the switch/case/if is the right choice, sometimes it's making the code more convoluted. Once you step up a degree in complexity, you get e.g. lookup tables and class hierarchies to emulate more dynamic dispatch. Complex dispatch is all over the place in most large systems. Ruby is "an offender" in this to you because you hate the pattern that untangles the huge unholy mess that less dynamic languages use instead. E.g. hacky workarounds like whole class hierarchies or (marginally better) maps from values you dispatch on to first order functions/closures I have worked in over a dozen languages, and I've never seen a medium to large sized project where some form of dispatch mechanism hasn't been part of the codebase somewhere. And I'll take the simplicity of dynamic dispatch over hand rolling verbose mappings any day. > All the most heinous bugs I've had to deal with in my life were about magic in ruby. I've worked in 3 of the biggest rails codebases in the world, and in the end we had build checks to deny code with magic. I have no like for Rails, it encourages a lot of awful shit, but I also find this really curious, because the backtraces will clearly indicate you've passed through method_missing, you can breakpoint requests and attach remote debuggers to in flight requests, and execute code in-context in those requests. If that's too complex, sure, maybe a large Rails code base isn't right for you. I don't want to work on Rails codebases either, but because of Rails, not Ruby, nor because the dynamism makes it any harder to debug. > Software code should be optmised for reading and debugging, not looking nice for first time writes. I agree,and it's exactly why I love Ruby.
- tpm 3y agoThese days (years) I work mostly in Java and would love to have method_missing or define_method. Of course I can do everything I want without them, but it's not fun.
- erik_seaberg 3y agoGroovy has monkey patching and methodMissing (and propertyMissing) but runtime lookups make them slower than dispatch to classloader-defined methods.
- cutler 3y agoKotlin would be a good Java-compatible alternative with its extension functions.
- ljm 3y agoIt's not really any different to, say, lisp (which is lauded for its intuitive support of macros) and smalltalk (which is what ruby was directly influenced by). As a dynamic language, Ruby gives you a lot of tools to create fully expressive code. This is just one aspect of it that you can, but don't have to, use.
- postmodern_mod3 3y ago"but the ecosystem is the biggest problem by promoting magic." This argument isn't entirely true anymore. The Ruby ecosystem has mostly moved away from meta-programming, and embraced classical OOP. Rubyists now tend to avoid `method_missing` and `const_missing` when possible, and abandoned the craze of making everything a DSL. The most meta-programming that Rubyists still use on a regular basis is defining `self.included` on modules in order to inject other modules. Also, Rubyists have embraced API documentation, such as YARD, in order to document and communicate any "magic" that might exist or occur.