• Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r4wp

[Rebol School] REBOL School

GrahamC
27-Aug-2012
[853x2]
Arnold, 'stack is local to the function.  Ordinarily you would make 
a copy each time the function is called so that you have an empty 
new block.  But here the function does not so that the block contents 
are available unchanged between calls.
So, I guess my question is .. when do local variables get garbage 
collected?
Ladislav
27-Aug-2012
[855x3]
When do local variables get garbage collected?
 - never, only in case they are not accessible
,i.e. only in case the function is collected
however, the STACK local variable is actually not just "local variable", 
it is a value in the function body. In this case the only way how 
the value could be collected is to collect the function
GrahamC
27-Aug-2012
[858]
so you would have to unset the function ?  Or just set it to none?
Ladislav
27-Aug-2012
[859x2]
However, the function looks strange to me. I guess that it should 
have been implemented differently.
so you would have to unset the function ?

 - you cannot unset a function. You can only unset the variable referring 
 to it.
GrahamC
27-Aug-2012
[861]
yes, that's what I meant
Maxim
27-Aug-2012
[862]
Arnold, if you are proficient at language C,  R2's local word model 
is the same as static variables in C.
Ladislav
27-Aug-2012
[863]
E.g.

    f: func [] []
    unset 'f

would make the function inaccessible (collectable), but, e.g.

    g: func [][]
    g: 1

makes the function inaccessible (collectable) as well
Maxim
27-Aug-2012
[864]
that wasn't worded how I meant it...
Ladislav
27-Aug-2012
[865]
R2's local word model is the same as static variables in C.
 - hmm, there are some significant differences
Maxim
27-Aug-2012
[866x3]
Arnold, What I meant to say (and what ladislav is trying to say, 
I think) is that the code inside a function is not Garbage collected, 
so when a function has a litteral value.. that litteral value is 
the same at each execution (its static).
the local values are reset to none at each execution, but they will 
be re-assigned to the same litteral.
(which is why they look like static variables in terms of series 
which are references)
GrahamC
27-Aug-2012
[869]
So, anonymous functions are automatically garbage collected?
Maxim
27-Aug-2012
[870x2]
no.  it depends if they are referenced at least once in a value which 
is not also GCd.
so if you have a function in a block, named or not, it won't be GCd 
if that block is still refered to somewhere.
GrahamC
27-Aug-2012
[872]
so let's say you have something in a vid defintion

button "Test" [
	use [ f ][
		f: func [] []
	]
]

this is not subject to GC?
Ladislav
27-Aug-2012
[873x2]
the local values are reset to none at each execution
 - that should have been:


the local variables are reset to NONE at every function call. After 
the function returns, the local variables are:
- in R2 they 
remember" the last (outermost call) value
- in R3 their values are inaccessible
this is not subject to GC?

 - Such a function looks like a subject to GC, but you need to find 
 out *when*.


- in R2 it is a subject to GC right after the button is pressed and 
released

- in R3 the function *may* persist after the button is pressed for 
the first time and *before* it is pressed for the second time
GrahamC
27-Aug-2012
[875]
@Ladislav, have you written a paper on GC in Rebol ?
Ladislav
27-Aug-2012
[876x2]
Aha, I was wrong with R2, actually in R2 the function persists between 
presses as well, but the reasons are different for R2 and R3
have you written a paper on GC in Rebol ?

 - the reason why the function persists between presses in R2 is based 
 on the fact that USE modifies its argument block "leaving" the local 
 variable in it. (it is described in Bindology). In R3 USE is a closure 
 written in REBOL, that is why there may be some "persistence" until 
 the USE function is called next time
BrianH
27-Aug-2012
[878x2]
IIRC in R3 closures do a BIND/copy of their bodies at every call, 
then execute the copy. As soon as the USE is finished executing its 
context and body are no longer referenced, at least if you didn't 
save a reference elsewhere. The context containing the 'f and the 
function it references would be able to be GC'd as soon as the USE 
returns.
The CLOSURE function in R2 should behave the same way, though it 
fakes it with mezz code.
Ladislav
27-Aug-2012
[880]
Checked the USE implementation in R3 (source use) and you are right, 
Brian, so, the function in R3 shall not persist at all.
BrianH
27-Aug-2012
[881x2]
Yeah, R3's USE does a COPY/deep of the body, then make closure! uses 
the copy itself, then when executed (IIRC) the closure executes a 
BIND/copy of its body. So it copies its body more than once, but 
possibly less than twice.
Proof:
>> b: make closure! reduce [[] [append [] 1]]
>> b
== [1]
>> b
== [1]
>> mold :b
== "make closure! [[][append [] 1]]"
GrahamC
27-Aug-2012
[883]
so to control GC one should in such a block unset the contents before 
leaving it ...
BrianH
27-Aug-2012
[884x2]
Sorry, didn't get that. In R2 if you are using functions not defined 
by the CLOSURE function then you might want to set some local variables 
to none before returning - that's what ALSO was for, btw. In R3 you 
don't need to unset anything because the GC will collect the set 
of values associated with the function's local variables after the 
function returns, or the whole context after a closure returns.
I guess you could use ALSO for R2's USE blocks too, or you could 
explicitly COPY/deep the body the way R3's USE does internally.
Maxim
27-Aug-2012
[886]
In R3 ... the GC will collect the set of values associated with the 
function's local variables
   


does it actually perform the GC, actively mark them as potentials, 
or simply unreference them?
BrianH
27-Aug-2012
[887x5]
It's a stack frame. Stack frames are automatically available for 
collection after the particular function call returns. All function 
words are referenced stack-relative.
They aren't collected immediately, they are collected when the collector 
runs.
Closures are different; the contexts that they create when they are 
called are basically the same as object contexts, with no stack-relative 
indirection needed, but the whole body and context are unreferenced 
after the call.
Whoah, it turns out that R3's closures do more than a regular BIND/copy 
when they run, they copy strings too. Surprised I hadn't tried that.
>> c: make closure! [[] [append "" 1]]
>> c
== "1"
>> mold :c
== {make closure! [[][append "" 1]]}
Same in R2: MAKE function! does more than a BIND/copy on its body 
as well, it also copies strings.
>> c: closure [] [append "" 1]
>> source c
c: func [][native action function! [[throw]] [append "" 1]]
>> c
== "1"
>> c
== "1"
>> source c
c: func [][native action function! [[throw]] [append "" 1]]
Maxim
27-Aug-2012
[892x2]
I always  though  BIND/copy    was   equivalent to    BIND COPY/deep
(which would copy strings AFAIK)
BrianH
27-Aug-2012
[894x4]
BIND/copy doesn't copy everything, it just copies everything that's 
bindable. So, no copying of strings, objects, functions, modules, 
lists or hashes, but it copies blocks, parens and paths. Words are 
of course copied because they're literal values.
At least that's what I was told. Let me check.
Functions and objects aren't copied, but everything else seems to 
be:


>> a: reduce ["" #{} 'a/b [] quote () make list! [] make hash! [] 
does [] context []]

== ["" #{} a/b [] () make list! [] make hash! [] func [][] make object! 
[
    ]]
>> b: bind/copy a 'a

== ["" #{} a/b [] () make list! [] make hash! [] func [][] make object! 
[
    ]]
>> map-each [x: y] b [same? :y first at a index? x]
== [false false false false false false false true true]
I guess that R2's make function! and R3's closures to a BIND/copy 
after all.
GrahamC
27-Aug-2012
[898x3]
What we need is a document that discusses best practice for writing 
Rebol code.   Or is there such a beast?
Sure we have various idioms that people get used to using, but that's 
not the same thing
Ideally this should be in a book chapter .. perhaps Jerry could include 
it in his book as a guest chapter ?
Endo
28-Aug-2012
[901x2]
map-each [x: y] [...] is an interesting use. I sometimes needed to 
get that "index" value but I didn't know that usage so I used forall 
instead. Good to learn.
Why this doesn't work?
e: func [] [f]

context [f: does [print "ok"] do bind 'e self] ;error: f has no value

or when I BIND the F inside E, still doesn't work:
o: context [f: does [print "ok"]]
bind first second :e o
e
** Script Error: f has no value

while this one works:
do bind first second :e o
== ok

doesn't F stay BINDed?