Function Context Query
[1/20] from: robbo1mark:aol at: 3-Dec-2001 10:22
Surely this is incorrect?
>> a: has [b c] [ print b print c]
>> a
none
none
>> a/local 3 4
3
4
Surely local words default value should be unset
until they are defined?
Also in the second case is it correct to be
able to pass values to local words in this manner?
How is the above different from this....
>> use [b c] [print b print c]
** Script Error: b has no value
** Near: print b print c
Can somebody please explain the wisdom of this
or is it a bug?
cheers,
Mark Dickson
[2/20] from: rotenca:telvia:it at: 3-Dec-2001 17:30
Hi, Mark
> Surely this is incorrect?
> >> a: has [b c] [ print b print c]
<<quoted lines omitted: 4>>
> 3
> 4
Amazing! At least for me!
This demostrates that /local is a refinement like any other, only for
convention it is used for defining local. One can use another one. The only
difference is that at least Help is aware of the convention about local and
does not put /local about user refinements.
There is no difference between:
a1: has [b c] [ print b print c]
a2: func [/k b c] [ print b print c]
a1
a2
a1/local 2 3
a2/k 2 3
---
Ciao
Romano
[3/20] from: joel:neely:fedex at: 3-Dec-2001 10:42
Hi, Mark,
[Robbo1Mark--aol--com] wrote:
> Surely this is incorrect?
> >> a: has [b c] [ print b print c]
<<quoted lines omitted: 8>>
> Also in the second case is it correct to be
> able to pass values to local words in this manner?
I think you answered your own question; adding the LOCAL
refinement appears to invite A to set its locals as if
they were ordinary "optional" refinement args. As
additional evidence, note this
>> a: has [b c] [ print b print c]
>> source a
a: func [/local b c][print b print c]
>> a
none
none
>> a/local 17
** Script Error: a is missing its c argument
** Where: halt-view
** Near: a/local 17
>>
> How is the above different from this....
<<quoted lines omitted: 3>>
> Can somebody please explain the wisdom of this
> or is it a bug?
Neither wisdom nor bug, just a different mechanism;
USE creates a context containing the word(s) from its
first argument, then evaluates the expression(s) from
its second argument in that new context. Since your
sample didn't do anything to initialize B and C in that
new context, they had no values.
(Actually, USE also has a side effect -- it modifies its
second argument so that words named in the first argument
are bound to the new context. That explains the following
bit of behavior:
>> thing: [print b print c]
== [print b print c]
>> b: "Hello, "
== "Hello, "
>> c: "world!"
== "world!"
>> do thing
Hello,
world!
Presumably there's no surprise there.
>> use [b c] [
[ b: 1
[ c: 2
[ do thing
[ ]
Hello,
world!
If there's surprise here, recall that only occurrences of B
and C *within* the second argument of USE are re-bound to the
new context. Therefore THING still contains the global B and
C words.
>> use [b c] thing
** Script Error: b has no value
** Where: halt-view
** Near: print b print c
No surprise here, because the new B and C never got initiliized.
>> do thing
** Script Error: b has no value
** Where: halt-view
** Near: print b print c
If there's surprise here, recall that USE rebound occurrences
of B and C within THING to the new context. Therefore, THING
no longer contains references to the global B and C.
HTH!
-jn-
--
This sentence contradicts itself -- no actually it doesn't.
-- Doug Hofstadter
joel<dot>neely<at>fedex<dot>com
[4/20] from: ptretter:charter at: 3-Dec-2001 15:07
Seems pretty clear:
>> source has
has: func [
{A shortcut to define a function that has local variables but no
arguments.}
locals [block!]
body [block!]
][function [] locals body]
>> source a1
a1: func [/local b c][print b print c]
>>
Paul Tretter
[5/20] from: rotenca:telvia:it at: 3-Dec-2001 23:08
The strange thing for me is that you can use /local as a refinement and pass
the values of the locals vars as arguments.
I thinked that local was a special keyword for locals vars, not a refinement
like the all the others.
---
Ciao
Romano
[6/20] from: robbo1mark:aol at: 4-Dec-2001 4:21
Joel Neeely/ everybody,
perhaps you misunderstood my previous post,
my concern was that uninitialised local words
are treated differently between contexts and
function-contexts.
Please see below,
>> use [my-word] [print unset? get/any 'my-word]
true
>> my-func: has [my-word] [print unset? get/any 'my-word]
>> my-func
false
>> my-func: has [my-word] [print none? get/any 'my-word]
>> my-func
true
>>
In a use context they are initialised to the unset! value if they are not set BUT in
a function context they are initialised to the none! value and that's what bothers me.
I don't see a reason or logic for the distinction, can anybody please explain why these
contexts are treated differently, as from what I can see it is possible to use uninitialised
words in function contexts, well they're not actually uninitialised as REBOL sets them
to 'none during function context creation,
but WHY?
What makes function contexts a special case?
cheers,
Mark Dickson
[7/20] from: joel::neely::fedex::com at: 4-Dec-2001 7:52
Hi, Mark,
[Robbo1Mark--aol--com] wrote:
> Joel Neeely [sic]/ everybody,
>
> perhaps you misunderstood my previous post,
>
Perhaps the wording of the previous post was capable
of being understood in different ways...
> my concern was that uninitialised local words
> are treated differently between contexts and
<<quoted lines omitted: 12>>
> if they are not set BUT in a function context they are
> initialised to the none! value and that's what bothers me.
Is this a philosophical bothering, or is there some specific
problem that arises from the distinction?
> I don't see a reason or logic for the distinction, can
> anybody please explain why these contexts are treated
<<quoted lines omitted: 3>>
> function context creation, but WHY?
> What makes function contexts a special case?
I don't know about the original design thinking or intent
but we *do* know a little bit about the difference between
FUNC and USE that might be relevant.
1) The naive use of FUNC creates a value that will persist
(for some time) between evaluations. Since REBOL retains
function contexts between uses, perhaps there was some
perceived benefit (either for user or implementor) to
ensuring that each word in the context is associated with
*some* value at all times -- even before first evaluation.
2) The naive use of USE creates a "temporary" context that
allows one to perform an evaluation using some temporary
word names without worrying about whether those names are
already in use in the surrounding environment. Perhaps
there was more of an assumption that the user would have
an immediate purpose for declaring the words of the new
context and would naturally initialize them appropriately
anyway.
Two caveats with the above:
1) I used the word "naive" above not to give offense, but
to distinguish the simplest and most obvious uses of
those features from the more subtle uses normally made by
more experienced (or devious ;-) programmers:
a) One can certainly create anonymous functions for
ad hoc usage (such as the comparison of SORT)
without expecting the function to persist for any
significant amount of time. (Someone who is tempted to
reply that the comparision function can be called many
times in a single invocation of SORT should be skilled
enough to think of plenty of use-once examples...)
b) One can certainly utilize USE in the construction of
closures, which *are* expected to persist. (However
someone who is skilled enough to write closures should
be able to manage initialization...)
In any case, we sometimes see design decisions (in many
languages in addition to REBOL) driven by the expectations
of the "commonest" use of a language feature.
2) We should probably be cautious about assuming this
difference in behavior was deliberate and not simply a
matter of different code, perhaps written by a different
person, perhaps at a different time, exhibiting different
behavior for no preconceived purpose.
Sometimes things are the way they are just because that's
how they are.
-jn-
--
; sub REBOL {}; sub head ($) {@_[0]}
REBOL []
# despam: func [e] [replace replace/all e ":" "." "#" "@"]
; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"}
print head reverse despam "moc:xedef#yleen:leoj" ;
[8/20] from: rotenca:telvia:it at: 4-Dec-2001 15:26
Hi Mark,
> I don't see a reason or logic for the distinction, can anybody please
explain why these contexts are treated differently, >as from what I can see it
is possible to use uninitialised words in function contexts, well they're not
actually uninitialised >as REBOL sets them to 'none during function context
creation,
> but WHY?
>
> What makes function contexts a special case?
I thik at refinements. It is easy to test them in the body of func if they are
= none.
---
Ciao
Romano
[9/20] from: robbo1mark:aol at: 4-Dec-2001 10:18
Hi Romano,
surely it would be just as easy to test whether local words or refinements are set, ie
with the function Unset? as opposed to none?.
Iam not particularly bothered by this now that I know about it, it was just the oddity
& inexplicable difference about it that initially concerned me.
That's all,
cheers,
Mark Dickson
In a message dated Tue, 4 Dec 2001 9:57:52 AM Eastern Standard Time, "Romano Paolo Tenca"
<[rotenca--telvia--it]> writes:
[10/20] from: rotenca:telvia:it at: 4-Dec-2001 16:54
Hi Mark,
> surely it would be just as easy to test whether local words or refinements
are set, ie with the function Unset? as >opposed to none?.
Mine is only an idea, i'm not sure this is the true reason, but a none value
can be used directly in expression like:
if ref [...]
either ref [][]
An unset value would generate an error in these cases.
Unset? can't be used with an unset word (the evaluation of the word gives an
error), you must use:
value? lit-word
or
unset? get/any lit-word
As you can see it is not the first thing one could try :-)
---
Ciao
Romano
[11/20] from: larry:ecotope at: 4-Dec-2001 12:06
Hi Mark, Joel,
Just a couple of quick comments. The situation with function contexts is a
bit confusing. I believe there are 3 stages involved. We can call them "load
time", "function creation time", and "function application time". Consider
the following:
>> a: "hello"
== "hello"
>> g: func [/local a][a]
>> get first second :g
** Script Error: a has no value
** Near: get first second :g
>> unset? get/any first second :g
== true
>> g
== none
>> get first second :g
== none
1) load time
The word 'a' in the body block [a] of the function definition has been bound
to the global context before the function FUNC is executed, at this time it
will be associated with the value "hello".
2) function definition time
After func has run, a local context has been created in which the word 'a'
has no value. It is unset. The body block is not evaluated at function
definiton time, but is bound to the new context.
3) function application time
Only after g has been executed, is the word 'a' set to NONE. The local words
in the function only get values when the function is applied. If the values
are determined by the arguments or refinements, or by the use of SET or a
set-word in the body block; they assume that value, otherwise they are set
to NONE.
Cheers
-Larry
----- Original Message -----
From: <[Robbo1Mark--aol--com]>
To: <[rebol-list--rebol--com]>
Sent: Tuesday, December 04, 2001 1:21 AM
Subject: [REBOL] Re: Function Context Query
> Joel Neeely/ everybody,
> perhaps you misunderstood my previous post,
<<quoted lines omitted: 12>>
> >>
> In a use context they are initialised to the unset! value if they are not
set BUT in a function context they are initialised to the none! value and
that's what bothers me.
> I don't see a reason or logic for the distinction, can anybody please
explain why these contexts are treated differently, as from what I can see
it is possible to use uninitialised words in function contexts, well they're
not actually uninitialised as REBOL sets them to 'none during function
context creation,
[12/20] from: greggirwin:mindspring at: 4-Dec-2001 13:40
Hi Romano, et al
<< Mine is only an idea, i'm not sure this is the true reason, but a none
value
can be used directly in expression like:
if ref [...]
either ref [][]
An unset value would generate an error in these cases. >>
That's exactly what I was thinking. I have no clue about the inner workings,
but I can say, from my persepctive, that I wouldn't want to use unset? to
check for refinements. The current approach makes for very readable code
IMO.
--Gregg
[13/20] from: rotenca:telvia:it at: 4-Dec-2001 23:51
Hi, Larry
> 1) load time
> The word 'a' in the body block [a] of the function definition has been bound
> to the global context before the function FUNC is executed, at this time it
> will be associated with the value "hello".
Yes, but this is true for everything which is loaded. It depends only by load.
> 2) function definition time
> After func has run, a local context has been created in which the word 'a'
> has no value. It is unset. The body block is not evaluated at function
> definiton time, but is bound to the new context.
This is like in use body or at the start of the body of an object:
>> probe make object! [x: unset? get/any 'a a: 2]
make object! [
x: true
a: 2
]
> 3) function application time
> Only after g has been executed, is the word 'a' set to NONE. The local words
> in the function only get values when the function is applied. If the values
> are determined by the arguments or refinements, or by the use of SET or a
> set-word in the body block; they assume that value, otherwise they are set
> to NONE.
This is the "strange" (but useful) thing which happens in function body (and
not in use or object body): at the start of the execution of function body all
the context values are set to none or to the value of args (true for
refinement!).
> Cheers
> -Larry
---
Ciao
Romano
[14/20] from: larry:ecotope at: 4-Dec-2001 15:22
Hi Romano,
I think we are in good agreement on the mechanics.
> This is the "strange" (but useful) thing which happens in function body
(and
> not in use or object body): at the start of the execution of function body
all
> the context values are set to none or to the value of args (true for
> refinement!).
>
Another way of looking at this is to note that USE and MAKE OBJECT! both
result in immediate evaluation of their body (or spec) blocks, but for
functions the body is only evaluated when the function is applied.
Ciao
-Larry
[15/20] from: robbo1mark:aol at: 5-Dec-2001 4:16
Just my 2 cents worth,
WHY is setting words in functions to 'none by default useful?
Why is the ability to use apparently unset words a desirable feature?
Does this not confuse the language in that words cannot be used until after they have
been defined?
Now we have another "exception" case for words in functions.
What makes words in functions different from global words or words in objects or words
in a use context?
Why the special case?
cheers,
Mark Dickson
In a message dated Tue, 4 Dec 2001 6:44:01 PM Eastern Standard Time, "Larry Palmiter"
<[larry--ecotope--com]> writes:
[16/20] from: rotenca:telvia:it at: 6-Dec-2001 16:27
Hi Mark
> WHY is setting words in functions to 'none by default useful?
When you create the function, all the words (args, refinements, args of
refinements) are binded at a new hidden context and the starting value of
words in context is the unset value.
When you execute the function, all the args and refinements and args of
refinements are set to none if they are not used in the function call. It is
more easy to test a none value of an unset value (none = false for
if/either/while/until...).
The so called "locals words" of a function are only arguments of the
refinement 'local, so they are set to none like any other argument not used in
the function call.
> Why is the ability to use apparently unset words a desirable feature?
> Does this not confuse the language in that words cannot be used until after
they have been defined?
An unset word is a word with the value unset. It is like any other value and
any other word. If you use it where a function ask a value, Rebol triggers an
error. But Rebol triggers the same error if you pass an argument of type
integer! where a function ask for a value of type unset:
>> x: func [a [unset!]][value? 'a]
>> do [x ()]
== false
>> do [x 1]
** Script Error: x expected a argument of type: unset
** Near: x 1
BTW, I think that the name of function value? is confusing. It should be
something like: not-unset-value?
And also unset is confusing, because you can set a word at the unset value:
>> set/any 'a ()
>> value? 'a
== false
my conclusion: unset <> no value
A true word without value is a word out of context which trigger the error:
"is not defined in this context"
> Now we have another "exception" case for words in functions.
> What makes words in functions different from global words or words in
objects or words in a use context?
That they are also arguments. Functions are not contexts, they only use a
context to mask the global context from the value of their arguments.
---
Ciao
Romano
[17/20] from: lmecir:mbox:vol:cz at: 6-Dec-2001 18:21
Hi Romano,
<<Romano>>
(...)
An unset word is a word with the value unset. It is like any other value and
any other word. If you use it where a function ask a value, Rebol triggers
an
error. But Rebol triggers the same error if you pass an argument of type
integer! where a function ask for a value of type unset:
>> x: func [a [unset!]][value? 'a]
>> do [x ()]
== false
>> do [x 1]
** Script Error: x expected a argument of type: unset
** Near: x 1
BTW, I think that the name of function value? is confusing. It should be
something like: not-unset-value?
And also unset is confusing, because you can set a word at the unset value:
>> set/any 'a ()
>> value? 'a
== false
my conclusion: unset <> no value
(...)
<</Romano>>
yes! Another example: (block: reduce [()]). BLOCK will not be empty. Will it
contain
a value?
[18/20] from: robbo1mark:aol at: 6-Dec-2001 14:14
Romano,
I understand how and what happens when words which are local to functions are not defined,
they are defined to the 'none value when REBOL evalautes the function, however my contention
is that REBOL should not do this and leave all local words unset if they are not defined,
just as would happen in a 'use context or in the global context system/words, or indeed
an object context although this would involve first defining the new word in the object!
context then explicitly unsetting it with the 'unset function.
My preference would be all words are defined as local to their context, including words
defined in objects, functions and use contexts. All undefined words are intitialised
to the 'unset value and are testable with the value? or unset? get/any 'word functions.
This seems the most logical, simple, straightforward and consistent solution to me, however
it's not REBOL behaviour so we just have to make do with the quirkiness that is current
REBOL behaviour / design.
Makes it much harder for everybody however to have to learn and remeber all these special
cases and exceptions, don't you agree.
cheers,
Mark Dickson
In a message dated Thu, 6 Dec 2001 10:44:00 AM Eastern Standard Time, "Romano Paolo Tenca"
<[rotenca--telvia--it]> writes:
[19/20] from: rotenca:telvia:it at: 7-Dec-2001 3:08
Hi, Marck
> My preference would be all words are defined as local to their context,
including words defined in objects, functions and use contexts. All undefined
words are intitialised to the 'unset value and are testable with the value? or
unset? get/any 'word functions.
Well, a question of taste (and strict ortogonality).
> This seems the most logical, simple, straightforward and consistent solution
to me, however it's not REBOL behaviour so we just have to make do with the
quirkiness that is current REBOL behaviour / design.
If you prefer unset value, you could use (and eventually extends to implements
args) this joke example which is like a "delayed use block" (define once and
use many times) (is 9/10 times faster than an use block):
>>ufunc: func [locals body][does second func locals body]
>>k: ufunc [a b c][a]
>>k
** Script Error: a has no value
** Where: k
** Near: a
---
Ciao
Romano
[20/20] from: g:santilli:tiscalinet:it at: 6-Dec-2001 19:21
Larry Palmiter wrote:
> 3) function application time
> Only after g has been executed, is the word 'a' set to NONE. The local words
> in the function only get values when the function is applied. If the values
> are determined by the arguments or refinements, or by the use of SET or a
> set-word in the body block; they assume that value, otherwise they are set
> to NONE.
Hint:
>> set [a b c] [1 2]
== [1 2]
>> a
== 1
>> b
== 2
>> c
== none
I should have not spent all this time reading emails today, ;-)
Gabriele.
--
Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer
Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted