I am thinking about the best way to get continual feedback with more detailed type hints in VSCode. Similar to how it is done with rust-analyzer.
Background
For those who haven’t used Rust, here’s what the feedback loop looks like when you are coding:
I really want to have the same thing in Julia. I want the IDE to immediately highlight type instability while I am writing the function, rather than me needing to debug it later. Type instability should be automatically apparent with an ugly warning by my IDE.
Now, since Julia is very dynamic, this is obviously a bit trickier. Right now we can get something similar to Rust, via connect an external REPL, and running Cthulhu descend on a function (thanks to @Zentrik and @pfitzseb’s work on this with @tim.holy’s Cthulhu). This looks like the following:
which I can set up with:
- Launch REPL in my Julia project
- VSCode → Command Palette → Connect External REPL, and paste into REPL
- Load my package as well as Cthulhu
- Instantiate an example input
- Call
@descend rand(tree)
and descend once to enter the function shown in the screenshot. - Types are now displayed on this function in VSCode.
This is awesome but I am wondering if we can do even better. I want type information to automatically show up while I am typing out the function, so I can immediately and effortlessly be alerted to type instability, rather than needing to manually descend to find it (which is still not convenient enough to run on all functions; I have to only descend on functions that show up on profiler results)
Proposal
Here’s one idea that I want opinions on. Could we have a special comment that tells Julia LSP to run Cthulhu (or simply @code_warntype
) for the function with a given example input?
For example:
function foo(x)
out = []
for xi in x
push!(out, xi)
end
push!(out, "bar")
out
end
#! descend: ([1, 2, 3],)
This “descend” would tell the Julia language server to continually run Cthulhu.descend(foo, ([1, 2, 3],))
whenever the code is changed. (Or just @code_warntype
, but I feel like multiple levels could be useful)
The descend could also be more complex to allow different input types. For example,
foo(s, x) = do_something(s) + x
#=! descend:
using MyPkg
(MyPkg.MyStruct(), "foobar")
=#
I think the comments are the right place to put this kind of information, because this is where you control linters and formatters. And it also nicely slots into the developer experience, so I don’t have to also set up some script that runs such things (which discourages me from doing so) – I can just do it right in the same script with almost zero effort.
Other ideas:
- Maybe there can also be some way to specify the module context, with the top-level
Main
being the default. - In the future I think you could also specify multiple
descend
. In VSCode I believe there is the ability to cycle between code warnings for a given function (?) which would let you quickly switch between seeing the warnings for different example inputs. The key point is that you want these to show up immediately while writing the code, rather than sometime after. - One issue with this scheme is that beginners, the most likely victims of type instability, might not know about this. Rust is nice in this way because it requires zero configuration other than installing
rust-analyzer
. But I’m not sure what other option we have unless the beginner was to specify explicit types in the signature. Maybe the auto-complete template for a function call could generate this or something.
Interested in other ideas on this. Basically I am trying to figure out how to make Julia’s dev experience offer as much feedback as Rust even with its extra dynamicism.
Edits:
- Changed syntax to use
#! descend:
rather than just# descend:
- Added block version with
#=! descend: