Scope of Included Files

Ok, this helps a lot. There’s definitely a bunch going on here, so let’s take it piece by piece.

  1. It is true that Julia does not emphasize the __name__ == "__main__" approach that’s so common in Python, but large Python codebase also don’t always get written with the assumption each file can be executed in isolation. So setting aside the cultural tradition of “code duality” in Python, it’s useful to keep in mind that Julia’s cultural tradition of using include does mean that code is often written with the assumption that both (a) the sources of identifiers may be quasi-implicit (via include) and (b) the enclosing context may be implicit rather than strictly determined by the filesystem directory structure. But neither of these are big challenges for IDE’s, which can trivially scan and index thousands of files to do binding analysis.

  2. Regarding “how does the IDE know AbstractFoo in file2.jl is a valid identifier”, the truth is that it’s not a valid identifier except in the broader context. But usually you’d edit a Julia codebase starting from a directory where this context is present and the IDE could easily index it: for example, starting in the main directory for the GitHub repo for Optim.jl. The current Julia VSCode toolchain doesn’t seem to do as much indexing as it could, but there’s no deep reason that’s substantially harder than handling Python code – it’s just an ecosystem gap that exists today.

  3. It seems like you’re used to languages with very mature IDE tooling, but it’s actually worth learning more foundational techniques than “hover my cursor over” X since you’ll likely hit up against limitations of IDE’s many more times in your life with many different languages and/or situations. Instead of assuming the IDE does all binding analysis for you, it’s quite easy to find the definitions of bindings from purely syntactic considerations – just look for abstract type AbstractFoo. It’s always possible that such syntactic approaches will fail, but that’s an issue with Python too and really with any dynamic language in which bindings can get created at runtime in ways that require running something close to the full program to understand.

  4. For your specific example, it’s a great test of a purely syntactic search. The first thing I did was to search for function value!, which produced two results that didn’t seem correct. So I then did a regex-based search for import .* value!, which immediately shows exactly one result: import NLSolversBase: value, value!, ...

In summary, you are hitting up on maturity gaps in Julia’s VSCode integration, but they’re also gaps that the approaches you’d need in most environments will easily solve.

3 Likes