4

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?

Rebol Tutorial
  • 2,738
  • 2
  • 25
  • 36
  • This is a clear question for any rebolers, if you are not a reboler skip this instead of just voting down what you are not capable to understand. – Rebol Tutorial Jul 02 '10 at 18:33
  • Maybe you should ask "Why does -part 1- return false but -part 2- return true?" It probably isn't weird behavior at all. – John Jul 02 '10 at 18:37
  • SURE IT IS WEIRD because class-name: default-class-name isn't even executed yet so class-name shouldn't exist in memory and so value? 'class-name should not return true. – Rebol Tutorial Jul 02 '10 at 18:41
  • 2
    The point is "is this weird" is not a good question. "Why does this happen" or "How does this work" are good questions. – Rex M Jul 02 '10 at 18:43
  • Rex: Yes, that was my point. Rebol: I was trying to explain why someone downvoted you. – John Jul 02 '10 at 18:44
  • If people were machines I would maybe more explicit but I guess that some human brains are capable to understand that they should of course elicit the cause. – Rebol Tutorial Jul 03 '10 at 06:29

4 Answers4

2

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.

Graham Chiu
  • 4,856
  • 1
  • 23
  • 41
  • Ah that's it. But this should be considered a bug because that is not the expected behavior of a function. funct shouldn't behave differently from func except for the variables being turned local. So I have to return to func and declare all my variables local just because funct not behaves like a true function ? That defeats the purpose of having created funct. – Rebol Tutorial Jul 03 '10 at 06:28
  • 1
    funct is syntactic sugar for func /local. It scans the body of the function for you looking for set-words, and creates them as /local. If you declare them with /local, the effect is the same. – Graham Chiu Jul 03 '10 at 21:26
  • I don't think it should be considered a bug, because it cannot work any other way. Remember that in REBOL, the only context that can be expanded dynamically is the global one. In your case, the behavior is exactly as expected: a context is created and words are bound to it. – Gregory Higley Jul 08 '10 at 01:28
  • It's a bug because it doesn't behave as a user would expect or it should documented explicitely and says: it's impossible to use value? with funct. – Rebol Tutorial Jul 17 '10 at 14:00
  • I mean doc implicitely says funct behaves exactly like func /local. but that is not the case. And I'm not interested in using funct if value? and maybe other functions don't work exactly as with func /local. – Rebol Tutorial Jul 17 '10 at 14:02
  • /local is daunting because you have to not forget to add local vars but I prefer that rather than realize I need to use it finally just because I need to use value? function. – Rebol Tutorial Jul 17 '10 at 14:03
  • So funct sucks I'll never use it :) – Rebol Tutorial Jul 17 '10 at 14:04
  • `funct` behaves exactly like `func /local`. You can read the source to confirm this. Or you can show an example where they behave differently. So far you seem to have done neither. – earl Aug 02 '10 at 21:16
1

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.

Ladislav
  • 151
  • 2
  • Thanks ladislav I know about /local but it's so daunting to add to /local each time you add an other variable so that you forget to do it. Now I finally prefer func and /local if funct is not able to behave exactly like func /local. – Rebol Tutorial Jul 17 '10 at 14:01
1

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.

Ladislav
  • 970
  • 4
  • 15
  • Thanks Ladislav but it doesn't change the fact that I cannot use funct and so funct is useless for me. Either funct is a shortcut for func /local either it isn't and for me it isn't in my very example. – Rebol Tutorial Jul 29 '10 at 22:40
  • 1
    It is as *my very example* proves – Ladislav Jul 30 '10 at 09:35
1

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.

endo64
  • 2,269
  • 2
  • 27
  • 34
  • Well I don't understand why you say it doesn't behave differently since I found an example where it does :) – Rebol Tutorial Jul 29 '10 at 22:36
  • But in your first example, there is no set-word, as in your second example: "class-name: default-class-name". funct runs at definition-time not when you call the function. When you use funct and if there is a set-word like "class-name:" then it is already defined as a local variable in your function. Even if you never call the function. And this is exactly the same behavior as func /local. If you put class-name as a /local in your func then it will be the same. – endo64 Jul 30 '10 at 13:05