Hacker News new | ask | show | jobs
by dmitriid 3099 days ago
> Sure, these depended upon injecting new methods into core classes, but who cares?

I, as a developer reading your code 6 months later, care.

When something fails, it's nearly impossible which of the magic methods were injected by which magic library.

4 comments

Not really. It's hard for your editor to do this statically, but there's heaps of good tooling for finding the method source and docs dynamically.

  pry> show-source SomeClass.class_method
  pry> show-source AnotherClass#instance_method
  # List an arbitrary object's class methods, instance methods, methods mixed in by included modules
  pry> cd some_object
  pry> ls
The runtime knows how to execute your program (it's not random) so everything you want to know is available.
Been doing Ruby full-time for 3+ years, bunch of experience before that.

    there's heaps of good tooling for finding the 
    method source and docs dynamically
I know, but this is a huge problem with a lot of code I see in the wild because this stuff is (ab)used so widely in Ruby-land.

If I have to run code just to see where `Foo.bar` is defined, that makes things... about an order of magnitude harder to understand. I mean, that's really tough thing to do in anything but a trivial codebase.

This is nearly 100% the fault of developers, not the language itself, but I would suspect that most Ruby developers spend a significant amount of time dealing with things like this because it's how the ecosystem rolls.

You realise you just validated my point, right? :)
I'm not sure you did.

People who don't use Ruby seem to think this is a huge thing that you run into constantly. It's not. People are for the most part pretty responsible with these things.

It’s very far from impossible. It is trivial to programmatically determine where a method was defined using Method#source_location.

Determining which method responds to which message is only possible in an instantiated runtime, but that’s true for any late-binding programming environment. Complaining about it tells us more about the complainer than about the language.

Rust's way of doing this is nice. It allows you to extend core types (e.g. add methods to integers), but in order to use the added methods you import the trait that adds them in the file you want to use them in (so you can always have a good idea of where they've come from)
It's almost as if you didn't even bother reading the sentence immediately following.

If you're writing a library doing things like this is a bad idea (except in very limited circumstances). And to what seems to be every non-Rubyist's surprise, virtually no libraries in practice actually do this sort of thing so there are never problems in practice.

The times I do this sort of thing in my own application code, I put the methods in a module and have a hook that raises an exception if the methods already exist when the module is included. This is the best of both worlds: I can add features that don't exist, but am informed immediately when my app launches if such a method has already been defined.