julia
julia copied to clipboard
Abbreviate `show(io, ::Module)`
For cases like
module A
module B end
end
, A is already visible in Main once defined. As a consequence, B can be accessed through A.B without having to go through Main. This adjusts the printing of A.B, so that this is reflected.
This also makes cases like
module A
export B
module B
f() = "foo"
end
end
have f printed like B.f and not A.B.f after using A, since B is also already accessible in Main.
Failures are real - one consequence of this PR is that e.g. Base.Iterators is truthfully printed as just Iterators, similar for Threads, because the name is exported:
julia> Base.isexported(Base, :Iterators)
true
julia> Base.isexported(Base, :Threads)
true
It's long been convention though to prefix these with Base everywhere :thinking: Should I change the docstrings or exclude these manually?
Imo, this should just not be done (and instead we should strive the other direction). Having things printed differently depending on the local context of where it is printed has caused many issues (https://github.com/JuliaLang/julia/pull/42329).
Also ref https://github.com/JuliaLang/julia/pull/29466
My usecase is consistency of show with what users can type/have access to; in the REPL this is Main, in other places it would of course be that module. I have types defined in a submodule like so:
module A
export B
module B
struct C end
end
end
Users aren't generally expected to need C directly, the default pattern of access is through B.C. Currently, this prints in the REPL as Main.A.B.C (or A.B.C if the module is obtained through a package and not defined in Main) though, which is superfluous (and quite bloaty if A is something longer). Since C is not generally used in A though, I can't just set a module context through an IOContext; there is no chain that ends up printing this as B.C:
julia> using .A
julia> println(IOContext(stdout, :module => Main), B.C())
Main.A.B.C()
julia> println(IOContext(stdout, :module => A), B.C())
Main.A.B.C()
julia> println(IOContext(stdout, :module => B), B.C())
C()
julia> println(IOContext(stdout, :module => Base), B.C())
Main.A.B.C()
julia> versioninfo()
Julia Version 1.11.0-alpha2
Commit 9dfd28ab751 (2024-03-18 20:35 UTC)
Build Info:
Official https://julialang.org/ release
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: 24 × AMD Ryzen 9 7900X 12-Core Processor
WORD_SIZE: 64
LLVM: libLLVM-16.0.6 (ORCJIT, znver4)
Threads: 1 default, 0 interactive, 1 GC (on 24 virtual cores)
Environment:
JULIA_PKG_USE_CLI_GIT = true
Ideally, these would be (per module context) printed as
Main->B.C()(since we have direct access toBinMain)A->B.C()(since we have direct access toBinA)B->C()(since we have direct access toCinB)Base->Main.A.B.C()(since we have no direct access and need to go through the implicit globalMainmodule)
but as you note, that runs into trouble with too much location specific printing. Personally, I'd prefer to print things globally the same, in a way that they are as short as possible while still being copy-pastable. That's what this PR attempts.
Would it be better if this checks isvisible(module_name, parentmodule(m), active_module()) instead of Main?
I've adjusted the code to first try to retrieve a given context module from the given IO, falling back to active_module(). I think this is the best option here.
Failures are real - seems like I missed some earlier! I'll get to them tomorrow.