I have reduced down to a small example some code that I have, which tests for whether a variable called class-name
has a value assigned to it:
ask-params: function [
config-file [file!]
default-class-name
default-fields
] [
probe value? 'class-name
input
either (value? 'class-name) [
probe class-name
] [
;-- omit code in this branch for now
]
]
ret-block: ask-params %simple-class.params.txt "Person" "First Name, Last Name"
The expression value? 'class-name
returns false here. On the other hand, if I f开发者_如何学编程ill in the missing branch with an assignment:
ask-params: function [
config-file [file!]
default-class-name
default-fields
] [
probe value? 'class-name
input
either (value? 'class-name) [
probe class-name
] [
class-name: default-class-name
]
]
ret-block: ask-params %simple-class.params.txt "Person" "First Name, Last Name"
This will return true for value? 'class-name
. But in this second case, class-name: default-class-name
isn't even executed yet.
I would think that class-name shouldn't exist in memory, so value? 'class-name
should be returning false. Why is value?
returning true instead?
You are using function
. This scans the body of the function and pre-creates the local variables for you, initialized to NONE. That's why value? 'class-name
becomes true (because NONE is a legal value for a variable, distinct from the situation of being "unset").
If you used func
instead, then both would return false.
I don't think function
behaves differently than func /local
. Look at these examples:
>> f: func [/x] [value? 'x]
>> f
== true
I didn't give any value to x, but it says it HAS a value. Same for /local
>> f: func [/local x] [value? 'x]
>> f
== true
Because when you make a variable local (or a refinement) then it means you already set a value for it (which is none) and that is what function
does.
Here I show you two examples not using FUNCTION, but otherwise equivalent to your code:
ask-params: func [config-file [file!] default-class-name default-fields] [
probe value? 'class-name
input
either (value? 'class-name) [
probe class-name
][
]
]
ask-params: func [
config-file [file!] default-class-name default-fields /local class-name
] [
probe value? 'class-name
input
either (value? 'class-name) [
probe class-name
][
]
]
While the value?
function in the first example yields #[false]
, in the second example it yields #[true]
. That is because the "refinement arguments" following an "unused refinement" (a refinement that is not used in the actual call) are initialized to #[none!]
together with the refinement variable. This applies to the /local
variables as well, since the /local
refinement does not differ from other function refinements (except for the fact, that it is a convention to use it to define local variables).
Since the function
generator uses the /local
method to implement local variables "under the hood", the above description applies to all functions it generates as well.
There is another way, which avoids using FUNC/LOCAL and still allows the use of FUNCTION.
That is to not use a SET-WORD! for the assignment. Instead use the SET function on a LIT-WORD!
ask-params: function [config-file [file!] default-class-name default-fields] [
probe value? 'class-name
input
either (value? 'class-name) [
probe class-name
] [
set 'class-name default-class-name
]
]
You will get #[false]
for the value?
function. However, the call to SET will be setting class-name
in the global environment...not as a local.
精彩评论