문제

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 fill 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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top