Introducing the Concept of a Current Module
Let me just say this outright: my Modules document is not very good. Sorry, but it's just not very clear. It is quite old, and as soon as I get a better doc written, I promise I will delete that old one.
So, to make it clear: Modules provide a way to extend the REBOL
environment. That's their purpose.
Of course, that statement is not indended to mean that everything about modules is simple. It is not. But, to understand and to use modules must be simple. Anyone and everyone should be able to do it. (Otherwise, I would not be doing it, right? You know me.)
So, this means a few things:
1. You need to be able to create a module just as simply as
loading a script that looks like:
REBOL [title: "My module" type: module]
...
and alternately you can use this method at any time in your code:
my-mod: make module! [
[title: "My module"]
a: 10
func1: func [...] [...]
]
Note: that means you can create multiple modules within a single script, if that's what you need to do.
2. You should be able to access the exported values of a module
easily. How easily? Well... automatically.
For instance, if your module is:
REBOL [title: "My Math" type: module export: [buy sell]]
...
buy: func [value price] [...]
sell: func [value price] [...]
then later, you run a script that does this:
buy "google" $200
sell "microsoft" $10
It should work as you would expect. It must be just that easy.
3. There are many extra options that are the other 20%. Yes, they
are useful, but most of the time you don't care.
Now, that's where it gets a bit more complicated. Let me give you a good
example:
Let's say a section of code runs an external script using the do
function. To what module do the words of that script get bound? This
is a non-trivial question. I mention it go get you thinking. Deeply,
I hope.
Why does it matter? Here's why: if you are using a function of a REBOL
module (call it Mod-A) that looks like:
do-it: func [file] [
...
do file
...
]
are the variables of the newly evaluated file bound to Mod-A or are they
bound to the module that called do-it in the first place?
Over the years, I've found that when these questions come up, there
is some kind of implicit action taking place. There is an assumption
going on. In this case it is what module do the new words get bound
to? We have two choices:
- The module where the do was evaluated.
- The original module where the do-it was evaluated.
In low-power static languages like C and most others, this would be an easy
choice. But, in the dynamic evaluation of REBOL, it's not quite as easy
to decide. Both choices are valid.
Like in other areas or REBOL, the better design choice must come
from some kind of common sense rule. Let it be this:
- It is best to avoid the accidental auto-expansion of
modules.
Such results would be problematic because arbitrary new functions
could be added to any of the existing standard modules of the
system. That wouldn't be a good thing.
Therefore, according to this rule, the do above would bind new
words to the current active module. So there is the implicit
action: the concept of a current module.
When your user script gets evaluated, REBOL will launch it within
its own unique "user module". And, when any additional scripts are
loaded and evaluated, by default they are bound to the same user
module unless they are explicitly directed elsewhere.
Now, what if you want a section of code to refer to an explicit
module? What if you do a load or a do and you want a specific
module to be affected? That's the purpose of the with function:
Just as you can say:
with object [... expressions ...]
Here object is any valid object, and the block is evaluated within the context of an object, you can also say:
with module [... expressions ...]
Where module is any existing module. This line specifies that the expressions are bound to the context of a given module.
You can even write:
with module [do %script.r]
to force the module to accommodate the new script's bindings.
In addition, to help make this action easier, you can also use any
word with a context to provide the context itself. That way you
don't have to figure out how to obtain the reference to the context.
For example:
with 'word [do %script.r]
where word is bound within the target context.
I think those of you who are expert REBOLers see that with is
more than just another name for bind. A hidden variable is
being set that indicates the module, the "current environment" for
the block. And, there are some deeper implications that go along
with it (such as what happens when an error occurs that throws us
out of the with block.)
So, there you are. Simplicity with just a pinch of spice to
create the very best of flavor. Now, if only I could cook everything
that well.
Please post your comments. I am open to your ideas. Thanks.
18 Comments
|