Is there a way to export ALL the symbols declared in a module? Just to avoid writing them all under export
.
No. You typically don’t want to do this.
I am just following this tip:
https://docs.julialang.org/en/stable/manual/workflow-tips/
which I find very useful. However since I am constantly changing the package, it is very inconvenient to track exported variables. So I think this is a use-case for exportall. Why is it so dangerous? I think it could be useful in certain scenarios.
I would prefix the module name before the functions you are using when developing (or do something like const m = MyPackage
and use m.f()
.
For improved workflow, I would look at https://github.com/timholy/Revise.jl
What is the advantage of that, versus exportall
? I am just trying to see the downside of having exportall
as a feature.
Global namespace is global.
Julz has a function for exporting all vars (that were included using the package)
Maybe you can do something like this:
https://github.com/djsegal/Julz.jl/blob/master/src/macros/export_all_files.jl
A practice which I like but I see others employ only rarely is putting export
statements immediately following definitions like so
f(x::AbstractFloat) = # do some stuff
function f(x::Complex{<:AbstractFloat})
# do some other stuff
end
export f
I agree that creating an exportall
keyword would be asking for trouble.
Can you explain this code a bit? It seems to be exporting all files, not symbols of a module.
That does seem good for readability while the code is being written, but I wonder if it will become more difficult for other people (or a future you) to understand what the code does. Looking at a list of exports is one of the ways that I typically start to understand a new package.
I think I might try this style on my next project and see how it works…
I haven’t particularly found reading the export lists useful without a good handle on what the functions actually do. Sometimes having argument types is enough for this, but the names alone usually aren’t (for me at least).
Granted, it does make it easy to lose track of which functions are being exported.
Yea, I felt like exportall was a little dodgy (so I scoped it on files for Julz).
I believe the following code does exactly what you want
// at least it did in v0.5
https://github.com/djsegal/julz_legacy/blob/master/app/templates/config/export_all_except.jl
The following simple snippet seems to work:
module Foo
foo(x) = x+1
bar(x) = x-1
# exportall:
for n in names(current_module(), true)
if Base.isidentifier(n) && n ∉ (Symbol(current_module()), :eval)
@eval export $n
end
end
end
@stevengj Sometimes I have a module spread over multiple files. Is there a way to specialize this to only export symbols defined in the current file?
Here’s a version of the export-all code chunk from @stevengj that is updated for Julia v1.0. (Well, for v1.4 at least. I haven’t tested on v1.0).
# export all
for n in names(@__MODULE__; all=true)
if Base.isidentifier(n) && n ∉ (Symbol(@__MODULE__), :eval, :include)
@eval export $n
end
end
When I’m developing a new package, I find it pretty convenient to just export all the functions in the package. Later when the code stabilizes I can choose which functions to export, but initially I’m usually the only user of my package and it’s easier just to export everything.
Here’s the new code in action:
julia> module Foo
x = 1
y = 2
for n in names(@__MODULE__; all=true)
if Base.isidentifier(n) && n ∉ (Symbol(@__MODULE__), :eval, :include)
@eval export $n
end
end
end
Main.Foo
julia> using .Foo
julia> x
1
julia> y
2
@CameronBieganek Thanks for posting. Adding export all
to my toolbox.
I wrote my own convenient macros for this, one exports all names and one follows all sub-modules recursively. Only tested under 1.7.1
Usage:
module MyModule
# code here
end
@make_public MyModule
# or, if you want to follow sub-modules recursively:
@make_public_rec MyModule
Code:
#
# Copyright 2021 Clemens Cords
# Created on 26.12.2021 by clem (mail@clemens-cords.com)
#
"""
export all non-temporary, non-imported values (values not having a '#' at the
start of it's symbol when listed via Base.names) in a module
Example:
module MyModule
module SubModule
_sub_variable
end
_variable
end
@make_public MyModule
# exports:
# MyModule
# MyModule.SubModule
# MyModule._variable
See also: @make_public_rec
"""
macro make_public(module_name::Symbol)
eval(Meta.parse("export " * string(module_name)))
as_module = eval(module_name)
@assert as_module isa Module
for name in names(as_module; all = true)
if (string(name)[1] != '#')
#println("export " * string(name))
as_module.eval(Meta.parse("export " * string(name)))
end
end
return nothing
end
export make_public
"""
export all non-temporary, non-imported values (values not having a '#' at the
start of it's symbol when listed via Base.names) in a module and all
such values in any submodule, recursively
Example:
module MyModule
module SubModule
_sub_variable
end
_variable
end
@make_public_rec MyModule
# exports:
# MyModule
# MyModule.SubModule
# MyModule.SubModule._sub_variable
# MyModule._variable
See also: @make_public
"""
macro make_public_rec(module_name::Symbol)
function make_public_aux(child_name::Symbol, super::Module) ::Nothing
if (string(child_name)[1] != '#')
#println("export " * string(child_name))
super.eval(Meta.parse("export " * string(child_name)))
end
child = super.eval(child_name)
if (child isa Module && child != super)
for name in names(child; all = true)
make_public_aux(name, child)
end
end
return nothing
end
origin = eval(module_name)
@assert origin isa Module
for name in names(origin; all = true)
make_public_aux(name, origin)
end
return nothing
end
export make_public_rec
It will be part of jlwrap which I am the author of and can be used freely with attribution under GNU license
I think that a good in-between would be the ability to write something like
export function myfn()
# ...
end
This way you would be explicit about exported function, but you don’t have to review the code every so often to export whatever you wrote: you just put export
in front of every function you write and you’re sure is going to be exported.
Attaching export
to method definitions is not a good idea, I think. Export cares about functions, not methods (i.e. you cannot export a subset of methods of a given function; it’s all or none).
Makes sense