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