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

Dynamically Modifying objects!

 [1/7] from: edanaii:cox at: 21-Feb-2003 16:03


All, About a month ago, I asked if it were possible to dynamically modify an object. I got various answers, all good, btw, but all indicating that it is not a built-in part of the language. I decided to revisit the problem and here is my solution. ====================================================================== REBOL [ File: %Malleable.r Date: 20-Feb-2003/15:44:54-7:00 Title: "Make Malleable Object" Name: "Malleable Object" Version: 1 Author: "Ed Dana" Usage: {* Create - Test: Make Malleable! [ Name: "Will Robinson" ] * Add - Test: Test/_Add [ Status: "Lost in Space" ] * Remove - Test: Test/_Remove [ 'Status ] * Display- Test/_Data } Purpose: "Allows data do be added to an object dynamically." Type: 'Misc ] Malleable!: make object! [ _Add: func [Data [block!]][ Make Self Data ] _Class: 'Malleable _Data: func [/Local Blk Str][ Blk: Make Block! 0 ForEach Item Next First Self [ Str: To-String Item If Str/1 <> #"_" [ Append Blk Item ] ] ] _Remove: func [Minus [word! block!] /Local Str][ If Type? Minus = 'Word [Minus: To-Block Minus] Str: Make String! 0 ForEach Item Self/_Data [ If Not Find Minus Item [ Str: Rejoin [Str " " Item ": " Mold Get In Self Item] ] ] Make Malleable! To-Block Str ] ] ====================================================================== It works as follows: --> Create <--
>> Contact: Make Malleable! [ Name: "Fred Flintstone" ] >> Contact/_Data
== [Name]
>> Contact/Name
== "Fred Flintstone" --> Add <--
>> Contact: Contact/_Add [ Address: "32 E. Deer Trail" Status:
Hanna-Barbaric Phone: "Shout!" ]
>> Contact/_Data
== [Name Address Status Phone]
>> Contact/Name
== "Fred Flintstone"
>> Contact/Address
== "32 E. Deer Trail"
>> Contact/Status
== "Hanna-Barbaric"
>> Contact/Phone
== "Shout!" --> Remove <--
>> Contact: Contact/_Remove 'Status >> Contact/_Data
== [Name Address Phone]
>> Contact/Status
** Script Error: Invalid path value: Status ** Near: Contact/Status Feel free to question, comment, criticize or even offer tips. :) -- Sincerely, | We're Human Beings, with the blood of a million Ed Dana | savage years on our hands! But we can stop it! We Software Developer | can admit we're killers, but we're not going to 1Ghz Athlon Amiga | kill today. That's all it takes! Knowing that we're | not going to kill... Today! -- Shatner, Star Trek.

 [2/7] from: joel:neely:fedex at: 21-Feb-2003 18:41


Hi, Ed, Your approach doesn't dynamically modify an object. It packages up a way to create a *new* object based on modifying the previous one. To see that this is true, consider this transcript:
>> contact: make malleable! [name: "Fred Flintstone"] >> contact/_data
== [name]
>> contact/name
== "Fred Flintstone" Thus far I followed your example, but let's add one new step here:
>> customer: contact
so that we now have another reference to the original CONTACT object via a different word. Now continuing with the exploration:
>> contact: contact/_add [address: "32 E. Deer Trail"] >> contact/_data
== [name address]
>> contact/address
== "32 E. Deer Trail" However, we didn't *modify* the object referenced by CONTACT; we just made a new object and set CONTACT to that new object. If we use the other reference, we see that fact, because the ADDRESS attribute is only in the *new* object, not added to the original:
>> customer/_data
== [name]
>> customer/address
** Script Error: Invalid path value: address ** Where: halt-view ** Near: customer/address The only way to get shared mutations that I can think of right now would be something like the following, which explicitly manages the sharing: mutable-thing: make object! [ shared: make object! [] add: func [etc [block!]] [shared: make shared etc] data: func [/local pub] [ pub: copy [] foreach item next first shared [ insert tail pub item ] pub ] remove: func [gone [word! block!] /local spec] [ if word? gone [gone: to-block gone] spec: copy "" foreach item data [ if none? find gone item [ insert tail spec reduce [ " " mold to-set-word item mold get in self item ] ] ] shared: make object! to-block spec ] new: func [sharable [object!]] [ make self [shared: sharable] ] ] This could be used as follows, passing an object for the sharable content...
>> contact: mutable-thing/new make object! [
[ name: "Fred Flintstone" [ ] ...then explicitly inserting /SHARED into the path to deal with attributes of that content.
>> contact/shared/name
== "Fred Flintstone"
>> contact/shared/name: "Fred X. Flintstone"
== "Fred X. Flintstone"
>> contact/shared/name
== "Fred X. Flintstone" The DATA method gives the attribute list, as in your version:
>> contact/data
== [name] and the ADD method allows insertion of new attributes, but the new object is the SHARED content of the wrapper object, not a replacement for the wrapper:
>> contact/add [address: "123 Stone Circle"] >> contact/data
== [name address]
>> contact/shared/address
== "123 Stone Circle" We can see this by creating another reference to the wrapper, then using it to modify the content object:
>> customer: contact >> customer/add [wife: "Betty"]
after which the original reference (to the wrapper) also allows access to the modified sub-object:
>> contact/data
== [name address wife]
>> contact/shared/wife
== "Betty" Hmmmmmm... I probably should have called SHARED something else, if the enclosed object is going to have a WIFE attribute!! ;-) HTH! -jn- -- ---------------------------------------------------------------------- Joel Neely joelDOTneelyATfedexDOTcom 901-263-4446 Counting lines of code is to software development as counting bricks is to urban development.

 [3/7] from: edanaii:cox at: 22-Feb-2003 7:34


Joel Neely wrote:
>Hi, Ed, > >Your approach doesn't dynamically modify an object. It packages >up a way to create a *new* object based on modifying the previous >one. To see that this is true, consider this transcript: >
Yes, I know. I never said otherwise. I merely stated that this was my solution to the "problem". For all intents and purposes, the object is dynamic. Maybe not in the truest sense of the word, but certainly enough to achieve my goals.
>Thus far I followed your example, but let's add one new step here: > >> customer: contact
<<quoted lines omitted: 15>>
> ** Where: halt-view > ** Near: customer/address
This was never my intention. I didn't want attributes shared between parent and child dynamically. I wanted the ability to add and remove attributes from the currently instantiated object. And my approach was to model it as closely as possible to how REBOL normally does it.
>The only way to get shared mutations that I can think of right now >would be something like the following, which explicitly manages >the sharing: >
[Snip, example of dynamic inheritance]
>after which the original reference (to the wrapper) also allows >access to the modified sub-object: > > >> contact/data > == [name address wife] > >> contact/shared/wife > == "Betty" >
Very nice. :)
>Hmmmmmm... I probably should have called SHARED something else, if >the enclosed object is going to have a WIFE attribute!! ;-) >
Maybe you should have named it Swinger/Shared/Wife. =) -- Sincerely, | Ed Dana | Faith is believing what you know ain't so. Software Developer | -- Mark Twain 1Ghz Athlon Amiga |

 [4/7] from: joel:neely:fedex at: 22-Feb-2003 11:59


Hi, Ed, Ed Dana wrote:
>... I merely stated that this was my solution to the "problem". > > For all intents and purposes, the object is dynamic. > Maybe not in the truest sense of the word, but certainly enough > to achieve my goals. >
Apparently I didn't understand understand your goals. Sorry.
> This was never my intention. I didn't want attributes shared > between parent and child dynamically... > > I wanted the ability to add and remove attributes from the > currently instantiated object. >
I'm not clear on what you mean by "parent" and "child", but here's what I was trying to address:
>> dee: make object! [firstname: "Tweedle"] >> dum: dee >> dee/firstname: "Twaddle"
== "Twaddle"
>> dum/firstname
== "Twaddle" There's only one object here. There just happen to be multiple words that refer to it. Any changes to the one object are visible via any way we can access it. This is different from
>> dee: make object! [firstname: "Tweedle"] >> dum: dee >> dee: make dee [middlename: "Xavier"] >> dum/middlename
** Script Error: Invalid path value: middlename ** Near: dum/middlename where "the currently instantiated object" isn't changed at all, but a new object is constructed and one of the words is set to refer to that new one. If your goals are such that you always have a single specific word (or some other distinguished reference) that you're using, and never have to e.g. pass as an argument to a function, keep up with via a reference in a block, etc. then by all means, ignore the suggestion for an extra layer. -jn- PS: Another way to use multiple reference capability using your implementation would be simply stick the (replaceable) object into a block, and hand around references to the block, as in:
>> contact: reduce [make malleable! [name: "Fred Flintstone"]]
== [ make object! [ _Add: func [Data [block!]][ Make Self Data ] _Class: 'Malleable ...
>> contact/1/_data
== [name]
>> customer: contact
== [ make object! [ _Add: func [Data [block!]][ Make Self Data ] _Class: 'Malleable ...
>> change contact contact/1/_add [address: "001 Shale Slope"]
== []
>> customer/1/_data
== [name address] Of course, this depends on the convention of unwrapping one layer of reference, so there's not much gain...

 [5/7] from: edanaii:cox at: 22-Feb-2003 13:50


Joel Neely wrote:
>Hi, Ed, >Ed Dana wrote:
<<quoted lines omitted: 7>>
>> >Apparently I didn't understand understand your goals. Sorry.
No big whoop, really. :)
>>This was never my intention. I didn't want attributes shared >>between parent and child dynamically...
<<quoted lines omitted: 6>>
>I'm not clear on what you mean by "parent" and "child", but here's >what I was trying to address:
Inheritance. You're original example allowed you to create a parent, create the child, assign a new attribute to the child which is then owned by the parent as well. Dynamic Inheritance, to be exact.
> >> dee: make object! [firstname: "Tweedle"] > >> dum: dee
<<quoted lines omitted: 19>>
>via a reference in a block, etc. then by all means, ignore the >suggestion for an extra layer.
My goal was simply to add and remove attributes from an object. Create a new object based on the parent, and then add and remove attributes from that object. Both separate and distinct from one another, but mutable. The object is used as a parent for a class called Parameter! which is then used to provide data to html in name/value pairs. -- Sincerely, | Cold Hearted Orb, that rules the night. Removes Ed Dana | the colours from our sight! Red is gray and Software Developer | yellow white! But we decide which is right... 1Ghz Athlon Amiga | And which is an illusion! | -- The Moody Blues, Late Lament.

 [6/7] from: antonr:iinet:au at: 23-Feb-2003 14:03


Ed, As I found out recently, you can use the path notation to reference into blocks as well as into objects. It's not as fast, but blocks are more flexible, and allow you to add and remove elements, which is what you want:
>> blk: [name "anton" language "rebol"]
== [name "anton" language "rebol"]
>> blk/name
== "anton"
>> blk/language
== "rebol"
>> append blk [country "australia"]
== [name "anton" language "rebol" country "australia"] etc. Anton.

 [7/7] from: edanaii::cox::net at: 23-Feb-2003 8:03


Anton wrote:
>Ed, >As I found out recently, you can use the path
<<quoted lines omitted: 11>>
> == [name "anton" language "rebol" country "australia"] > etc.
Well, I'll be dipped... :) I didn't know you could do that. Thanks for the tip. -- Sincerely, | The problems of two little people don't amount to Ed Dana | a hill of beans in this crazy mixed-up world! But Software Developer | this is OUR hill, and these are OUR beans! 1Ghz Athlon Amiga | -- Leslie Neilson, Naked Gun (Casablanca).

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