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

How do I dynamically extend an object! instance

 [1/11] from: bobr:dprc at: 9-Sep-2000 23:50


I have an existing dataase of saved objects which I wish to add fields to (IE add words:). I probably only want to add the words if I absolutely must in order to keep size down. I also may already have added a particular word to an object instance and dont wish to overwrite the value already associated with that word. Here is what I have so far. questions follow below. object-addword: func [ { add a word only if it is not already there, returns a new instance of the object examples myobj: object-addword myobj emailaddr dbrecord: object-addword/initial dbrecord areacode 978 } o [object!] "the object to have a word added" 'w1 [any-word!] "the word to add" /initial vdef [any-type!] "provide initial value for the word" /local mb "mini block" ] [ if not find (first o) w1 [ ; try to emulate: set/any in o w1 none mb: do rejoin [ {[} :w1 {: none ]} ] o: make o mb if initial [ set/any in o w1 vdef ] ] return o ] ;-------- for discussion: - can this be written more succinctly yet not hardcode anything about the object? - can it be done without creating a new instance? - can a corresponding function for removing a word from an object be written without evaluating all the other words/elements? I have tried several arrangements for the arguments and names for the function. I have settled on object-addword rcvrobj operand - are the precedents for putting the word operand first? - since, from context, you can tell which argument is the object and which is simply a word which may need to be added to the object, why not make the function figure out which argument is which type and do the right thing regardless of how it is called? can this be coded without resorting to second-level functions? - is a better name for the function possible? I have considered 'object+ and 'object+word as potential names. Is there a precedent that I have missed? ;# mailto: [bobr--dprc--net]

 [2/11] from: agem:crosswinds at: 10-Sep-2000 15:51


not read detailed, but: if you have a: block[ key1 "data1" key2 "data2" ] .. you can say a/key1 ; -> "data1" but add new values. which hash it should be fast enough? but beware, if key & data are of same type, it may find a data as a key, giving the next key.. maybe enhancement find/skip 2 ? i use like this to extend a block, it sets new fields from config-default config: from somewhere.. config-default: [file %./unnamed files [] posis []] a: config-default forskip a 2 [if not find config first a [ append config reduce [first a second a]]] ;config updated [bobr--dprc--net] wrote on 9-Sep-2000/23:50:09-4:00

 [3/11] from: g:santilli:tiscalinet:it at: 10-Sep-2000 18:34


Hello [bobr--dprc--net]! On 10-Set-00, you wrote: b> object-addword: func [ b> { add a word only if it is not already there, b> returns a new instance of the object b> examples b> myobj: object-addword myobj emailaddr b> dbrecord: object-addword/initial dbrecord areacode b> 978 b> } I'd suggest: object-addword: func [ object [object!] 'word [word!] /initial value [any-type!] ] [ either not found? in object word [ make object reduce [to-set-word word value] ] [ object ] ]
>> probe o
make object! [ a: 1 ]
>> probe object-addword o b
make object! [ a: 1 b: none ]
>> probe object-addword/initial o b 2
make object! [ a: 1 b: 2 ]
>> probe object-addword/initial o a 2
make object! [ a: 1 ] b> - can it be done without creating a new instance? I'm afraid not, with the current implemenation of REBOL. b> - can a corresponding function for removing a word b> from an object be written without evaluating b> all the other words/elements? I can only think of: remove-word: func [ object [object!] 'word [word!] /local words values ] [ if found? in object word [ words: first object values: second object object: clear [] foreach obj-word next words [ if obj-word <> word [insert object to-set-word obj-word] ] insert tail object none object: make object! object remove at values index? find words word set next bind first object in object 'self next values ] object ] HTH, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [4/11] from: whip:cs:unm at: 10-Sep-2000 11:06


Howdy Bob: I see Gabriele's message just came in with similar approach, but I'll send along mine for good measure.
> I have an existing dataase of saved objects which I wish to add > fields to (IE add words:). I probably only want to add the words if
<<quoted lines omitted: 23>>
> return o > ]
Here's my crack at it: add-obj-word: func [ "add word to object iff not already there" 'obj-word [word!] 'word [word!] /initial init /local the-obj ][ all [not object? the-obj: get obj-word make error! "No object provided." ] all [in the-obj word return the-obj] set obj-word make the-obj reduce [ to-set-word word init ] ]
> ;-------- for discussion: > - can this be written more succinctly yet not hardcode anything > about the object?
I think the above does that. Your version was more in a functional style (needed to reassign the result), mine's more side-effecty. Also, by leaving out the type specifier for the init value, we'll exclude unset! values from init.
>- can it be done without creating a new instance?
A new instance which replaces the old instance.
> - can a corresponding function for removing a word from an object be > written without evaluating all the other words/elements?
I can't think of how with out remaking the object minus that word: remove-obj-word: func ["remove word from object iff there" 'obj-word [word!] 'word [word!] /local the-obj words-in-obj vals-in-obj new-body ][ all [not object? the-obj: get obj-word make error! "No object provided." ] if not in the-obj word [return the-obj] words-in-obj: next first the-obj vals-in-obj: next second the-obj new-body: copy [] foreach w words-in-obj [ if word <> w [ append new-body reduce [to-set-word w vals-in-obj/1] ] vals-in-obj: next vals-in-obj ] set obj-word make object! new-body ] Here's a hacky approach that will fail for removing words that don't point to simple datatypes: r-o-w: func [ 'obj-word [word!] 'word [word!] /local the-obj words-in-obj vals-in-obj new-body ][ all [not object? the-obj: get obj-word make error! "No object provided." ] if not in the-obj word [return the-obj] new-body: third load mold the-obj ;-yuck remove/part find new-body to-set-word word 2 set obj-word make object! new-body ] Above should fail if you try to remove an object word that refers to another object, for instance. That's the perils of doing your metalevel work through string manipulation -- so I happily disavow the above.
> I have tried several arrangements for the arguments and names for > the function. I have settled on > object-addword rcvrobj operand > - are the precedents for putting the word operand first?
The typical REBOL parameter arrangement is that which is operated on followed by the things to operate on it with.
> - since, from context, you can tell which argument is the object > and which is simply a word which may need to be added to the object, > why not make the function figure out which argument is which type > and do the right thing regardless of how it is called?
Makes for a candy machine interface, IMHO.
> can this be > coded without resorting to second-level functions?
Sure.
> - is a better name for the function possible? I have considered > 'object+ and 'object+word as potential names. Is there a precedent > that I have missed?
The REBOL naming style suggests verb noun. do-thing, remove-thing. -jeff

 [5/11] from: lmecir::geocities::com at: 10-Sep-2000 21:09


Hi bobr, you wrote:
> I have an existing dataase > of saved objects which I wish to add fields to (IE add words:).
<<quoted lines omitted: 29>>
> - can this be written more succinctly yet not hardcode > anything about the object?
I would suggest the following: object-addword: func [ { add a word only if it is not already there, returns a new instance of object examples myobj: object-addword myobj emailaddr dbrecord: object-addword/initial dbrecord areacode 978 } o [object!] "the object to have a word added" ; I prefer not to use unevaluated/fetched arguments w1 [word!] "the word to add" /initial vdef [any-type!] "provide initial value for the word" ] [ if not find (first o) w1 [ o: make o reduce [to set-word! w1 none] ; because you declared vdef to be any-type!, this is the only way to set it error? set/any in o w1 get/any 'vdef ] return o ] Example:
>> probe object-addword/initial make object! [] 'a ()
make object! [ a: unset ] The problem is, that even this is not general enough, as is explained below
> - can it be done without creating a new instance?
No.
> - can a corresponding function for removing a word > from an object be written without evaluating > all the other words/elements?
The general answer is no, IMHO, only special cases can be solved. There are two problems: 1. 'Self can be any-type! in Rebol. 2. There are problems with "complicated" datatypes, eg. functions
> I have tried several arrangements for the arguments > and names for the function. I have settled on
<<quoted lines omitted: 7>>
> regardless of how it is called? > can this be coded without resorting to second-level functions?
It is feasible, if you don't use unevaluated arguments: object-addword: func [ [catch] o [object! word!] w [object! word!] ] [ if word? o [ set [o w] reduce [w o] ] if not object? o [ throw make error! reduce ['script 'expect-arg 'object-addword 'o object!] ] if not word? w [ throw make error! reduce ['script 'expect-arg 'object-addword 'w word!] ] ; ... ]

 [6/11] from: bobr:dprc at: 12-Sep-2000 19:07


At 09:09 PM 9/10/00 +0200, [lmecir--geocities--com] wrote:
>Hi bobr, >> - can it be done without creating a new instance? > >No.
ok here is my latest method for extending an object in-situ. the example hasnt been turned into a function and I hope I am not violating any storage but here goes... [ a: make object! [ addr: "417 howser st" name: "joyce haversham" ] wds: first a vals: second a append wds 'email append vals "[joyce--someplace]" probe a ] now this -looks- fine, you can save/probe/mold the object and read it back in with no problems. best of all no new object is instantiated so all references to a are updated as well. for some reason you cannot access the new items by a path. as soon as you type a/email there is an error. remove seems to be just as simple but I think I will stay away from it till I know exactly is going on with a/email and why the path doesnt work before I drop something out of the middle. ;# mailto: [bobr--dprc--net]

 [7/11] from: jeff:rebol at: 12-Sep-2000 15:42


Bob:
> ok here is my latest method for extending an object > in-situ. the example hasnt been turned into a function and
<<quoted lines omitted: 7>>
> now this -looks- fine, you can save/probe/mold the object > and read it back in with no problems.
FIRST obj and SECOND obj have returned copies of the object word and value blocks since last year or so. Modifying those blocks will not affect the original object. -jeff

 [8/11] from: bobr:dprc at: 13-Sep-2000 0:05


At 03:42 PM 9/12/00 -0700, [jeff--rebol--net] wrote:
> Bob: >> ok here is my latest method for extending an object
<<quoted lines omitted: 17>>
> word and value blocks since last year or so. Modifying > those blocks will not affect the original object.
Rats, I knew it was too good to be true! I see in current version 'save, 'mold and 'probe all use the real values not the copies. So this used-to-work but for reasons of our own protection has been made unworkable? perhaps I should try another track... most object based systems try to respect that an object should resist external change and only undergo transformation when initiated from within. you cant change an object unless it wants to change {reminds me of an old light bulb joke} or provides an access method to facilitate the change. can a function be made (within the object) that self-extends the object? what would that function look like?
> -jeff >
;# mailto: [bobr--dprc--net]

 [9/11] from: jeff:rebol at: 12-Sep-2000 21:17


> So this used-to-work but for reasons of our own protection > has been made unworkable?
Right, what happens if you remove one of the values from the middle of the value block? Do all the other words now point to new values? What does the word at the end point at? Likewise, adding a new word without a corresponding value.
> perhaps I should try another track...
Are you opposed to using blocks inside objects?
> most object based > systems try to respect that an object should resist
<<quoted lines omitted: 5>>
> self-extends the object? what would that function look > like?
Yes, using blocks. obj: make object! [ a: [b: 2] ] obj/a/b: 4 obj/a/b == 4 append obj/a [c 6] obj/a/c == 6 etc.. If you were sadistic, you might use self modifying functions. Here's a rather counter intuitive way to add and remove refinements from an object: fobj: make object! [ p-words: [] path: func refs: [/add what /remove who] body: [ either add [ path: func head insert refs to-refinement what body append p-words what ][ either remove [ system/words/remove find p-words who system/words/remove find refs to-refinement who path: func refs body ][ foreach item bind p-words 'add [ print [item "==" get item] ] ] ] ] ] fobj/add 'a fobj/add 'b fobj/remove 'a Of course this isn't that much different from using blocks, though, and you still have to add logic in the body of the function to act on the activation of different refinements. Blocks are a much better and simpler way to go. -jeff

 [10/11] from: lmecir:geocities at: 13-Sep-2000 7:48


Hi bobr, what are the results of the code below and which version of Rebol you use? -Ladislav

 [11/11] from: bobr:dprc at: 13-Sep-2000 12:16


At 07:48 AM 9/13/00 +0200, [lmecir--geocities--com] wrote:
>Hi bobr, > >what are the results of the code below and which version of Rebol you use? > >-Ladislav
we have a "production" version 2.1.2.3.1 in which this works (except for the error below). [ a: make object! [ addr: "417 howser st" name: "joyce haversham" ] d: make object! [ user: a ] ; now modify in-place wds: first a vals: second a append wds 'email append vals "[joyce--someplace]" print mold d ; works yay! save %mytmp a ; works probe a ; works b: make a ; works and retains new fields (but these too are inaccessable via b/email path method ) print a/email ; fails ] that is, after the words are modified (append/remove) all references to the object are also changed in place without creating a new object. this works good for us. however paths referring to the new words in the object dont work unless the object is saved and reinstantiated (save/load) or unless a new object is made which violates the in-place ideal. so for now, if we want to create a new path/word into an object and we must use the new paths right away then we have to live with creating a new instance of the object. to minimize the effect on running system maint we try to add words to an object just after loading it before anythisg else (another object) has had a chance to attach to it. [ fileloaded: %dbrecords/u0012 tmp: do load fileloaded ; load a single record if anyfieldsmissing [ tmp: object-addword/initial tmp resave-as fileloaded tmp: object-addword/initial tmp name "?name" ; should already be present tmp: object-addword/initial tmp addr "?street addr" ; should already be present tmp: object-addword/initial tmp phone "011 978 555 1212" tmp: object-addword/initial tmp county "maui" tmp: object-addword/initial tmp email "[*--*--*][.*]" ] append in-memeory-records tmp ; attach to in-system lists ; from here on all sorts of things attach to this puppie ] it will be a corporate decision wether we upgrade to a newer version which does not support inplace mods to the fields (words) of a record. depends on the return on investment for the re-engineering work.
>> At 09:09 PM 9/10/00 +0200, [lmecir--geocities--com] wrote: >> >Hi bobr,
<<quoted lines omitted: 43>>
>> >>
;# mailto: [bobr--dprc--net]

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted