Names from Base appear in modules

The standard behavior is that names from Base are accessible as properties of normal modules.

julia> module Foobar end
Main.Foobar

julia> Main.Foobar.:*
* (generic function with 237 methods)

Do we like this? It seems a bit odd to me: They don’t appear in names(Main.Foobar; all=true) or propertynames(Main.Foobar), so I wouldn’t expect them to be properties. The alternative would be that the names are accessible from within Foobar but aren’t actually properties of it.

Yes, I expect to access imported names (like FooBar importing * from Base) with dot syntax. Unfortunately, names isn’t good at showing those. The imported keyword doesn’t work for implicit imports or explicit imports with using:

julia> module A
         module B
           export b, c, d
           b = 1; c = 2; d = 3
         end
         using .B
         using .B: c
         import .B: d
       end
Main.A

julia> A.b, A.c, A.d
(1, 2, 3)

julia> names(A;imported=true)
2-element Vector{Symbol}:
 :A
 :d

Ironic because explicit imports with using are now more recommended than with import so that module qualification protects against unintended method definitions on imported functions like it always protects against unintended reassignment of imported variables.

If you don’t want this behavior, you can use a baremodule

4 Likes

Could someone explain why it’s desirable? I’m not seeing the advantage currently.

For example I find it more intuitive that this would define a new function rather than extending the Base function.

julia> module Foobar end
Main.Foobar

julia> Foobar.:*(a::Symbol, b::Symbol) = Symbol(string(a,b))

julia> Foobar.:*
* (generic function with 237 methods)
1 Like

That just seems intuitive to me when imported names exist at all. If you want to make a new function particular to FooBar, it should be done in the module itself with no qualification.

julia> module Foobar end
Main.Foobar

julia> @eval Foobar (*)(a::Symbol, b::Symbol) = Symbol(string(a,b))
* (generic function with 1 method)

I would agree that it’s ideal that qualified modules are exactly the origin module, but that’s necessary for reassigning global variables at the moment and it’s a pain when modules get nested. Seems good enough just specify one imported module without going down the whole import chain.

1 Like