Search code examples
functionobjectrebolrebol2

What is the undocumented block you get from THIRD on object/function in Rebol2?


I've read internally R2 stores contexts as two tables, one for words and the other for values, so you can ask for them:

o: context [a: 1 b: 2]
>> first o
== [self a b]
>> second o
== [make object! [
        a: 1
        b: 2
    ] 1 2]

in any way...

>> pick o 1
== [self a b]
>> pick o 2
== [make object! [
        a: 1
        b: 2
    ] 1 2]

but there's a third "table" (a block) which seems to be undocumented and this one is only accessible using third function

>> third o
== [a: 1 b: 2]

>> pick o 3
** Script Error: Out of range or past end
** Near: pick o 3

what is supposed to be this third block?

something similar seem to occur in functions but this time both third and pick perform well:

>> f: func [a] [print a]
>> first :f
== [a]
>> second :f
== [print a]
>> third :f
== [a]
>> pick :f 1
== [a]
>> pick :f 2
== [print a]
>> pick :f 3
== [a]

first block is params, second block is body but what does this third block represents in a function?


Solution

  • You noticed:

    >> third o
    == [a: 1 b: 2]
    
    >> pick o 3
    ** Script Error: Out of range or past end
    ** Near: pick o 3
    

    ...which is odd. It seems in Rebol2 that THIRD was not purely synonymous with PICK of 3, for some edge cases. :-/

    In Rebol3 this is no longer the case. But what's also not any longer the case is that in Rebol3 positional picking isn't available for objects or functions:

    >> pick object [a: 1 b: 2] 1
    ** Script error: pick does not allow object! for its aggregate argument
    

    Instead you have WORDS-OF, VALUES-OF, and BODY-OF:

    >> words-of object [a: 1 b: 2]
    == [a b]
    
    >> values-of object [a: 1 b: 2]
    == [1 2]
    
    >> body-of object [a: 1 b: 2]
    == [
        a: 1
        b: 2
    ]
    

    These have been backported to Rebol2 in an built-in library called "R2/Forward", so you can (and should) use these functions in place of positional pick.

    You noticed getting similar answers from FIRST and THIRD with:

    >> f: func [a] [print a]
    
    >> first :f
    == [a]
    
    >> second :f
    == [print a]
    
    >> third :f
    == [a]
    
    >> pick :f 1
    == [a]
    
    >> pick :f 2
    == [print a]
    
    >> pick :f 3
    == [a]
    

    first block is params, second block is body but what does this third block represents in a function?

    Your example was too simple to notice that the distinction of the third was that it was the SPEC-OF, because your spec only contained words. So SPEC-OF was equal to WORDS-OF. Adding a type constraint to your spec reveals the difference.

    >> f: func [a [integer!]] [print a]
    
    >> first :f
    == [a]
    
    >> third :f
    == [a [integer!]]
    

    Once again, Rebol2 via R2/Forward offers you WORDS-OF, SPEC-OF, and BODY-OF for functions. And once again, avoid using positional picks for these properties.