Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] More on "embedded" objects

From: joel::neely::fedex::com at: 15-May-2001 23:03

Hi, all, Here is a little hack that I'm sure we can improve on. It provides a way to create objects which can contain *both* features based on the present state of a prototype object *and* features based on the original state of the prototype object. For those who didn't follow the earlier thread, here's a sample of the standard mechanism:
>> ob1: make object! [
[ a: 1 [ ob11: make object! [ [ b: 10 [ wot?: func [] [a + b] [ ] [ ]
>> ob1/ob11/wot?
== 11
>> ob2: make ob1 [] >> ob2/ob11/wot?
== 11
>> ob1/a: 5
== 5
>> ob2/ob11/wot?
== 15
>> ob1/ob11/wot?
== 15 Note that OB2, being made from OB1, inherits a *reference* to OB11, rather than having its own fresh version of OB11, which means that OB2/OB11/WOT? still refers to the A of OB1, and not the A of OB2. Much virtual ink was spilled over this a few days ago. The INSTANTIATE function is offered for discussion (and improvement, quite likely knowing this list ;-). In its simple usage, it just creates objects, as in
>> ob1: instantiate [a: 1] >> source ob1
ob1: make object! [ a: 1 ]
>> ob2: instantiate ob1 >> source ob2
ob2: make object! [ a: 1 ] INSTANTIATE is just synonymous with MAKE OBJECT! until we add the /UNIQUE refinement, which takes block argument. The additional block is also used to construct the resulting object, but future instantiations get a fresh copy of the attributes specified in the /UNIQUE argument. For example, we can "fix" the original example at the beginning so that any block created from OB1 gets a "unique" OB11 that refers to its new parent.
>> ob1: instantiate/unique [
[ a: 1 [ ][ [ ob11: instantiate [ [ b: 10 [ wot?: func [] [a + b] [ ] [ ]
>> ob1/ob11/wot?
== 11
>> ob2: instantiate ob1 >> ob2/ob11/wot?
== 11
>> ob1/a: 5
== 5
>> ob2/ob11/wot?
== 11
>> ob1/ob11/wot?
== 15 Note the following changes: 1) INSTANTIATE/UNIQUE get two arguments. 2) The first argument [a: 1] behaves as a normal spec-block for object creation. 3) The second argument, appearing because of the /UNIQUE refinement, [ob11: instantiate [b: 10 wot?: func [] [a + b]]] is included in the creation of the first object, but it is flagged as something that should be unique (not shared) when subsequent objects are created. 4) When OB2 is INSTANTIATE -ed from OB1, an additional empty block is not supplied. INSTANTIATE just uses the first argument (OB1) as its specification. 5) When OB2 is created, it gets a *fresh* OB11 created just for itself, rather than sharing the one referenced by OB1. INSTANTIATE knows to do this because OB11 was included in the /UNIQUE specification for OB1. 6) Changes to OB1/A no longer affect OB2/OB11, since it was created "from scratch" for OB2. Its connection to OB1 is ignored. Another bit of transcript immediately following the above should make it clear that the two "embedded" OB11 objects are each unique to their respective "parents".
>> ob1/ob11/b: 20
== 20
>> source ob1
ob1: make object! [ a: 5 ob11: make object! [ b: 20 wot?: func [][a + b] ] ; unique: [ ob11: instantiate [ b: 10 wot?: func [] [a + b] ]] ]
>> source ob2
ob2: make object! [ a: 1 ob11: make object! [ b: 10 wot?: func [][a + b] ] ; unique: [ ob11: instantiate [ b: 10 wot?: func [] [a + b] ]] ] Notice that changing OB1/OB11/B affects only that unique embedded OB11; that change is *not* shared with OB2/OB11. Without further ado, here's the definition of INSTANTIATE. 8<---------------------------------------------------------- instantiate: func [ [catch] spec1 [block! object!] /unique spec2 [block!] /local ospec uspec uattr result ][ ospec: copy [] uspec: copy [] uattr: to-word "; unique" if all [object? spec1 found? in spec1 uattr] [ append uspec get in spec1 uattr ] if unique [ append uspec spec2 ] if 0 < length? ospec: copy/deep uspec [ append ospec reduce [to-set-word uattr 0] ] result: either object? spec1 [ make spec1 ospec ][ make object! append copy/deep spec1 ospec ] if 0 < length? uspec [ set in result uattr uspec ] result ] 8<---------------------------------------------------------- A possible future enhancement (which it's too late for me to tackle tonight) would be to add another refinement to allow sharable attribute creation when instantiating a new object from an existing object. I may take a quick look at that in the morning. Meanwhile, enjoy! And -- as always -- feedback, suggestions, corrections, etc. are welcome. -jn- ------------------------------------------------------------ Programming languages: compact, powerful, simple ... Pick any two! joel'dot'neely'at'fedex'dot'com