rebolrebol2

Retrieving function arguments programmatically in Rebol


This works at the shell level:

>> a: "hello" 
== "hello"
>> get to-lit-word "a"
== "hello"

But within a function like this:

f: func [ arg1 ] [
    v1: get 'arg1
    ? v1
    v2: get to-lit-word "arg1"
    ? v2
]

>> f "goodbye"
V1 is a string of value: "goodbye"
** Script Error: arg1 has no value
** Where: f
** Near: v2: get to-lit-word "arg1"

How do I get the argument value using "get"?


Solution

  • For starters, I'll mention that when you use v1 and v2 in a FUNC like that, you are writing them into the enclosing context. So they'll act like "global variables". To suppress that you'd put in your FUNC-spec func [arg1 /local v1 v2].

    (Note: Rebol3 has FUNCTION which scans for locals automatically and builds the underlying FUNC for you. But FUNCTION meant something else in Rebol2 so that is available as FUNCT.)


    Also: when you write get 'a you aren't passing a lit-word to get. Their lit-ness is what keeps them from being looked up, but when the evaluator runs over it...a lit-word is evaluated to become a word:

    >> type? 'a
    == word!
    

    If you really wanted to pass a lit-word argument to a function, you would have to quote it:

    >> type? quote 'a
    == lit-word!
    

    GET is apparently not rejecting you passing it a lit-word!, although I think it would be clearer if it were more narrowly typed. In any case, I'd write that as get to-word "a".


    I'm probably a bad person to try and answer your main question. But I'll point out that even the first pattern doesn't work in Rebol 3:

    >> a: "hello"
    == "hello"
    
    >> get to-word "a"
    ** Script error: a word is not bound to a context
    ** Where: get
    ** Near: get to-word "a"
    

    For GET to be able to find a value from a word, it's not enough to just "be a word". That word has to be bound to some object that acts as the "context"; and binding is a property attached to the word itself.

    Rebol 2 acts a little different from Rebol 3 about this. But if you want a firehose of information, there are some posts on the topic:

    What is the summary of the differences in binding behaviour between Rebol 2 and 3?

    Often I find that I can get by in cases where I would have said to-word "some-string" by instead saying load "some-string". So in Rebol3:

    >> a: "hello"
    == "hello"
    
    >> get load "a"
    == "hello"
    

    These function arguments look to be a different story. You can manually bind your converted word to a context you get by querying something else within that context:

    f: func [arg1 /local dummy] [
        v2: get bind (to-word "arg1") (bind? 'dummy)
        ? v2
    ] 
    
    >> f "goodbye"
    V2 is a string of value "goodbye"
    

    That works in Rebol2, but not Rebol3 unless you use a closure:

    f: closure [arg1 /local dummy] [
        v2: get bind (to-word "arg1") (bind? 'dummy)
        ? v2
    ] 
    
    >> f "goodbye"
    V2 is a string of value "goodbye"
    

    In the category of mysterious statements about Rebol (like "there are no variables, colon is not an assignment operator") you can add in "Rebol actually does not have scoping at all."

    Is there a overall explanation about definitional scoping in Rebol and Red

    You'll have to ask the experts for more details in chat...