Is there a way to test if something `isexported()`?

question

#1

Sometimes isdefined is a little too loose.

Is there a way to see if a variable is explicitly exported by a module?


Example:

# src/FizzBuzz.jl

module FizzBuzz
   export foo
   foo() = println("hello")
   bar() = println("world")
end
# Julia REPL

> isdefined(FizzBuzz, :foo)
true

> isdefined(FizzBuzz, :bar)
true

> isexported(FizzBuzz, :foo)
true

> isexported(FizzBuzz, :bar)
false

#2

Base.isexported on 0.6 ?


#3

That’s exactly what I wanted. How did you find out about that? (it’s not in the docs)


#4

Just by accident :), I assumed that they must have it to define what to bring into the Main module after using FizzBuzz, so I looked in Base and Core.

julia> isdefined(Base,:isexported)
true

julia> Base.isexported(Base,:isexported)
false

#5

Maybe this is stupid idea:

julia> [i for i in names(Base, true) if contains(string(i), "exported")]
4-element Array{Symbol,1}:
 Symbol("#is_exported_from_stdlib")
 Symbol("#isexported")             
 :is_exported_from_stdlib          
 :isexported  

But using undocumented features could be bad idea too…


#6

Here is an implementation using names which is documented:

isexported(m::Module,s::Symbol)=(s \in names(m,true)) && (s \in names(m))

(I could not get the \in tab to get the right symbol)


#7

Implementation in Base is this:

isexported(m::Module, s::Symbol) = ccall(:jl_module_exports_p, Cint, (Any, Any), m, s) != 0 

Sorry but your implementation doesn’t work. According to doc names(m) is subset of names(m, true) which makes part of your code redundant. Also exported deprecated symbols are ignored. See:

#Julia 0.7
julia> isexported(m::Module,s::Symbol)=(s ∈ names(m,true)) && (s ∈ names(m))
isexported (generic function with 1 method)

julia> isexported(Base, :zeta)
false

julia> Base.isexported(Base, :zeta)
true

#8

You are right about the names so the the two are redundant (I misunderstood names, I wanted something that almost can tell if it is defined/undefined, and then decide if it is exported).

Now, weirdly on 0.6:

julia> isexported(Base,:zeta)
true

julia> Base.isexported(Base,:zeta)
true

I don’t have 0.7 but I thought that special functions where taken out from Base in 0.7.


#9

Maybe I am wrong. I tried to simulate deprecated symbol. And zeta on 0.6 is working without deprecation message:

julia> zeta(0)
-0.5

and on 0.7 deprecation is faked up:

julia> zeta(0)
ERROR: Base.zeta has been moved to the package SpecialFunctions.jl.
Run `Pkg.add("SpecialFunctions")` to install it, restart Julia,
and then run `using SpecialFunctions` to load it.
Stacktrace:
 [1] error(::Function, ::String, ::String, ::String, ::String, ::String, ::String, ::String, ::String, ::String) at ./error.jl:42
 [2] #zeta#852(::Base.Iterators.IndexValue{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}, ::Function, ::Int64, ::Vararg{Int64,N} where N) at ./deprecated.jl:142
 [3] zeta(::Int64, ::Vararg{Int64,N} where N) at ./deprecated.jl:142
 [4] top-level scope

So I tried to find really deprecated symbol on 0.6:

julia> ipermutedims([1 2;3 4], (2,1))
┌ Warning: `ipermutedims(A::AbstractArray, p)` is deprecated, use `permutedims(A, invperm(p))` instead.
│   caller = top-level scope
└ @ Core :0
2×2 Array{Int64,2}:
 1  3
 2  4

julia> Base.isexported(Base, :ipermutedims)
true

but:

julia> :ipermutedims in names(Base)
true

So it seems I don’t understand what is doc saying:

help?> names

Get an array of the names exported by a Module, excluding deprecated names.