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.

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.

@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.

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.

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