Open krader1961 opened 4 years ago
Is this essentially proposing a way to import all symbols from another module directly into the current namespace - like Python's import * from foo.bar
, or Go's import . "foo/bar"
?
Is this essentially proposing a way to import all symbols from another module directly into the current namespace ...
Yes, conceptually it is similar; although the Python and Go equivalent didn't occur to me since $dayjob outlaws those import forms. Which I why I said "I appreciate that the above proposal runs counter to best practices." So I'm not wed to that proposal but would like to have some way to split an ungainly script (such as ~/.elvish/rc.elv) into smaller files. I've already done that with the statements that manipulate the $E:
namespace since I can put those in a module named ~/.elvish/lib/env.lib and use env
.
Also, resolving this might make it possible to eliminate $-exports-
-- depending on the specifics of how this is resolved. For example, I want the utility functions, such as ff
(find files), that I place in my ~/.elvish/lib/util.elv module to be usable in an interactive shell without the util:
namespace prefix while still being able to use them in non-interactive scripts. I do this today by doing the following after use util
in my rc.elv:
-exports- = [
&coff~=$util:coff~
&con~=$util:con~
&ff~=$util:ff~
&gitfiles~=$util:gitfiles~
&nx~=$util:nx~
]
Related to my previous comment see also issue #1116 which illustrates why being able to import the public identifiers in a module into the current namespace is useful.
So far the use case seems to be restricted to splitting rc.elv
, which, assuming #1138 and #668 are implemented, can be done like this:
keys $local: | each [key]{ edit:add-var $key $local:[key] }
If this is a bit wordy, as part of #1138 we can add a utility edit:import-ns
, and make this just edit:import-ns $local:
.
Is there a compelling use case that is not about splitting rc.elv
, i.e. about splitting a library namespace into multiple files?
Is there a compelling use case that is not about splitting rc.elv, i.e. about splitting a library namespace into multiple files?
In theory, yes. The obvious analog is how Go uses the package
statement to allow splitting a package implementation across multiple files. I've only recently started writing standalone programs in Elvish; i.e., Elvish code not primarily meant to be used interactively. Those have been small enough that splitting them into multiple files hasn't been needed but I can certainly envision a time when I've written a program in Elvish that would benefit from being able to split into multiple files.
I dislike huge interactive shell init scripts; whether that's ~/.bashrc or ~/.elvish/rc.elv. So I typically break the initialization up into smaller modules. That, however, is problematic in Elvish because every
use
statement creates a new namespace. So if I douse ./prompt
from inside my ~/.elvish/rc.elv the former does not have access to the vars defined in the latter, and vice-versa. In the past I would have used the experimental-source
command but that no longer exists. It would be extremely useful if it was possible touse
a module in manner that utilized the current namespace; e.g.,use &same-namespace ./prompt
.I appreciate that the above proposal runs counter to best practices. Specifically, it is generally recommended that importing should always do so in a distinct namespace independent of the current namespace. Too, I can workaround the lack of this feature by separating the
use
(import) from the initialization the module performs such that the initialization requires an explicit invocation of a command in the module. But that is a bit of a PITA for this common use case.Of course this is applicable to any module that might live in ~/.elvish/lib/. So another solution is to introduce something analogous to Go's
package
statement. That would require exposing the interactive (REPL) namespace so that it can be used as an explicit namespace; e.g.,package _repl
at the top of my ~/.elvish/prompt.elv module.