List of use´d or import'ed modules in a Julia session

Hi there

I would like to understand a little bit more about the answer to the question implied on the title of this topic of mine, as per the following question from StackOverflow: List of loaded/imported packages in Julia. The answer by Przemislaw Szufel seems the best one for me:

filter((x) -> typeof(eval(x)) <: Module && x ≠ :Main, names(Main,imported=true))

but I do not understand clearly the need for the eval function inside the typeof function in the conditional to the filter function. Could someone explain it from first principles? I have looked up the help for eval to no avail…

names returns a list of symbols, eval(name) “evaluates” the symbol into the object it represents in the current Julia session. typeof(eval(x)) <: Module checks whether or not that object is a module.

You also have access to the Dict

ulia> Base.loaded_modules
Dict{Base.PkgId, Module} with 194 entries:
  OpenSSL_jll [458c3c95-2e84-50aa-8efc-19380b2a3a95]                  => OpenSSL_jll
  Xorg_xcb_util_jll [2def613f-5ad1-5310-b15b-b15d46f528f5]            => Xorg_xcb_util_jll
  libass_jll [0ac62f75-1d6f-5e53-bd7c-93b484bb37c0]                   => libass_jll
  Qt5Base_jll [ea2cea3b-5b76-57ae-a6ef-0a8af62496e1]                  => Qt5Base_jll
  Xorg_xcb_util_image_jll [12413925-8142-5f55-bb0e-6d7ca50bb09b]      => Xorg_xcb_util_image_jll
  Libgcrypt_jll [d4300ac3-e22c-5743-9152-c294e39db1e4]                => Libgcrypt_jll
  SnoopPrecompile [66db9d55-30c0-4569-8b51-7e840670fc0c]              => SnoopPrecompile
.
.
.

which is an explicit list of loaded modules. These will in general include modules that are not available in Main.

2 Likes

In this case you can replace eval(x) with the conceptually much simpler getfield(Main, x). So no, there’s no need for eval here.

5 Likes

@baggepinnen, showall(Base.loaded_modules) returns 174 items, including crazy things like FriBidi_jll, while the @pszufe’s user function loadedModules() returns 16 explicitly loaded packages, as expected.

Any further insights on this difference?

Base.loaded_modules includes all dependencies of imported packages.

1 Like

I still do not get the need for eval: I tried

x =names(Main, imported=true)

and then

eval(x)

and they both seem to have the exact same output, of type Vector{Symbol}. So why does the call

filter((x) -> typeof(x) <: Module && x ≠ :Main, names(Main,imported=true))

provide an empty Symbol, whereas the original one by @pszufe does what was wanted?

The original filter code in the OP iterates over a vector of symbols and evals each of them. Each type is then a Module, not a Symbol.

Base.loaded_modules appears to include all modules that are loaded, even if they are loaded indirectly (not explicitly by the user). This includes jll packages that contain pre-compiled and packaged binaries.

1 Like

I noticed that, but why does eval(:Base) for instance returns Base (which happens to be of type Module, no longer Symbol)? I was not able to get this crystal clear from eval’s function help, though I do see, via the REPL, it is what it does. I guess I really do not get what eval does…

It evaluates the symbol in global scope, and it will return its object, or an error if undefined:

x = 2
:x + 2                 # Error, cannot add Symbol and Int
eval(:x) + 2           # 4
Symbol(:x, 0)          # :x0
eval(Symbol(:x,0))     # Error x0 not defined