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

[REBOL] Re: local vars in functions

From: joel:neely:fedex at: 24-Apr-2002 7:52

Hi, Rishi, My uninformed $0.02... (Note that I try to make an alternative suggestion at the end of my discussion. I'd be interested in feedback on that idea!) The main root problem I have with your suggestion is that it seems to make an assumption about REBOL that I do not believe to be true -- that there's some sort of conventional "compile" step that preprocesses the entire text of a piece of code before generating some internal representation. For why I think this, see below. Please let me know if I have misunderstood your meaning... Rishi Oswal wrote:
> What I would like to see is another shortcut to > creating local variables in any context (function, > innerfunction, loop). The obvious way I see of doing > this is as follows: > > myfunc: func [][ > localvar:: $25 > myinnerfunc: func [][ > innerlocal:: $10 > print localvar ; prints $25 > ] > print innerlocal; error! > ] > print localvar ; error! >
Based on your description, should I infer that you would like the above to be equivalent to? myfunc: func [/local localvar myinnerfunc] [ localvar: $25 myinnerfunc: func [/local innerlocal] [ innerlocal: $10 print localvar ] print innerlocal ; error ] print localvar ; error Note that I assumed you meant for MYINNERFUNC to be local to MYFUNC even though you didn't use the double colon (because of the way you named it). Do you intend the above meaning or do you intend an alternative meaning, such as: myfunc: func [] [ use [localvar] [ localvar: $25 use [myinnerfunc] [ myinnerfunc: func [] [ use [innerlocal] [ innerlocal: $10 print localvar ] ] print innerlocal ; error ] ] ] print localvar ; error Alternately, I could pose it as two questions: 1) What context do you think should contain the double-colon variables? 1a) The context of the smallest enclosing function definition? 1b) A new context whose scope is described below? 2) How far should the scope of that context extend (lexically I mean)? 2a) From just before the double-colon expression to the end of the enclosing block? 2b) From the beginning of the enclosing block to the end of the enclosing block? 2c) Just the following expression?
> using the "::" for local var will make it more > convienient to create local vars (which i use all the > time over global vars). In addition, it will help > prevent some errors of accidental global var creation > because it is now easy to spot a local var. >
Pardon me, but I must disagree. The typographic differences among the following expressions foo: 10 bletch:: "this is a test" somelongervariablename: foo + length? bletch shortername:: somelongervariablename + 5 * (thing1: square-root 75) - (thing2:: now/time/second) lastone: shortername + 7 do *not* IMHO make the local vs. non-local names stand out all that much.
> Best of > all, this type of shortcut would not break anything in > rebol. You could even use this in a loop: > > for count 1 10 1 [ > localvar:: "hello" > ] >
Based on this example, I assume you *must* mean (1b) is the context you want, but I'm still unclear what the answer to (2) would be. I'm also not clear on what semantics you intend e.g. for the following case myfunc1: func [s [string!]] [ a:: 1 foreach char s [ a:: a + 1 if all [#"A" <= char char <= #"Z"] [ a: a + 1 ] if all [#"a" <= char char <= #"z"] [ a:: a + 1 ] if all [#"0" <= char char <= #"9"] [ a: a + 1 ] ] a ]
> Using the "::" shortcut in a global context would be > the same as using a ":". >
So "::" behaves differently depending on "context" (I assume you mean lexical setting, not REBOL "context"...) and on which time it is being evaluated??? How does it know? (See below.) That's not the same as defining e.g. print flarp:: square-root length? "Yowp!" as meaning the same as use [flarp] [ print flarp: square-root length? "Yowp!" ] Remember that LOADing an expression implicitly wraps it in a block. All of the answers to (2) above have to do with the idea of the lexically-encl0sing block. Being able to create, use, and discard "temporary" variables at the global level is quite handy!
> The disadvantage I see is that it adds another thing > to the language.. But consider that now we could stop > using the /local keyword, reduce bugs, and use it > consistently everywhere, overall it can simplify > things. >
But it's *NOT* consistent, IMHO! In the example you give for count 1 10 1 [ localvar:: "hello" ] the double-colon-word LOCALVAR does something different the first time it is evaluated compared to the subsequent time(s) it is evaluated, although I'm not at all clear what that something is. You also seem to be saying that it must be able to figure out (dynamically, remember!) which of an arbitrarily large number of possible contexts should be affected. Remember that REBOL has no idea of "current context" so in the case (combining your examples) of func1: func [n [integer!]] [ func2: func [] [ for count 1 n 1 [ localvar:: count * count ] ] ] I must again wonder what context LOCALVAR belongs in, and how the reader (interpreter or human!) should figure that out, whereas in current REBOL there are four distinct cases, each of which is clear from the text of the expressions: ;; localvar belongs in the context of func1 func1: func [n [integer!]/local localvar] [ func2: func [] [ for count 1 n 1 [ localvar: count * count ] ] ] ;; localvar belongs in the context of func2 func1: func [n [integer!]] [ func2: func [/local localvar] [ for count 1 n 1 [ localvar: count * count ] ] ] ;; localvar belongs in a context inside the FOR body func1: func [n [integer!]] [ func2: func [] [ for count 1 n 1 [ use [localvar] [ localvar: count * count ] ] ] ] ;; localvar belongs in some other context established ;; outside this text fragment func1: func [n [integer!]] [ func2: func [] [ for count 1 n 1 [ localvar: count * count ] ] ] Because of the way REBOL views words and contexts, I have real trouble figuring out the interactions of this proposed new feature with all of the mechanisms already in the language. There are already enough cases where there are subtle differences and undocumented behaviors that I really can't feel good about adding another one. Finally, in a design situation I always like to ask "What problem are we trying to solve?" In this case it appears that the primary problem is the risk of modifying the global context by forgetting to declare a word as local to some scope under construction. If that's the case, I'd like to suggest an alternative. If I understand correctly, REBOL builds contexts as required by the expressions being evaluated (e.g., FUNC, USE, FOR, MAKE OBJECT!, etc.) and refuses to extend those contexts after initial creation -- with one specific exception being the global context, which may be extended at any time. What if REBOL had a new word, e.g. GLOBAL-CONTEXT-FROZEN (and I'm quite happy for suggestions for a better name!), that controlled whether adding new words to the global context were prohibited? Then we could write things like this: global-context-frozen: true do %somescript.r global-context-frozen: false and any attempt to add a word to the global context during the evaluation of the script file would cause an error. In addition, one could "nest" such protection e.g. within a script file such as somescript.r by writing: use [temp-global-safe] [ temp-global-safe: global-context-frozen global-context-frozen: true ;; do a bunch of stuff ;; ... global-context-frozen: temp-global-safe ] thus transparently ensuring that the "bunch of stuff" is evaluated without adding globals, and then restoring the level of safety that was in place when the above fragment began. (Of course, I'm avoiding the issue of whether we would get benefit from being able to "thaw" other contexts, e.g. to be able to add attributes to an existing object... ;-) -jn- -- ; Joel Neely joeldotneelyatfedexdotcom REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] { | e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]