Search code examples
rebolrebol3

How to extend object by adding a function, and then access original object using self?


I'm defining a simple object with two fields. Later I want to extend it with a function that can read those fields. (For the moment, let's say it just wants to print one of them out.)

email-service!: context [ 
    key: "abcd" 
    secret: "" 
] 

extend email-service! 'get-folders does [print self/key]

my_email: make email-service! [
    key: "asdfasdf" 
    secret: "who knows?" 
] 

my_email/get-folders 

The expected output is "asdfasdf", but instead, nothing is printed out.

As a slight twist, replace the "does" with a function:

extend email-service! 'get-folders func [] [print self/key]

Solution

  • Given the workings of "definitional scoping"...your routine defined as does [print self/key] did binding into the enclosing context. That context could be a module or some context we can't see here.

    But let's introduce a manual context just to show what I mean:

    context [
        key: "OUTER CONTEXT KEY"
    
        email-service!: context [ 
           key: "abcd" 
           secret: "" 
        ] 
    
        extend email-service! 'get-folders does [print self/key]
    
        my_email: make email-service! [
            key: "asdfasdf" 
            secret: "who knows?" 
        ] 
    
        my_email/get-folders 
    ]
    

    That will give you "OUTER CONTEXT KEY" as output. This function you are defining only knows about its enclosing context, it doesn't know you will later be passing it by parameter to become a new member of email-service!.

    But obviously your question isn't about how to put the function inside the definition of email-service!. You want to add it after-the-fact. How to connect it up to know about email-service? By explicitly binding the body of the function where you want it.

    email-service!: context [ 
        key: "abcd" 
        secret: "" 
    ] 
    
    extend email-service! 'get-folders does bind [print key] email-service!
    
    my_email: make email-service! [
        key: "asdfasdf" 
        secret: "who knows?" 
    ] 
    
    my_email/get-folders 
    

    That should get you the desired "asdfasdf". If you wanted to do it with a function you would do the same...bind the body:

    extend email-service! 'get-folders func [] bind [print key] email-service!
    

    It's up to you to decide whether to bind the self word to email-service! and use it. You don't need it here (notice that I say print key and not print self/key). Just remember that every word you deal with can have a binding for evaluation...and it can be different even for words with the same spelling in code composed from multiple contexts.