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

problems with local vars???

 [1/22] from: raimund::swol::de at: 16-Aug-2000 16:12


Hi, I have quite some problems with the scope of local variables. The following script does point it out: -------------------------------------- REBOL [] local-func: function [input][my-local-string][ my-local-string: "that is local " print append my-local-string input ] local-func "Call 1" local-func "Call 2" print my-local-string ------------------------------------- [raimund--linux]:~/Development/rebol/Tests > rebol test_locals.r that is local Call 1 that is local Call 1Call 2 ** Script Error: my-local-string has no value. ** Where: print my-local-string
>>
The results suggest that locals are handled like static vars in C is that correct? Why does the assignemnt to my-local-string at the start of the local-func not inititalize the local? Can anyone point me to some more info about this issue? Thanx Raimund <---------------------------------------------> 42 war schon immer einge gute Antwort;-))

 [2/22] from: bhandley:zip:au at: 16-Aug-2000 23:19


Hi Raimund, The first thing is to understand that you can use my-local-string like a variable, but it is not really a variable (in the sense of a pointer to memory). It is a word that can refer to a value. The word my-local-string exists in it's own right - so does the value of type string "that is local". Doing an "assignment" associates the two. With this in mind, Rebol does not "initialise" the variable - it actually associates a word with a value. In C and other compiled languages when you declare a variable you give the variable a datatype and when you assign something to the variable your value is just a bunch of bits that conform to the datatype. This is not the case with Rebol. In Rebol the value has the type information. A word is a value too - a special type of value that can be associated with another value. In Rebol everything is a value including functions. So local-func is a word that refers to a value of type function. Here's your function slightly edited local-func: function [input][my-local-string][ my-local-string: ; This says make it so that my-local-string refers to the next value. (1) "that is local " ; This says create a string value. (2) print append my-local-string input ; (3) ] Both (1) and (2) are part of the function definition. When (3) is actually executed, it in fact changes the value of (2). Why? because when the line is evaluated, my-local-string is evaluted before the append. My local string evaluates to the actual string stored in the function definition. You can see how the function definition has changed by calling your function once and then using the command. source local-func Now, if you function read like this... local-func2: function [input][my-local-string][ my-local-string: ; This says make it so that my-local-string refers to the next value. (4) copy "that is local " ; This says create a new string value that is a copy of another. (5) print append my-local-string input ; (6) ] What would happen in (5) is a copy would be make of the string that is stored inside the function definition and the copy would be "assigned" to the word my-local-string. In this case when line (6) is executed the string will change but the function will not because the function does not refer to the copy. Hope it helps. Brett.

 [3/22] from: joel:neely:fedex at: 16-Aug-2000 4:39


Hi, Raimund, You've encountered the First Koan of REBOL. Use of literal strings gives you the actual string, not a copy. The first phrase in your function my-local-string: "that is local " makes the local word my-local-string refer to the second element of the function's body. When you subsequently say print append my-local-string input the append is operating on the string that is the second element of the function's body. Therefore the changes persist between invocations of the function. The gotcha is that in some other languages, assigning a string to a variable does an implicit copy, whereas in REBOL, you must ask for the copy operation if you want it. Therefore, the following version of your function probably does what you expected: -------------------------------------- REBOL [] local-func: function [input][my-local-string][ my-local-string: copy "that is local " print append my-local-string input ] local-func "Call 1" local-func "Call 2" print my-local-string ------------------------------------- This is also true of blocks; if you want to construct a block within a function (with no persistence of content), you likely will want to initialize it with my-local-block: copy [] before putting stuff into it. The issue here is one of the meaning of literal values (strings, blocks, etc.) in REBOL, and is not specific to functions.
>> stuff: [blk: [] append blk more-stuff print mold stuff]
== [blk: [] append blk more-stuff print mold stuff]
>> more-stuff: "Hello, world!"
== "Hello, world!"
>> do stuff
[blk: ["Hello, world!"] append blk more-stuff print mold stuff]
>>
Here we see that, without reference to function or context issues, the literal block in the second position of stuff is modified. -jn- [raimund--swol--de] wrote:

 [4/22] from: raimund:swol at: 17-Aug-2000 10:18


Thanx to all who answered, it helped quite a lot!! Raimund -- <---------------------------------------------> 42 war schon immer einge gute Antwort;-))

 [5/22] from: joel:neely:fedex at: 17-Aug-2000 4:20


Hi, Brett! Being the nit-picky kind of guy that I am ;-) I'd like to suggest a slight change in the wording of your explanation. [bhandley--zip--com--au] wrote:
...[snip]
> Here's your function slightly edited > local-func: function [input][my-local-string][
<<quoted lines omitted: 3>>
> print append my-local-string input ; (3) > ]
I think it's slightly confusing to say in (2) that the literal string says to create a string value . Instead, I suggest that in (2) the literal string IS a string value. (If I had my geek hat on, I'd say something more complicated like "serves as a reference to the string that was created when this source code was loaded", bit I left my geek hat at home today... ;-) In many other languages, using a literal string causes a fresh string value to be created whenever the containing code is executed. In the REBOL code above, a string! value only gets created once -- when the above code is loaded. Every time the function referred to by to local-func is evaluated, my-local-string is set to refer to THE SAME STRING, rather than a newly-created one. Therefore, mutations on the value of my-local-string (e.g., append, insert, remove, replace ) are continuing to operate on the same string which ORIGINALLY (at load time) contained that is local , but which has subsequently been modified with every evaluation of the function. I don't want to sound hypercritical here! I'm really just thinking out loud about how to describe the behavior of literal series values in REBOL, as this sort of thing keeps coming up on the list. You certainly described the correct solution in the remainder of your note, but I'm wondering if making a more explicit distinction between load time and evaluation time will help us explain this. Anyone think so? -jn-

 [6/22] from: bhandley:zip:au at: 18-Aug-2000 10:09


> > Here's your function slightly edited > > > > local-func: function [input][my-local-string][ > > my-local-string: ; This says make it so that my-local-string
refers
> > to the next value. (1) > > "that is local " ; This says create a string value. (2)
<<quoted lines omitted: 7>>
> that was created when this source code was loaded", bit I left my geek > hat at home today... ;-)
Yeah, it probably is a bit confusing. I confused my contexts. I intended to to convey the sense that Rebol "does it differently", especially compared to a compiled language (which was the example), rather than attempting to explain the deepest truths behind Rebol (which I'm not entirely confident on). I should have made that clear. I sould have also made clear that my meaning referred to what happens at load - distinguishing between might happen when Rebol script is parsed as opposed to when Rebol values are evaluated.
> Every time the function referred to by to local-func is evaluated, > my-local-string is set to refer to THE SAME STRING, rather than a > newly-created one.
This sounds like a nice description when you have the expectation that functions always do something (their definitions) when they are evaluated. That they carry out all the parts of their definition when evaluated. A way of thinking that says "this function now has program control" so it has to do something (which is quite reasonable to imagine). But I wonder if Rebol necessarily sees functions like this? Are they perhaps a dialect that is interepreted? I only ask this because I'm trying to shake of my normal assumptions of what Rebol is doing when it evaluates a "function" which is after all a Rebol value not something like machine instructions (another guess!).
> Therefore, mutations on the value of my-local-string > (e.g., append, insert, remove, replace ) are continuing to operate
<<quoted lines omitted: 4>>
> out loud about how to describe the behavior of literal series values > in REBOL, as this sort of thing keeps coming up on the list.
Yes, I know. I've collected three useful descriptions of it on my tips page. But I feel that at least two levels of description (absolute beginner/ not an absolute beginner) could be useful - differentiated perhaps by one using metaphor and the other describing "the truth"...
> You certainly described the correct solution in the remainder of your > note, but I'm wondering if making a more explicit distinction between > load time and evaluation time will help us explain this.
Well, I think Elan can tell you that he believes it would since this distinction is made in "The Official Guide" (p230). Brett.

 [7/22] from: ptretter:charter at: 17-Aug-2000 19:58


Is three blocks proper syntax for a function? Paul Tretter

 [8/22] from: rryost:home at: 17-Aug-2000 19:19


3 blocks is ok as can be seen by
>> help function
Russell [rryost--home--com]

 [9/22] from: al:bri:xtra at: 18-Aug-2000 16:15


Paul wrote:
> Is three blocks proper syntax for a function?
MyFunc: func [Args] [print Args] MyFunction: function [Args] [Locals] [Locals: Args print [locals args]] MyDoes: does [print "No args or locals"] Yes. I hope that helps! Andrew Martin ICQ: 26227169 http://members.xoom.com/AndrewMartin/

 [10/22] from: al:bri:xtra at: 18-Aug-2000 17:43


Brett wrote:
> But I wonder if Rebol necessarily sees functions like this? Are they
perhaps a dialect that is interpreted? Rebol functions are a dialect and they are interpreted. Andrew Martin ICQ: 26227169 http://members.xoom.com/AndrewMartin/

 [11/22] from: agem:crosswinds at: 18-Aug-2000 13:37


i add my description too hope its new :) REBOL makes no destinction beetween data and program. not to the user: you can edit text and you can load (do) text. not to the program: it can edit blocks and load (do) blocks. the "a:" should be seen as a "bookmark" in a block. nothing more. in a functions it bookmarks into a part of the function. if it changes its content, it changes the function too. if you want to avoid it, you have to tell the system "i need a new block". which can be done by copy "this string (or block or other series)" or make string! 1000 ;empty string with 1000 char preallocated when it comes to do code, the system can not decide if a block is only read or changed to: if something [some code] print "this string" change [datas here] 'code yes-way: [some code] if something yes-way ... and maybe one wishes to really change the function? simply like c's "statics" or because of clever meta-hacks or to keep scripts shorter? would need new sytax otherwise.
>> repeat i 10 [append [] i]
== [1 2 3 4 5 6 7 8 9 10] ( do copy [repeat i 10 [append [] i] ] ; in a function ..) or repeat i 10 [append list: [] i] probe list you can collect scripts output with
>> &: func[s][append append "" s ", "] >> & "this" & "that" third second :&
== "this, that, " short :)
>> &: func[s][append append "" s ", "] >> get-res: third second :& 3 ;change if '& changes!
== 3
>> & "this" & "that" res ;use it
== "this, that, " safer. i remember to change 'get-res if you change '& ..
>> &: func[s][append append res: "" s ", "] >> & "this" & "that" res
== "this, that, " better. should have thought before :) other ways like auto-copy may break concepts i not know yet.., and may be slower.. -- Volker --- [bhandley--zip--com--au] wrote on 18-Aug-2000/10:09:43+10:00

 [12/22] from: agem:crosswinds at: 18-Aug-2000 15:20


--- [agem--crosswinds--net] wrote on 18-Aug-2000/13:37:06+1:00
> i add my description too hope its new :) > ... > >> repeat i 10 [append [] i] > == [1 2 3 4 5 6 7 8 9 10] > > ( do copy [repeat i 10 [append [] i] ] ; in a function ..) >
do copy/deep [repeat i 10 [append [] i] ] ; in a function .. copy/deep of course.. Volker

 [13/22] from: bhandley:zip:au at: 19-Aug-2000 1:26


Guru question. Rebol functions are a dialect which is interpreted... [ ] At load time. [ ] After being loaded. [ ] Both of the above. [ ] The question is irrelevent and can be ignored without harm. [ ] Not enough information to say. [ ] Other (please specify). ________________ ;) Brett

 [14/22] from: galtbarber:mailandnews at: 18-Aug-2000 15:03


To Andrew: why do you say that rebol functions are a kind of rebol dialect? I thought they were more of a built-in type function! There are some special things that happen in a function that are all about binding params and locals, but I would be surprised if functions worked internally like the dialect that is in parse or view. If it works that way, it's a sheer revelation to me. In fact, how could you define a dialect without referring to other functions? Is that a chicken and egg kind of thing? To Everybody: in the examples given in this thread, there is none showing this obvious one using /local with func: somefunc: func [ n [integer!] /local tmp ][ tmp: n * n ;;; snipped rest of code ... ] I believe that internally 'function will just end up calling 'func and passing the block of locals as /local. If you make yourself a function f with 'function and then look at first :f, second :f and third :f, you will see that in first :f there is the param list with the locals defined with /local. I think this change appeared with Rebol2. -Galt p.s. although Rebol may be "interpreted", the body and params and etc. have been fully load -ed and that means they are like typed tokens and bound words that are ready to roll. It's not like a lot of simple interpreters which are converting straight from source as just a string of characters for each and every line. when the function definition is executed that baby creates the function! value and assigns it to the function's name word, and that value sure isnt just a string! of code. so that makes sense and the interpreter can run pretty fast. I am sure that it is the same with Logo, Lisp, Scheme, etc... I think the series type is also something that helps make Rebol fast. I don't recall seeing its like in those other cousins of Rebol. -Galt

 [15/22] from: al:bri:xtra at: 19-Aug-2000 9:58


Brett wrote:
> Rebol functions are a dialect which is interpreted...
Yes. Rebol functions are merely words and blocks. For example: [ Rebol[] ArgBlock: [Arg] BodyBlock: [print Arg] append/only ArgBlock [string!] MyFunc: func ArgBlock BodyBlock MyFunc "This is my Arg." ] See that 'ArgBlock and 'BodyBlock are just Rebol blocks. Look at the reflection:
>> source MyFunc
MyFunc: func [Arg [string!]][print Arg] It really is as simple as that. I hope that helps. Andrew Martin See Rebol, do Rebol, know Rebol... ICQ: 26227169 http://members.xoom.com/AndrewMartin/

 [16/22] from: al:bri:xtra at: 19-Aug-2000 10:27


Galt wrote:
> why do you say that rebol functions are a kind of rebol dialect?
Because they are a kind of rebol dialect. They are blocks with special meaning.
> I thought they were more of a built-in type function! There are some
special things that happen in a function that are all about binding params and locals, but I would be surprised if functions worked internally like the dialect that is in parse or view. If it works that way, it's a sheer revelation to me. In fact, how could you define a dialect without referring to other functions? Is that a chicken and egg kind of thing?
>> first :MyFunc
== [Arg]
>> second :MyFunc
== [print Arg]
>> third :MyFunc
== [Arg [string!]] The: make function! that appears in the source for 'func and 'function is where any dialect pre-processing occurs, and MyFunc is where the function dialect gets executed. This is where the "magic" happens. 'Func, 'function and 'does are simply built on top of these. I hope that helps! Andrew Martin ICQ: 26227169 http://members.xoom.com/AndrewMartin/

 [17/22] from: larry:ecotope at: 18-Aug-2000 17:34


Hi Galt You raise some interesting questions. I don't have time right now to go into much detail on this, so just a couple of quick comments.
> p.s. although Rebol may be "interpreted", > the body and params and etc. have been fully > "load"-ed and that means they are like typed > tokens and bound words that are ready to roll.
make function! which can be used directly and is called by 'func and 'function takes two block args: spec and body. The spec block contains a spec which is a REBOL dialect. It is parsed (internally) with the spec dialect rules to determine the meaning. make function! creates a local enviroment or frame with bindings for the local words. The local words include each arg, each refinement (as a word!), each refinement arg, as well as each local specified with /local. These are all bound locally and have the value unset!. When the function is executed, the interpreter evaluates the refinements to true or false, and evaluates the args and refinement args and binds the local words in the local frame to those values or, as appropriate to none. The interpreter then simply evaluates 'do body-block. third :f gives the original spec and first :f gives the word list including /local to separate those values specified with local. In both cases, the words in the returned block are not bound to the local context of the function. These are "dead" blocks, the original versions in the function cannot be modified by appending something to the "dead" blocks. In other words, the spec cannot be modified after the function is created, it is used during the function creation process (i.e. by make). After creation, these blocks provide reflective info about the function. Of course, they *can* be used to create a new function with the same spec or with a modification of the spec. second :f is different. It returns a "live" block of code (the body) with the contained words bound to the local frame of the function f. This block of code can be modified with and extended (with append etc. using 'bind if necessary) after the function is created. It seems clear that the interpreter executes the function by 'do-ing this body block.
> It's not like a lot of simple interpreters which are converting > straight from source as just a string of characters > for each and every line.
Well, it is not a string, it is a block defined within a context.
> when the function definition is executed > that baby creates the function! value and > assigns it to the function's name word, > and that value sure isnt just a string! of code.
As above, I think the body is a block of code with words bound in a private frame, which *is* actually evaluated by the interpreter each time the function is called. Of course, the arg values are bound to the local words first. Recursion requires more explanation. See some of the recent posts on contexts by Ladislav.
> so that makes sense and the interpreter can run > pretty fast. I am sure that it is the same > with Logo, Lisp, Scheme, etc... I think the > series type is also something that helps make > Rebol fast. I don't recall seeing its like > in those other cousins of Rebol.
REBOL blocks and more generally series combine the access and modification features of Scheme lists (head, tail, next, first) and Scheme vectors (pick, poke, at). Most of the above is just my current best guess about how function creation works. Cheers -Larry --------snip

 [18/22] from: bhandley:zip:au at: 19-Aug-2000 12:41


> second :f is different. It returns a "live" block of code (the body) with > the contained words bound to the local frame of the function f. This
block
> of code can be modified with and extended (with append etc. using 'bind if > necessary) after the function is created. > It seems clear that the > interpreter executes the function by 'do-ing this body block.
The original reason I originally questioned the relationship between functions and dialects in this thread was due to this "'do-ing the body block" concept. To make the question specific define a function f like this:
>> f: func[/local x][x: {} append x "a" print x]
My question then is, how are the first two values (x: {}) of the body block treated when the interpreter executes the function? In terms of purely executing the block, logically it seems, the first two values could be considered redundant, correct? A related issue (maybe), I don't know if it is been asked before. If I now use f, I get:
>> f
a
>> f
aa Compare this with another function g and its results:
>> g: func[/local x][x: 0 x: add x 1 print x] >> g
1
>> g
1 Are these results related to the execution of a function or the interpretation of datatypes? Any enlightenment please? Brett.

 [19/22] from: lmecir:geocities at: 20-Aug-2000 23:57


Hi, no "Dialect" notion can help you with your problem. (My personal preferences are, that Rebol functions aren't "Rebol dialect", because I think that there is a difference between a Rebol code in a block and a Rebol function, which has got more attributes, than Rebol code - see my Rebol function model in Words, Bindings and Contexts thread.) Back to your problem. The difference you see can be visualised here: a: "" b: :a append :b "a" probe :a a: 0 b: :a add :b 1 probe :a The results show, that there are differences between integers and strings in Rebol, Rebol strings are mutable (you can change them), while integers are immutable (you cannot change them). More can be found eg. in: www.rebol.org/advanced/mutable.r or in the Evaluation thread. Regards Ladislav

 [20/22] from: ptretter:charter at: 20-Aug-2000 17:57


The result is not what I expect. How do we account for this behavior.
>> probe :a
a I thought the output would be "" Please explain this in more detail.

 [21/22] from: lmecir:geocities at: 21-Aug-2000 19:53


Hi, you can do: print read http://www.geocities.com/lmecir.geo/evaluation.txt to read my "Rebol Values vs. Human Values" and print read http://www.geocities.com/lmecir.geo/contexts.txt to read "Words, Bindings and Contexts" Regards Ladislav

 [22/22] from: ptretter:charter at: 21-Aug-2000 14:47


Thanks for this information. Helps.

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted