extendDynamic Languages are hot today since people now realize that static language properties are less suitable for some kind of tasks like Behavior Driven Development. Javascript Framework like Prototype has a method for extending an object, and even now static languages like C# are looking to become dynamic with extension methods.

Since Rebol is a dynamic language by design (code / data duality or Homoiconicity Property) it should be capable to do so (adding either properties or methods). Indeed that is easy as this is done by just recreating the object from himself by using inheritance.

For example, let’s say you have this User Object:


User: Make Object! [FirstName: "" Last Name ""]

You can extend User trivially with:


User: Make User [created_at: now]

Just one line !

You could think of shortening the syntax even more (you can’t find someone lazier than I am, I don’t want to type User twice or forget the “: ” as I’m always inclined to) and make it english fluent with an extend function like this:


extend user [created_at: now]

by creating this implementation


extend: func[Obj block] [
  Obj: Make Obj block
]

When testing:


User: Make Object! [FirstName: "" LastName: ""]
extend User [created_at: now]
Probe User

You realize it doesn’t work:


>> Probe User
make object! [
    FirstName: ""
    LastName: ""
]
>>

The reason is that you have passed the Object by value, to pass it by reference (see “Understanding Rebol’s Words”), you should do this:


extend: func['byRefObj Block /local Obj][
  Obj: get byRefObj
  Set byRefObj Make Obj Block
]

This time it works:


>> User: Make Object! [FirstName: "" LastName: ""]
>> extend User [created_at: now]
>> Probe User
make object! [
    FirstName: ""
    LastName: ""
    created_at: 13-Dec-2009/15:27:03+1:00
]
>>

If you want to unprotect the object and add type-safety, this is a refined version:


extend: func['byRefObj [word!] Block [block!] /local Obj][

  Obj: get byRefObj
  if/else (type? Obj) = Object! [
    Unprotect byRefObj
    Set byRefObj Make Obj Block
  ][
    print [byRefObj "is not an object." ]
  ]
]

If you want to play extend with our class and new functions, we put them below:


Class: func['Class Body [block!]][
    Type: to-word Class
    set Type Make Object! Body
    Protect Type
]

new: func[Class [Object!] Param-Block [block!]][
    Constructor: to-word pick pick Class 1 2
    Obj: Make Class []
    params: copy ""
    foreach param Param-Block [
      if string? param [
        param: rejoin [{"} param {"}]
      ]
      append params param
      append params " "
    ]
    do rejoin [{do get in Obj constructor} { } params]
    Obj
]

Future: I just realize Rebol 3 has an extend function so in Rebol I should rename the one above or override extend to have both.

Bookmark and Share