reboltutorial
reboltutorial

Reputation:

Why can't a built-in function be overridden in Rebol?

I have created this

cloneset: :set
set: func[word [word!] value][
if/else (type? get word) = list! [
    print "list is immutable"
][

    cloneset word value
    protect word
]
]
protect 'cloneset
protect 'set

I have this error when defining the val function with the new set function:

val: func[word [word!] value][
    set word value
    protect word
    value
]

>> val: func[word [word!] value][
[        set word value
[        protect word
[        value
[    ]
** Script Error: set has no refinement called any
** Where: throw-on-error
** Near: if error? set/any 'blk try

I don't understand why ?

Upvotes: 4

Views: 200

Answers (3)

Ladislav
Ladislav

Reputation: 987

In Rebol any built-in function can be overridden. You actually did override the set function above.

However, when seeing the error you obtained you should have examined the throw-on-error function. You would have found out that in the function source code there is a call of the set function looking as follows:

set/any 'blk try ...

This call suggests that the throw-on-error function assumes the set variable to refer to a function having a /any refinement. Since your redefined version of the function does not have such a refinement, the throw-on-error function cannot call it that way and thus the error you obtained.

Generally spoken, you can redefine anything, but you have to take the responsibility for the redefinition, especially if the redefined version is not backwards compatible with the original.

Upvotes: 3

ingo
ingo

Reputation: 521

To be sure to get the spec right, you can reuse the spec of the original function:

set: func spec-of :cloneset [
    'new-implementation
]

source set
set: func [
    {Sets a word, block of words, or object to specified value(s).} 
    word [any-word! block! object!] "Word or words to set" 
    value [any-type!] "Value or block of values" 
    /any "Allows setting words to any value." 
    /pad {For objects, if block is too short, remaining words are set to NONE.}
]['new-implementation]

in older versions without 'spec-of, you can use 'first in its place.

Upvotes: 3

Gregory Higley
Gregory Higley

Reputation: 16558

When you redefine a word that's defined in system/words, you should redefine it exactly. The set word has two refinements: /pad and /any that your redefinition should also include:

cloneset: :set
set: func [
    word [word! block!]
    value
    /any
    /pad
][
    either all [word? word list? get word] [
        throw make error! "List is immutable!"
    ][
        comment {
           At this point you'll have to forward the arguments and refinements
           of your SET method to CLONESET. This will be made much easier in R3
           with the new APPLY function.
        }
    ]
]

(I have not tested the above code at all. It should be regarded as pseudocode.)

Upvotes: 6

Related Questions