Object lesson, please?
[1/5] from: SunandaDH::aol::com at: 23-Oct-2003 11:19
I need a function that expands an object to add extra fields.
So I've written one. See below. From an engineering perspective, it works
fine. From a REBOL elegance viewpoint that "return do mold obj" goes clunk in
my brain. Is there a better way?
A bit of background....I got a system that holds persistent data as molded
objects in files. I need to add fields that weren't dreamt of in the initial
release. But I don't need to worry about circular references or the object being
referenced elsewhere.
The simplest solution is to apply a template of all possible fields to an
object each time we read it.
The function below is intended to do that.
The "return do mold obj" seems necessary to stop inner objects that aren't in
the original being the 'same? as the template object.
How can I do this more elegantly, please?
;;========== the function ==========
Rebol []
update-object: func [obj [object!]
template [object!]
/local
]
[
foreach field next first template
[
if error? try [obj/:field]
[
obj: construct/with reduce [to-set-word field template/:field]
obj
]
if object? template/:field
[
obj: construct/with reduce [to-set-word field update-object
obj/:field template/:field] obj
]
] ;; for
return do mold obj ;; added objects are independent beings.
;;;;return obj ;; added objects are the 'same? as template
] ;; func
;; ========== Some test data data ==========
test-template: make object! [
a1: "initial data value"
a2: "not in test object"
a3: make object!
[
a3-1: 1-oct-2003
a3-2: make object!
[a3-2-1: "sss"
a3-2-2: "also not in test object"
]
a3-3: "rebol [halt]" ;; dangerous value if loaded
a3-4: reduce [now/precise]
]
a4: make object! [] ;; empty object -- not in test
a5: make object! [a5-1: a5-2: a5-3: true]
a6: a7: a8: none
a9: make object! [a9-1: a9-2: a9-3: false]
]
test-object: make object! [
a1: "got a value"
a3: make object!
[a3-1: false
a3-2: make object!
[a3-2-1: "also got a value"
]
]
]
loop 10 [print ""]
res1: update-object test-object test-template
wait 0.1 ;; see if nows cause a problem -- they shouldn't in this case
res2: update-object res1 test-template
print "test failure messages follow...."
if strict-not-equal? mold res1 mold res2
[Print "Something didn't work"]
if same? res1/a4 test-template/a4
[print "we've got cloning!"]
if same? res1/a9 test-template/a9
[print "we've got cloning!"]
====================
Thanks!
Sunanda
[2/5] from: g:santilli:tiscalinet:it at: 23-Oct-2003 17:53
Hi SunandaDH,
On Thursday, October 23, 2003, 5:19:47 PM, you wrote:
Sac> I need a function that expands an object to add extra fields.
Just some quick notes...
1. you can do this:
>> original: context [a: 1 b: 2]
>> template: context [a: b: c: none]
>> probe changed: make template original
make object! [
a: 1
b: 2
c: none
]
to update the original object based on a template.
2. you could just recursively apply this function to all the
sub-objects... this way you get a copy of all the objects so you
won't need the mold anymore.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[3/5] from: SunandaDH:aol at: 24-Oct-2003 4:34
Gabriele:
> 1. you can do this:
>
> >> original: context [a: 1 b: 2]
> >> template: context [a: b: c: none]
> >> probe changed: make template original
Thanks, Gabriele. The one thing I hadn't thought of trying was context -- the
word had slipped from my mental context.
I had to change the code around as context takes a block, not an object --
hence the the "content third xxx" to grab the block inside the object.
But even then a simple conversion of the code didn't work -- I ended up with
inner objects still being cloned.
I've had to do a copy/deep of the originals to break the cloning. That's
almost as unsatisfactory as the original code. Here's the latest version, with a
simpler set of test data:
;;========== the function ==========
Rebol []
update-object: func [obj [object!]
template [object!]
/local
obj-copy
template-copy
]
[
obj-copy: make object! copy/deep third obj
template-copy: make object! copy/deep third template
foreach field next first template-copy
[
;; add a field if it doesn't exist
if error? try [obj-copy/:field]
[
obj-copy: context join third obj-copy
[to-set-word field template-copy/:field]
]
;; recurse adding fields if field is an object
if object? template-copy/:field
[
obj-copy: context join third obj-copy
[to-set-word field update-object obj-copy/:field
template-copy/:field]
]
] ;; for
return obj-copy ;; no more do mold !
] ;; func
;; ========== Some test data data ==========
original-object: make object! []
template: make object! [a: make object! [b: 1]]
new-object1: update-object original-object template
new-object2: update-object original-object new-object1
print "status messages follow -- all say true if it's worked"
print not same? new-object1/a template/a
print not same? new-object1/a new-object2/a
print equal? mold new-object1 mold new-object2
=============
Sunanda.
[4/5] from: g:santilli:tiscalinet:it at: 24-Oct-2003 11:20
Hi SunandaDH,
On Friday, October 24, 2003, 10:34:39 AM, you wrote:
Sac> Thanks, Gabriele. The one thing I hadn't thought of trying was context -- the
Sac> word had slipped from my mental context.
It is just a shortcut for MAKE OBJECT!... What I wanted to point
out was that you could just use MAKE to update your object.
I.e. (QAD):
update-object: func [obj template] [
obj: make template obj
foreach word next first obj [
if all [object? get in obj word in template word object? get in template word] [
set in obj word update-object get in obj word get in template word
]
]
obj
]
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[5/5] from: nitsch-lists:netcologne at: 24-Oct-2003 16:51
with inner objects i would go with your
do mold object
it has the additional advantage that it checks your data for moldability.
today its prety reliable, but in the old days a bad string could break it.
when i stored data to disk, i checked them that way, instead of saving broken
data.
either attempt[do mold data][save %file data][alert "Internal error"]
So doing it more often may help stability.
-Volker
Am Freitag, 24. Oktober 2003 10:34 schrieb [SunandaDH--aol--com]: