this post was submitted on 28 Mar 2024
236 points (94.4% liked)
Rust
6140 readers
45 users here now
Welcome to the Rust community! This is a place to discuss about the Rust programming language.
Wormhole
Credits
- The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)
founded 2 years ago
MODERATORS
you are viewing a single comment's thread
view the rest of the comments
view the rest of the comments
You can go to definition / find references / rename for dynamically typed languages too.
E.g. https://github.com/palantir/python-language-server
Without static type annotations you can only make best effort guesses that are sometimes right. Better than nothing but not remotely the same as actual static types. The LSP you linked works best when you use static type annotations.
Also I would really recommend Pylance over that if you can - it's much better but is also closed source unfortunately.
Why would it just be best effort? To find references for a specific thing, it still would parse an AST, find the current scope, see it's imported from some module, find other imports of the module, etc.
Where is the definition of x? What is the type of x? If you can't identify it, neither can the LSP.
This kind of thing actually happens when implementing interfaces, inheritance, etc. Thus, LSPs in dynamic languages are best effort both theoretically and in practice.
Types are not necessary at all.
Saying "x is defined somewhere in the entire program" isn't satisfactory to many users. Also, you didn't tell me what type x has. Can I do
x + 5
?It absolutely does. Without static types an IDE/LSP can't reliably find all the references / definition and therefore can't refactor reliably either.
Consider something like this:
Now imagine you want to rename
Foo.bar
or find all references to it. Impossible without the type annotations.Ah, I see. You're talking about object properties. I don't see any issue with finding references to variables, but for properties, yeah.
Tbf this example can be deducted as
string | int
just fine.The real problem is when you start using runtime reflection, like
getattr(obj, "x")
It breaks down when you do runtime reflection, like
getattr(obj, "x")
.Ok imagine you are a LSP. What type is
x
? Isprize
a typo? What auto-complete options would you return forx.
?I didn't say types. I said find references / go to definition / rename.
How are you going to find references to
prize
, go to its definition or rename it without knowing what typex
is? It's impossible without static types.