The non-existence of tools that you find in other languages might signal an immature ecosystem, but it might also signal a diminished need for them.
The non-existence of tools that you find in other languages might signal an immature ecosystem, but it might also signal a diminished need for them.
Given Ruby's open classes and per-object metaclasses (which are still open), I'm pretty sure a general solution to "find the definition of the method being called at this point in the code" is impossible (and not just, "there is a single correct answer, no general solution is available" impossible, but "there is no guarantee that there is a single correct answer, and even for the subset of cases where there is, no general solution is available" possible.)
But, OTOH, I am aware that its possible to do good-enough-for-many-uses implementations of things for which a complete, general solution is impossible, including the function described.
http://devblog.avdi.org/2015/05/11/in-which-i-make-you-hate-...
But finding the set of likely candidates is not that hard.
There are some pathological code-bases that dynamically defines lots of methods, but they are not that common.
On the flip side, the limitations of ruby forces its devs to adjust the way they write code. Knowing that I may need to use ⌘-shift-f (find in project) to look up method definitions changes some of my conventions, and because operations like refactor-rename (which I use all the time in C#) are very tedious, it forces me to think a bit harder up front when designing a class's API surface.
I'm not arguing that it's better than having good tooling -- just that the lack of tooling adds some interesting constraints that, in some ways, force us to write simpler code.
So it might be another issue with Rails' influence over Ruby: not many chances to move beyond the fence (me too.)
No, IDEs were pioneered (and if you checkout Pharo you'll see they are still pushing the boundaries) by dynamic languages that allow runtime refleciton. Like smalltalk.
As for your other statement I also disagree:
> I'm not arguing that it's better than having good tooling -- just that the lack of tooling adds some interesting constraints that, in some ways, force us to write simpler code.
What lack of tooling (and introspection in general) deprive us from is from forming a clear picture of what is going on, perspective. To illustrate my point I'll quote a Ken Pitman's annecdote:
> Last night on my Lisp Machine I was frustrated by the absence of NT file support. I had no idea how file support was implemented, but I had a general working understanding of how the Lisp Machine was organized, and within a small number of hours I had learned about how to extend the operating system to talk to NT over TCP and implemented a new set of classes so that I could transparently talk to my NT box over my local ethernet. A lot of my ability to do this was enabled by the ability to point and click on objects in order to debug them and inspect them without any fear or confusion about whether I was using the right sources, the right packages, etc.
https://groups.google.com/forum/#!topic/comp.lang.lisp/XpvUw...
However I think this is a more nuanced point, therefore I have no interest in arguing it over the internet. I see the case for constraints resulting in simpler code.
What I objected to is using Ruby's dynamic typing as a cop-out and try to pass it as trade-off.
A better measure of sophistication is how much bang you get for the buck, and how much of this bang is made possible by the language itself.
In my opinion, the best example of this is GHCi: Using GHCi almost feels like asking the computer "Is what I'm doing right?". GHCi itself is made possible by Haskell's excellent balance between type system expressiveness and making inference feasible. To see why maximizing raw expressive power won't help, in most dependently typed languages, it's hard to construct nontrivial meaningful utterances, so you don't even get to the point where you can ask "Is what I'm doing right?" - the type checker will tell you "It isn't even wrong". That being said, I'm aware that the situation w.r.t. tooling is improving a lot.
Another example is Rust's borrow checker: It will tell you exactly at which point an equivalent C or C++ program would have had a dangling pointer. It doesn't quite have the same "fluid conversation" feel as using GHCi, but it saves the enormous amount of time that would've been otherwise spent chasing memory bugs in a debugger, especially in a concurrent program.
Ruby isn't defined by poor tools. Ruby is defined by a design that makes static analysis intractable. The lack of sophisticated tools is just a corollary.