julia icon indicating copy to clipboard operation
julia copied to clipboard

Abbreviate `show(io, ::Module)`

Open Seelengrab opened this issue 1 year ago • 5 comments

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.

Seelengrab avatar May 03 '24 12:05 Seelengrab

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?

Seelengrab avatar May 03 '24 14:05 Seelengrab

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

KristofferC avatar May 03 '24 14:05 KristofferC

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 to B in Main)
  • A -> B.C() (since we have direct access to B in A)
  • B -> C() (since we have direct access to C in B)
  • Base -> Main.A.B.C() (since we have no direct access and need to go through the implicit global Main module)

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?

Seelengrab avatar May 03 '24 16:05 Seelengrab

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.

Seelengrab avatar May 04 '24 10:05 Seelengrab

Failures are real - seems like I missed some earlier! I'll get to them tomorrow.

Seelengrab avatar May 04 '24 20:05 Seelengrab