More on "embedded" objects
[1/1] 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