Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] context of a function Re:(6)

From: brian:hawley:bigfoot at: 23-Aug-2000 13:21

Galt Barber <[galtbarber--MailAndNews--com]> 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