In general it's impossible to "find usages" or "go to definition" when the language not only fails to equip IDEs and tooling with the static typing information that would grant definitive answers to such questions; but even goes further and allows methods to be redefined or even synthesized and defined, for the first time, at runtime, with no corresponding source location or file. Method lookup and dispatch are fully Turing complete (you can `#send` anything, including fully dynamic method names, and respond to any message with arbitrary logic in `#method_missing`), and you can even redraw the method lookup chain and inheritance hierarchies at runtime (includes, mixins, module prepend, eigenclasses et al).

This is not a failing of JetBrains tooling but rather a pervasive language smell and consequence of Ruby philosophy.

It is infrequent that "find usages" and "go to definition" don't work for me on good sized ruby code bases. Both solargraph and ruby-lsp seem to work fine for me. Occasionally, I'm surprised when they don't work. In my recent mileage, that happens once every couple weeks, and I use find references and go to definition multiple time per-hour.

Metaprogramming has fallen out of fashion in the ruby community for the most part. Rails is a great example of where that shift has happened. ActiveRecord used to have `find_by_<attr-name>(<value>)`, which became `find_by(<attr-name>, <value>)`. Sure devs can still go wild with metaprogramming in ruby, but it is generally discouraged.

They work well enough to a first approximation, but it's far from the certainty one has using other JetBrains products (e.g. C# ReSharper) on a statically typed codebase.

RubyMine will give you "Untyped (potential) usage." That's not good enough if I need to make a breaking API change and be sure that I've fixed all the callsites, such that I don't find out that I've missed a spot when the change breaks in production.

For all this talk about LLMs and AI improving developer productivity - what is one click and a few seconds in ReSharper to "Change Signature" or "Pull Members Up," which is a 100% guaranteed safe refactoring that will not introduce regressions, ends up being anywhere from "a few hours" of playing whack-a-mole with usage sites, to "completely intractable" in 15+ year old 1MLOC+ codebases making heavy use of metaprogramming.

If the Ruby milieu has turned against metaprogramming, I say good riddance; but my understanding is that it is still quite deep in technologies like Rails and RSpec in particular, where it's the fundamental secret sauce that enables convention-over-configuration and fluent, natural-language like DSLs.

Of course it takes some heuristic to jump to the definition of these common Rails idioms

  belongs_to :customer # class Customer
  after_save :do_something # method
  validate :custom_validation # method
or a Ruby send(:method, arg)

But an IDE specialized in Ruby can do it. No idea if RubyMine does it.

Bonus for handling

  send("method_#{var}".to_sym, arg)
In general it can only present a menu of choices: all the methods with a name starting with "method_"

"Find usages" and "Go to definition" work very well in RubyMine in my experience, at least in normal Rails projects - I use them all the time with command-click.

Anecdata that something is effective in 98% of cases is different from provable static verification that works 100% of the time.

> In general it's impossible to "find usages" or "go to definition"

> Anecdata that something is effective in 98% of cases is different from provable static verification that works 100% of the time.

Ruby has its faults. But you're not making sense complaining first about the "in general" situation, then complaining about a 2% situation. And it is a 2% situation, I'll add my anecdata as verifying 98% (or better) it works really well.

Secondly, you're mixing concepts of static typing and metaprogramming by saying "the language not only fails to equip IDEs and tooling with the static typing information that would grant definitive answers to such questions." Static typing is not the solution, or at least not the only solution, to metaprogramming concepts. For example, if I statically define a Ruby object via RBS, I may still do the things you list that are problematic.

Thirdly, you're complaining about runtime issues making things difficult for the IDE while doing a lookup. What language and IDE do you prefer that does this so much better?

Lastly, I doubt this will help but just to make you aware there are specific rules about how this stuff works, for example https://ruby-doc.org/3.4.1/syntax/calling_methods_rdoc.html#...

> But you're not making sense complaining first about the "in general" situation, then complaining about a 2% situation.

The use of "in general" has long established usage in mathematics to refer to properties that hold for all objects in a given collection [0] [1]. Thus, if 2% of those objects fail to satisfy these properties, you cannot say that such properties hold "in general."

> Secondly, you're mixing concepts of static typing and metaprogramming by saying "the language not only fails to equip IDEs and tooling with the static typing information that would grant definitive answers to such questions." Static typing is not the solution, or at least not the only solution, to metaprogramming concepts.

Propose alternate solutions then.

IDEs and tooling (let's leave LLMs and other stochastic methods aside for now) can only inspect the lexical, syntactic, and semantic (types) structure of source code in order to navigate and validate it. Thus, information that is absent from the lexical, syntactic, and semantic structure of the source code, is unavailable to the IDE and static tooling. Ruby, being a dynamically typed language, does not statically encode any structure regarding types, callgraphs/callsites/usages, definitions, or otherwise, in the syntax of the language alone. The behavior of a Ruby program - how its methods are defined, where they are defined, and which runtime objects invoke send what messages to whatever recipients, are only discoverable at runtime, because nobody bothered to put this information in at compile/typecheck time. You cannot discern information that simply is not there.

> For example, if I statically define a Ruby object via RBS, I may still do the things you list that are problematic.

Yes, and this is because RBS is not actually a sound typesystem [2] [3]. You can declare whatever fake types and interfaces you want in RBS; there is absolutely nothing stopping me from simply using `#define_method` to overwrite your implementation, destroying your static guarantees, or using other runtime metaprogramming facilities to delete your method, change its signature, or otherwise violate whatever other invariants you assumed you had when you wrote the static headers/type declarations and had them checked by the static verifier.

It doesn't matter if you statically verify the code, when the language offers innumerable opportunities to destroy those static guarantees, after they were established, at runtime.

> Thirdly, you're complaining about runtime issues making things difficult for the IDE while doing a lookup. What language and IDE do you prefer that does this so much better?

I already provided an example of C# ReSharper upthread [4]. C# actually provides the static typing information that the tooling requires in order to navigate the AST with deductive certainty, not loose approximations or heuristics as in RubyMine.

Out of curiosity, did you study computer science formally at a post-secondary institution, or did you learn from a bootcamp?

[0] https://en.wikipedia.org/wiki/Glossary_of_mathematical_jargo...

[1] https://en.wikipedia.org/wiki/Glossary_of_mathematical_jargo...

[2] https://en.wikipedia.org/wiki/Type_safety

[3] https://www.typescriptlang.org/play/typescript/language/soun...

[4] https://news.ycombinator.com/item?id=45105283

I didn't read your comment -- I'm sure it was insightful and well researched.

The fact that it ended with an elitist ad hominem attack tells me enough.

Just paying it forward. As a visible minority in Canada, I am subjected to this kind of passive aggressive, plausibly deniable ad hominem on a regular basis - and often by the very same Canadian white progressives who claim to have been educated out of such bigotry and racism. When in Rome...

[deleted]

SLIME is a better approach for dynamic languages, IMO. Interrogating the actual runtime is more effective than trying to do static analysis.

In a Turing complete dynamic language I believe that some properties of the runtime would be undecidable. The advantage of static typing is that many (most?) type systems are sufficiently constrained (i.e. not Turing complete) such that the typecheck procedure can be assured to terminate.

Of course, with sufficiently expressive type systems you end up with Haskell "UndecidableInstances" or Coq dependent types or C++ compile-time tetris, [0] and now you are back to the same problem as with analyzing the runtime. Otherwise you may find it difficult to encode the desired properties or invariants into your type system, for lack of expressive power... tradeoffs abound, and so on.

[0] https://news.ycombinator.com/item?id=9813800

Or my favorite alternative to that story: well, it's currently a str ... maybe it'll still be a str in 5 minutes, who knows

In a dynamic language where code that produces such a side effect is admitted by the (lack of) compiler/typechecker, sure; however a static checker would probably ensure, before runtime, that said binding indeed refers to a str, now and forever.

But I realize now the point of ancestor's comment is that you don't have such a guarantee in a dynamic language - hence the tendency to lean more on REPL-oriented development, highly interactive live runtime environments, tight TDD feedback loops, etc...

[deleted]