DO vs. IMPORT and "Console-Extending Applications"

During the module reworking, I roughly embraced the R3-Alpha distinction made in the header between two categories:


Rebol [Type: Script ...]  ; first category
  • You would run these "Scripts" with DO

  • Performing a DO could have side effects, but should be isolated...not allowed to leak changes into the caller's environment

    • This was a new rule I imposed as a default (because "Isolate" was made more economical, and I wanted to see how much we could get away with)

Rebol [Type: Module ...]  ; second category
  • An "ideal" module would not have any "side-effects"...because the concept was that no matter how many times you run IMPORT you will only get one copy of that module in memory.

    • Notably, if you run an IMPORT on a module that has already been loaded before...that will not run any code in the module body...it will just give you the MODULE! object that it already made.

We probably shouldn't be surprised that there are things that don't fit neatly into these categories!


"Console-Extending Applications"

So these add some functions to your environment, but also tend to have some side effects. Like:

  • @gchiu's chess program - It wants to display a board, show you some help, and add various chess-related behaviors to the console. But to add those commands which "contaminate" the calling environment, you have to say import. On the other hand, by displaying a board and showing help, it sort of violates that "no side-effects" rule.

    • He is working on another prescription-generating application that lets you automate a pop-up window that works in a similar way.
  • The ReplPad interactivity test - This test adds OKAY and NOPE to the vocabulary... where it's actually the typing of those words that runs commands which advance the console through steps in some way and instructs you on what to look for.

    • If you don't use IMPORT, you don't get the commands added as commands to the context...

    • ...but if you DO use IMPORT, you can only run through the test once... because doing it again will not load the code that prints out the instructions and launches it...

Should DO allow you to EXPORT ?

The nice thing about the word DO is it sounds pretty unambiguous, that you want to run something that has side effects.

But I do like the default of not leaking into the enclosing environment.

It seems like allowing scripts to export symbols could be a lazy compromise...which would let you ask to run something (vs. just bringing in a cached copy if previously loaded).

Yet this raises the question of what sort of behavior you'd expect from something that extends the console if you DO it multiple times.

There's also some things to think about regarding how modules will only load once, with respect to debugging. If you have a complex multi-module project running and want to tweak something--reload it and retry without losing your current interpreter state, that's rather complicated semantically.

We might also consider the idea that there's a new script type. Something like Rebol [Type: Commands ...] for lack of a better name. Maybe this would by default give you a new console session separate from the one you were in?

Much more work is needed on binding and modules, to try and figure out how to deliver a good experience. So hopefully if I don't die in a tornado here in Tennessee, I will work on that soon. :slight_smile:

I'm visiting this topic as I am contemplating modules vs. scripts and more practically, why IMPORT and DO (or DO*) are in SYS-LOAD and SYS-BASE respectively. There seems to be a lot of crossover between IMPORT and DO* and having them defined in different sources precludes sharing common code.

A part of my interest is in the distinction that when you DO a module in Rebol 3, it will update SYSTEM/SCRIPT, whereas when you IMPORT a module, it does not. The implication of this is that when importing a module (including from the NEEDS header which I am in favour of), you don't have any way to access the Module's header or location.

Further, if you DO a module twice, the module is IMPORTed on the first run, but then DO evaluates the code again on the second go (where IMPORT checks to see if it is now in the list of imported modules). This breaks my conception of what a module should be, which, I'd say is muddied by all the various goals and distinctions of scripts and modules.

I'd have assumed that SYS-LOAD would be concerned with the transformation from text/binary to values and that IMPORT is superfluous to this end. Perhaps the implication of having IMPORT in there is connected with the idea it's impossible to LOAD a module without running IMPORT on its needs. I'm not so sure about this.

Scripts vs. Modules vs. Unnamed Modules

In BrianH's epic StackOverflow answer on Words in Modules, he describes the various distinctions between Module types and the distinction between Scripts: paraphrasing—scripts are like modules, but all scripts share the same word space, system/contexts/user. Ok, this seems fine. He also describes Unnamed Modules as not being trackable, and thus suitable for code that is run for effect but in a private word space. That would be consistent with DO running it multiple times, but inconsistent with IMPORT.

I think this gets me to the same conclusion as you:

I think this could all be codified. Modules load once and must be indexed (preferably by URL instead of name), and a Script should have an option to have its own word space (even if the mechanism for doing so is MODULE!).

Additional takes include: Modules should not automatically export to LIB (which is #2115); need functional type headers.

Caveat: I realize I might be out of date in the ways Ren-C diverges from Rebol 3 when it comes to this stuff, however I notice the SYS-LOAD/IMPORT, SYS-BASE/DO* delineation still exists.

1 Like