Words, Bindings and Contexts. (1)
[1/17] from: lmecir::geocities::com at: 23-Jul-2000 19:01
Hi Rebols,
Mark Dickson wrote:
1. What contexts are?
2. Why are they important?
3. How are they determined i.e global or local ?
4. How, where & when are "new" context created ?
5. What is the lifespan of new context?
6. Why is it useful to know about this stuff ?
7. What productive use can be made of this ?
Here are my answers:
(feel free to suggest a better terminology or wording)
What are Rebol Words?
****************************
Word! is a very important Rebol datatype. A word can be used as a
value eg.:
probe 'a
, or:
equal? 'a 'b
etc.
What are Rebol Bindings?
******************************
The most important property of Rebol Words is the ability to
contain
any Rebol Values, so you can "store" a Rebol Value in a
Word like:
a: 12
set 'a 12
set/any 'a 12
and get the "stored" value back as:
:a
get 'a
get/any 'a
>From the printable form of a Word like mold 'a, mold 'b, etc., you
cannot decide, if and what value is stored in it. Even equal words
can store different values, as can be seen here:
; create a block Blk containing a word 'a
blk: copy [a]
a: 12
; now append another word to Blk
b: make object! [append blk 'a a: 13]
probe blk
; test if blk contains equal words
equal? first blk second blk
equal? get first blk get second blk
What is the reason behind such a "mystery"? The answer is simple:
*Words have Bindings*
and the first Word in Blk has a different Binding, than the
second.
The former sentence looks logical, but it doesn't make a good
sense yet, because I didn't say, what are Rebol Bindings. Let's
put a sense into it:
*Rebol Binding definition:*
Every Rebol Word has attributes allowing it to "contain" Rebol
Values. The set of that attributes I am calling the Word's
Binding.
When do Words have equal Bindings? A few observations:
a) different (ie. Not-equal) Words have different Bindings
b) equal words may have either equal or different Bindings (see
above)
c) the same Words have equal Bindings
d) Words, that have equal Bindings are the same
Illustration of d):
same? first blk (bind second blk first blk)
to be continued...
[2/17] from: lmecir:geocities at: 23-Jul-2000 20:47
Rebol Contexts
******************
Before introducing other properties of Bindings, I will try to
introduce Contexts.
Rebol Contexts are existing data, so we are not free to use any
definition of them. The "proof":
some Contexts are directly available:
Global Context is available as Rebol/Words
Objects
Some Contexts are not directly available, but because there is a
GC fault, they can be garbage-collected, which proves, that they
really existed (I cannot imagine collection of a non-existent
thing).
Here are some functions enabling us to access contexts not
directly available:
global: func [
{create a Global Context Word equal to the given Word}
word [word!]
] [
; this is just one of many possibilities, how to do it
make word word
]
global?: func [
{find out, if the given Word is a Global Context Word}
word [word!]
] [
same? word global word
]
; this function can help us explore the Contexts, that aren't
directly available
same-context?: func [
{find out, if the given Words are the Words of the same
Context}
word1 [word!]
word2 [word!]
/local word3
] [
if all [global? word1 global? word2] [return true]
if any [global? word1 global? word2] [return false]
if global? word3: bind global word1 word2 [return false]
same? word1 word3
]
to be continued...
[3/17] from: lmecir:geocities at: 23-Jul-2000 23:24
Allow me to present a cleaned Same-context? function. Sorry for
any inconvenience due to reading the former - more complicated
implementation.
; this function can help us explore the Contexts, that aren't
directly available
same-context?: func [
{find out, if the given Words are the Words of the same
Context}
word1 [word!]
word2 [word!]
] [
either global? word1 [
global? word2
] [
same? word1 bind global word1 word2
]
]
Context hierarchy. Pardon?
********************************
Example:
f: func [f-arg] [
prin "F-arg: "
print f-arg
g: func [g-arg] [
prin "G-arg: "
print g-arg
]
g "This is g's argument."
]
f "This is f's argument"
If there were any context hierarchy, then the F's Context should
have been a part of G's Context, which means, that F-arg should
have been in G's Context together with G-arg. Let's see:
word1: probe fourth second :f
word2: probe fourth second get pick second :f 9
same-context? word1 word2
== false
Context hierarchy
? Aye, aye, sir!
****************************************
f: func [x] [
g "this is g's argument."
print x
]
g: func [y] [
x: y
]
word1: second second :g
bind second :g fourth second :f
bind second :g word1
>> f "this is f's argument"
this is g's argument.
Does this prove any "Context Hierarchy?" (the answer left to the
reader)
to be continued...
[4/17] from: lmecir:geocities at: 24-Jul-2000 2:20
Note: The last two sections (Context Hierarchy. Pardon?; "Context
hierarchy"? Aye, aye, sir!) were complicated and not very useful,
but they can be skipped.
What are Rebol Contexts?
*****************************
Rebol Contexts are existing data, sometimes available to the user.
They are used internally by Rebol for the purposes of many Core
functions. Their main purpose is to serve as attribute of Rebol
Words - ie. Rebol Context is a part of any Word's Binding - in
different wording: every Rebol Word knows its Context. Proof: see
the function Same-context? defined in part 3.
Known Rebol Contexts: Available directly as:
a) Global Context Rebol/Words
b) Objects themselves
c) Function Contexts not available
d) Use Contexts not available
e) Special Contexts not available
Properties:
a) Global Context is the Default Context - Words are normally
Global Context Words, if not stated otherwise.
b) Objects are Local Contexts - as opposed to Global Context. They
are created by Make native. The list of Words object O
contains
- ie. the list of Words that are local to O is
available as First O. But look out! There is a catch - the
elements of First O are equal to local O's Words, but the elements
of First O are Special Context Words. To obtain a list of Words
really local to O, one must do:
words-local-to-o: bind first o in o 'self
c) Function Contexts are Local Contexts too. They are attributes
of functions and are created when the respective functions are
created. Function Contexts contain: all argument Words, all
refinement Words, all optional argument Words and all local Words
specified by /local refinement. (you can verify it for particular
examples by using Same-context? function).
d) Use Contexts are Local Contexts and are created when the
respective Use function is evaluated. They contain the Local Words
specified by the first argument of Use.
e) Special Contexts - see a note under Object Contexts, other
example:
a: "q"
a: make block! a
get first a
Here First A is a Special Context Word too.
The problem is, that Bind doesn't work for Special Contexts, which
means, that our Same-context? function doesn't work too. Here is
an improved version:
special-context?: func [
{determines, if a word is a Special Context Word}
word [word!]
] [
error? try [error? get/any word]
]
; this function can help us explore the Contexts, that aren't
directly available
same-context?: func [
{find out, if the given Words are the Words of the same
Context}
word1 [word!]
word2 [word!]
] [
either global? word1 [
global? word2
] [
either special-context? word2 [
special-context? word1
] [
same? word1 bind global word1 word2
]
]
]
[5/17] from: lmecir:geocities at: 24-Jul-2000 15:09
In the part 4 I forgot to introduce a special kind of Contexts:
f) Dangerous Contexts. Example:
f: func [x] []
special-context? first first :f
CRASH
I obviously cannot claim that Same-context? works in this case.
Now I supply another interesting function:
; actually, Thomas Jensen was first there (nice work), but this
function is able to find even the Unset Words
context-words: func [
{returns all Context Words of a Word's Context}
word [word!]
/local result c-word
] [
either special-context? word [
; we are out of luck in this case
none
] [
result: copy []
foreach g-word first system/words [
if not same? g-word c-word: bind g-word word [
append result c-word
]
]
result
]
]
to be continued...
[6/17] from: jeff:rebol at: 24-Jul-2000 9:00
I've always thought that someone could use REBOL/view to
create an animated colored map presentation which
demonstrates the nature of contexts...
-jeff
[7/17] from: lmecir:geocities at: 24-Jul-2000 19:55
In the previous sections I answered some questions regarding
Contexts.
The lifetime Contexts:
*************************
The Global Context should last forever, Local Context have
indefinite extent, which should mean, that if there were no GC
bugs, they should last as long, as they are accessible.
Now something on Bindings:
Bindings revealed:
**********************
I think, that I succeeded to demonstrate, that every Rebol Word
has got a Context attribute. The next attribute everybody is
familiar with, is its Mold attribute. It is simply the value that
can be obtained by:
mold 'word
The Context and Mold attributes are normally enough to
characterize a Rebol Word. A special case can be discussed:
Aliases. As a toy I present a function able to find out, if two
given words are aliases of each other:
aliases?: func [
{find out, if word1 and word2 are aliases}
word1 [word!]
word2 [word!]
] [
all [
; aliases are equal in Rebol
equal? word1 word2
; but have different Mold attributes
not equal? mold word1 mold word2
]
]
Aliases are not currently considered by Rebol as the same Words.
(Because their Mold attributes differ?)
Observation concerning Rebol Words is as follows:
Two Words are the same, if their Context attributes are the same
and their Mold attributes are equal.
(This would be true probably for all Contexts, but we haven't got
the means to check the case of Special Contexts and Dangerous
Contexts.)
Example illustrating, that the same value and equality of Words
doesn't mean the same Binding:
blk: copy [a]
a: 11
b: make object! [append blk 'a a: 11]
print [
mold blk
":"
mold reduce blk
]
print [
"Do the first and the second element above have the same
Binding?"
same-context? first blk second blk
]
What I didn't discuss, is the case of recursive functions in
Rebol, but I hope, that somebody finds even the present text
helpful. (If any of the questions at the beginning remains
unclear, feel free to ask.)
Ladislav
[8/17] from: giesse:writeme at: 24-Jul-2000 20:17
Hey, I did get only Jeff's message from this thread! Could someone
at RT check if they get errors from my account?
(Don't need to send me the thread, I'll have a look at it in the
archive. In the meantime, I'm sorry if someone asked something to
me and I did not answer yet.)
Regards,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
[9/17] from: agem:crosswinds at: 24-Jul-2000 19:39
[
REBOL[
version: 1.0.0.5
file: %/home/volker/edis/screbol-0.1.6.4/public/test.r
date: 24-Jul-2000/19:33:50+1:00
author: "volker"
purpose: {
here is a context-simulator to show what happens with
binding. AFAIK. in a way Elan is right with inheritance,
virtual function tables in c++ are created similar.
on the other hand he is "wrong", because scoping in
rebol can be a bit confusing, as Gabriele showed with
objects. but inheritance with objects is made by 'make
in another way,
I think one should think about binding by replacing
same-named addresses from another context
with functions bindings are summed, and each new call
to 'func binds its body to its argument-list. this
replaces all bindings to global names, if this names
are local variables. so getting "scoping".
for parameters i think Gabrieles push/pop arg-list-values
are right.
in Gabrieles nested-object sample for scoping he should
write [make make make object! [][][] ] to get scoping,
in his sample all stuff is bound to global, then 'object! . it can't
be bound to the static scope (=brackets around it
in sourcecode) because at block-creation no sub-context
exists..
>> obj1: make object! [
[ a: 2
[ obj2: make object! [
[ b: 2
..
Volker
}
]
{we nedd a memory-simulation}
memory: array 10
set-m: func [n][pick memory n]
get-m: func [n v][poke memory n v]
top: 1
new-adr: func [/local res][res: top top: add top 1]
is-unset: 0
{and one for contexts}
;note the need for copy contents! use make-context!
context: [words: make hash! [] addresses: make block! []]
new-context!: func [][make object! context]
get-adr-for: func [context word /local there adr][
there: find context/words word
either there [adr: pick context/addresses index? there] [none]
]
set-c: func [context word value /local adr][
adr: get-adr-for context word
if not adr [
adr: new-adr
append context/words word
append context/addresses adr
]
poke memory adr value
]
get-c: func [context word /local][
pick memory get-adr-for context word
]
{to simulate and dump code-blocks this}
code-entry!:
make object! [
context: none
word: none
adr: none
]
make-code-entry: func [.word /local id .adr res][
make code-entry! [context: 'no-context-yet word: .word adr: is-unset]
]
{and a bind-simulation (not for subblocks yet)}
bind-c: func [.context code /local adr][
foreach entry code [
adr: get-adr-for .context entry/word
if adr [entry/adr: adr entry/context: .context]
]
]
print {^/^/now the testing}
print {^/--- some data^/}
a-context: new-context!
another-context: new-context!
some-code: reduce [
make-code-entry 'a-word
make-code-entry 'b-word
make-code-entry 'c-word
]
? a-context ? another-context print "" ? some-code ? memory
print {^/--- filling a bit in^/}
set-c a-context 'a-word "a-word"
set-c another-context 'b-word "b-word"
set-c a-context 'c-word "c-word-in a-context"
set-c another-context 'c-word "c-word-in another-context"
? a-context ? another-context print "" ? some-code ? memory
print {^/--- binding first to a-context^/}
bind-c a-context some-code
? some-code
print {^/--- binding then to another-context^/}
bind-c another-context some-code
? some-code
print {^/in "original" the binding is performed to all sub-blocks}
]
[10/17] from: lmecir:geocities at: 25-Jul-2000 22:37
I see, that the fact, that my series didn't explain the behaviour
of functions WRT Recursion and Binding is a flaw. Here is the
continuation (a model of the behaviour):
; Model of Rebol function:
; ****************************
sim-function!: make object! [
; every function has got a Context attribute
context: none
; every function has got a Spec attribute
spec: none
; every function has got a Body attribute
body: none
; every function has got a provision for Recursion
recursion-level: 0
stack: none
]
; Model of Func function:
; ***************************
sim-func: func [
{create a Sim-function!}
spec [block!]
body [block!]
/local context-init spec-too body-too
] [
; first of all, the function context should be created
context-init: make block! 1 + length? spec
foreach word spec [
append context-init to set-word! word
]
append context-init none
spec-too: spec
body-too: body
make sim-function! [
; create context
context: make object! context-init
; a simplification here
spec: bind/copy spec-too in context 'self
; this is the secret of "Context Hierachy"
body: bind/copy body-too in context 'self
; Create a stack for storing values during recursive calls
stack: copy []
]
]
; Model of the function body execution:
; ******************************************
do-body: func [body] [do body]
; Model of the return from function:
; **************************************
sim-return: func [
sim-f
value [any-type!]
] [
; restore the former values from stack, if needed
if (sim-f/recursion-level: sim-f/recursion-level - 1) > 0 [
set/any sim-f/spec first sim-f/stack
; finish the stack-pop
sim-f/stack: remove sim-f/stack
]
; return the value
return get/any 'value
]
; Model of function Evaluation:
; *********************************
sim-evaluate: func [
{evaluate a sim-function contained in a block with its
arguments}
block [block!]
/local sim-f actual-values
] [
; evaluate the arguments
block: reduce block
; the executed sim-function is first
sim-f: first block
; detect recursion
if (sim-f/recursion-level: sim-f/recursion-level + 1) > 1 [
; get the actual values of local words
actual-values: copy []
foreach word sim-f/spec [
append/only actual-values get/any word
]
; push the actual values to stack
sim-f/stack: head insert/only sim-f/stack actual-values
]
; give local words the supplied values
set/any sim-f/spec next block
; execute the function body and return the result
return sim-return sim-f do-body sim-f/body
]
; Some tests:
; **************
blk: copy []
probeblk: func [] [
prin mold blk
prin ": "
print mold reduce blk
]
recfun: sim-func [x] [
append blk 'x
either x <= 1 [
probeblk
] [
sim-evaluate [recfun x - 1]
]
]
sim-evaluate [recfun 3]
probeblk
[11/17] from: giesse:writeme at: 26-Jul-2000 18:31
Hello [lmecir--geocities--com]!
On 25-Lug-00, you wrote:
l> I see, that the fact, that my series didn't explain the
l> behaviour of functions WRT Recursion and Binding is a flaw.
l> Here is the continuation (a model of the behaviour):
[...]
I just want to say that I agree with this model. This is the
closest representation of REBOL's function context handling IMHO.
OTOH, I'd like to understand why Carl considers the current
behaviour a bug, while I was convinced this was by design.
Still losing messages,
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
[12/17] from: larry:ecotope at: 26-Jul-2000 11:33
HI Ladislav
Very cool! Use of simulated behavior (implemented in REBOL) is a concise
and precise way of expressing one's thoughts about the workings of REBOL
functions. I find it much more informative than lengthy attempts to
describe in ordinary language how functions work.
I have followed your Words, Bindings, and Contexts posts with great
interest. I have learned a lot from your discussions and hope to see more.
Just a couple of quick questions:
Can you say more about Dangerous Contexts? For instance:
>> f: func [x][return x]
>> first :f
== [x]
>> type? first first :f
== word!
>>value? first first :f ;REBOL crashes on any attempt to examine the
words in first :f
Isn't this just a bug in REBOL? Why does it not return an error instead of
crash?
How about a modifying to sim-func to allow handling of /local and
refinements? Then it would be a more complete model of func.
Thank you again for sharing this excellent material.
-Larry
[13/17] from: lmecir:geocities at: 29-Jul-2000 9:56
The last part was about the behaviour of Rebol Functions. The
present behaviour can be called "Computed Quasi Static Binding
with Dynamic Recursion Patch."
Interesting about the "Computed Quasi Static Binding" is, that it
can handle recursion even without the "Dynamic Recursion Patch",
as can be
seen in the next model:
; Model of Context creation:
; **************************
make-context: func [
{create a Context containing given Words}
words [block!]
/local context-init result
] [
; this implementation has got an issue:
; the created Context always contains 'Self
words: difference/only words [self]
context-init: make block! 4 * length? words
foreach word words [
append context-init to set-word! word
append context-init none
append context-init :unset
append context-init to lit-word! word
]
result: make object! context-init
unset in result 'self
result
]
{
The following version of Same-context? uses Make-context to
look more natural:
}
same-context?: func [
{find out, if the given Words are the Words of the same
Context}
word1 [word!]
word2 [word!]
] [
either special-context? word2 [
special-context? word1
] [
same? word1 bind in make-context reduce [word1] word1
word2
]
]
; Model of CQSB function:
; *****************************
cqsb-function!: make object! [
; every cqsb function has got a Spec attribute
spec: none
; every cqsb function has got a Body attribute
body: none
]
; Model of CQSB Func function:
; *********************************
cqsb-func: func [
{create a CQSB-function!}
spec [block!]
body [block!]
/local spec-too body-too
] [
spec-too: copy spec
body-too: copy/deep body
make cqsb-function! [
spec: spec-too
body: body-too
]
]
; Model of the CQSB function body execution:
; *******************************************
; the same as for Sim-function
do-body: func [body] [do body]
; Model of CQSB function Evaluation:
; ***********************************
cqsb-evaluate: func [
{evaluate a sim-function contained in a block with its
arguments}
block [block!]
/local cqsb-f new-context actual-values
] [
; evaluate the arguments
block: reduce block
; the executed cqsb-function is first
cqsb-f: first block
; create a new Context
new-context: make-context cqsb-f/spec
; give new Context words the supplied values
set/any bind/copy cqsb-f/spec in new-context 'self next block
; execute the function body and return the result
return do-body bind/copy cqsb-f/body in new-context 'self
]
; Some tests:
; **************
blk: copy []
probeblk: func [] [
prin mold blk
prin ": "
print mold reduce blk
]
recfun: cqsb-func [x] [
append blk 'x
either x <= 1 [
probeblk
] [
cqsb-evaluate [recfun x - 1]
]
]
cqsb-evaluate [recfun 3]
probeblk
{
Results:
>> cqsb-evaluate [recfun 3]
[x x x]: [3 2 1]
>> probeblk
[x x x]: [3 2 1]
This shows, that "Pure CQSB" looks better than "CQSB with DRP".
Recursion is not the only case, where "Pure CQSB" looks better.
For another example, see this:
}
f: func [x] ['x]
y: f 1
z: f 2
get y
{
Results:
>> get y
== 2
While Pure CQSB yields:
}
f: cqsb-func [x] ['x]
y: cqsb-evaluate [f 1]
z: cqsb-evaluate [f 2]
get y
{
and the results:
>> get y
== 1
But, as always, everything has got its price. Pure CQSB is more
demanding (every call needs a new Context/Binding). Moreover, the
above implementation is not GC-bug proof.
}
to be continued...
[14/17] from: lmecir:geocities at: 26-Jul-2000 22:36
Hi,
> HI Ladislav
>
> Very cool! Use of simulated behavior (implemented in REBOL) is
a concise
> and precise way of expressing one's thoughts about the workings
of REBOL
> functions. I find it much more informative than lengthy
attempts to
> describe in ordinary language how functions work.
>
> I have followed your Words, Bindings, and Contexts posts with
great
> interest. I have learned a lot from your discussions and hope
to see more.
> Just a couple of quick questions:
> Can you say more about Dangerous Contexts? For instance:
<<quoted lines omitted: 4>>
> == word!
> >>value? first first :f ;REBOL crashes on any attempt to
examine the
> words in first :f
>
> Isn't this just a bug in REBOL? Why does it not return an error
instead of
> crash?
>
> How about a modifying to sim-func to allow handling of /local
and
> refinements? Then it would be a more complete model of func.
>
> Thank you again for sharing this excellent material.
>
> -Larry
>
1) I think, that every Rebol Context becomes Dangerous after being
Garbage Collected while still accessible, ie. Dangerous Contexts
may be just "Ghost Contexts" of once normal Rebol Contexts...
2) My intent was to describe the Rebol Context Handling and the
refinements would complicate the code beyond the limit I
considered acceptable. (BTW, if you consider Sim-function/spec as
containing all Function Context's Words ie. Arguments,
Refinements, Words specified as /local, everything holds, the
things that should be added are the examination of a call-path
used, a code to supply None as the value for respective Function
Context's Words, a code for spec parsing and the type checking
code.)
[15/17] from: deadzaphod::hotmail at: 27-Jul-2000 3:00
>l> I see, that the fact, that my series didn't explain the
>l> behaviour of functions WRT Recursion and Binding is a flaw. l> Here is
<<quoted lines omitted: 3>>
>OTOH, I'd like to understand why Carl considers the current behaviour a
>bug, while I was convinced this was by design.
Me too... I rather like the current behavior and have been writing scripts
that will probably break if it is changed. I feel that the current STATIC
binding is an excellent feature, and even if it was a bug, it should be kept
and documented.
- Cal ([deadzaphod--hotmail--com])
[16/17] from: lmecir:geocities at: 29-Jul-2000 17:01
; Model of Use behaviour:
; ***********************
sim-use: func [
"Defines words local to a block."
words [block! word!] "Local word(s) to the block"
body [block!] "Block to evaluate"
/local context
] [
if word? words [words: reduce [words]]
; create the Context
context: make-context words
do bind body in context 'self
]
{
The described behaviour has got its drawbacks (See Bug in
Use?). There is a possibility to improve the behaviour, see the
next model:
}
r-use: func [
"Defines words local to a block."
words [block! word!] "Local word(s) to the block"
body [block!] "Block to evaluate"
/local context
] [
if word? words [words: reduce [words]]
; create the Context
context: make-context words
do bind/copy body in context 'self
]
{
The last subject left is the behaviour of make object!.
Here it is:
}
make-object!: func [
{make object! simulation}
spec [block!]
/local words result
] [
words: make block! 0
foreach elem spec [
if set-word? get/any 'elem [
append words to word! elem
]
]
result: make-context words
result/self: result
do bind spec in result 'self
return get/any in result 'self
]
{
Analogically as above, this code is not well-behaved in some
circumstances. I would prefer the following:
}
r-make-object!: func [
{make object! simulation}
spec [block!]
/local words result
] [
words: make block! 0
foreach elem spec [
if set-word? get/any 'elem [
append words to word! elem
]
]
result: make-context words
result/self: result
do bind/copy spec in result 'self
result
]
[17/17] from: lmecir:geocities at: 29-Jul-2000 20:27
My apologies to everybody. The Make-object! and R-make-object!
functions shall be repaired (missing colon before Elem in append
words to word! :elem) The correct versions:
make-object!: func [
{make object! simulation}
spec [block!]
/local words result
] [
words: make block! 0
foreach elem spec [
if set-word? get/any 'elem [
append words to word! :elem
]
]
result: make-context words
result/self: result
do bind spec in result 'self
return get/any in result 'self
]
r-make-object!: func [
{make object! simulation}
spec [block!]
/local words result
] [
words: make block! 0
foreach elem spec [
if set-word? get/any 'elem [
append words to word! :elem
]
]
result: make-context words
result/self: result
do bind/copy spec in result 'self
result
]
{
here is a code that can behave "unexpectedly":
}
f: func [level] [
make object! [
a: 2 * level
b: either zero? level [
f 1
] [
none
]
a: a + 1
]
]
probe f 0
{
The results:
>> probe f 0
make object! [
a: 0
b: unset
]
}
f: func [level] [
r-make-object! [
a: 2 * level
b: either zero? level [
f 1
] [
none
]
a: a + 1
]
]
probe f 0
{
The results:
>> probe f 0
make object! [
a: 1
b:
make object! [
a: 3
b: none
]
]
}
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted