Galt Barber <[EMAIL PROTECTED]> wrote:
>Brian, /local revelation!  Thanks!
>
>So, you really can see that when invoked,
>/local is normally set to none, and
>all "optional switch params" following it,
>up to the next /switch if any, are set to none also.
>
>Somehow I never realized that MULTIPLE parameters
>can follow a /switch in the function definition
>so I thought that /local was doing something special
>allowing multiples, and that it had to come last.

Pretty cool, huh?

>So, you could use any [parma parmb /local x /morefrickinlocals s t u]
>and s t u are locals that are just every bit as good as /local,
>and it doesn't even matter if /local is the last switch, right?
>The only limit is that all real params have to come
>before the first /switch.

All of this only matters to the help function. Any
parameters or switches to your function that are
after the /local switch are left undocumented by the
help function. If you want undocumented switches,
this is the way to do it.

Keep in mind that the source function shows all of
your parameters and code, so "undocumented" is a
little relative here.

>What did this save RT?  Did they get to avoid having
>to use 'use inside the function to create a separate
>context frame with the locals local?  Since they
>had to support the /switches anyway and they had
>a mechanism for that, why not bag the extra 'use
>and stick the locals as "unused" switch parms?
>was their thinking, I suppose.

As I recall (anybody correct me here), there didn't
used to be any special treatment of /local at all.
All of the formal parameters, both refinements and
words, can be used as local variables.

I guess that people didn't realize this so they asked
for local variables. Some genius at RT (there are a
lot of them) figured out that undocumented local vars
would do as well, and hacked the help function.

As for functions' use of contexts, all contexts are
the same underneath. The only difference is in how
the contexts are treated underneath and the lifespan.
By lifespan, I mean during what part of the execution
process the words in that context are valid. Any time
outside of that lifespan, it's best to program as if
that context no longer exists and you could crash the
interpreter if you refer to it (mostly true).

Here's a quick comparison of the different contexts.
Words in a context are not initially set to a value,
but some users of contexts do some initialization.
Of course all of this is subject to change later by
RT, particularly when modules are introduced.

Global (system/words):
- Created: When REBOL starts?
- Lifespan: Duration of interpreter session.
- Strangeness: Only context that words can be added to
   after it has been created. Otherwise, like Object.

Use function:
- Created: When the function use is called.
- Lifespan: For the duration of that function call.

Object! :
- Created: When the object! is created.
- Lifespan: For as long as the object! is referenced.
- Initialization: Code block initializes object words
   at creation time.
- Strangeness: Always has self word, can be based on
   prototype of other object (_not_ inheritance).

Function! :
- Created: Conceptually at start of function call. For
   real behavior, see Strangeness.
- Lifespan: Conceptually until end of function call.
   For real behavior, see Strangeness.
- Initialization: Formal parameters (the words of the
   context) are set to either the values of the actual
   parameters, or to none! if none. Missing parameters
   at the end are left unset.
- Strangeness: Conceptually the context of a function!
   should be treated as if it had the duration of a use
   context - you shouldn't try to treat the words of
   the function! as variables after the function is done
   executing, unless you bind them to a valid context.

   In practice REBOL caches a single context for each
   function to cut down on context creation and rebinding
   overhead, making REBOL _much_ faster. However, this
   context is reused with every function call and treated
   as a stack frame during recursive calls, making use of
   the context outside of the function generally a bad
   idea. It is a particularly bad idea for those of us
   who are used to the languages Lisp or Scheme because
   REBOL doesn't close those variables (a Lisp term). The
   actual behavior of REBOL will be close enough to Scheme
   to make it very difficult to see where the bugs are,
   and won't generate a helpful error message to tell you
   what you did wrong.

   Because of these caveats, it's best to translate your
   closure-based code into objects until you know what to
   avoid doing. Any code that makes you wish that the IN
   function was defined for functions should be rewritten,
   probably to use objects or modules instead. When you
   really need closures, close the values yourself with
   compose or something. If you need static data, use a
   literal series embedded in the source code. Above all,
   treat function! contexts as if they are only valid as
   long as use contexts.

>The one change they had to make to accept this is
>that /local unused switch params (local vars) are
>set to none like any other unused switch parms
>(since /local itself is not usually invoked).

They didn't need to make any changes to the creation or
evaluation of functions at all. Functions are simpler
than most think they are. All they changed was help.

>This is kind of amusing:
>
> >> g: func [][probe local ]
> >> g
>** Script Error: local has no value.
>** Where: probe local
>
> >> g: function [][][probe local ]
> >> g
>none
>== none
> >>

Yup! :)

Brian Hawley

Reply via email to