[self-interest] Saving objects with Hackney

Russell Allen mail at russell-allen.com
Tue Jan 4 09:45:59 UTC 2011


I cleaned up my code a little. Have a look at the serialisation category in defaultBehavior and the transporter hackney object.

Objects can define their own test for inclusion in their object graph by implementing the 'hackneyFitnessTest:' method.

- Russell



For fun, here is the transporter hackney object as rendered by itself:

> (|{ 'ModuleInfo: Creator: globals transporter hackney.\n' }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlotVisibility: public'
>         fromFile: n = ( | f. s |
>             f: os_file openForReading: n.
>             s: f contents.
>             f close.
>             fromString: s).
>         }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlotVisibility: public'
>         fromString: s = ( reader copy read: s).
>         }
>         { 'Category: serializationModuleInfo: Module: hackney InitialContents: FollowSlot'
>         hackneyFitnessTest: m = ( 
>             (m = reflect: printer)   ifTrue: [^ true].
>             (m = reflect: reader)    ifTrue: [^ true].
>             (m = reflect: registrar) ifTrue: [^ true].
> 
>             m creatorPathIfPresent: [m creatorPath == nullPath] 
>                           IfAbsent: [m isMorph && [m morphTypeName = 'worldMorph'] ]
>         ).
>         }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>         parent* = traits oddball.
>         }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>         printer = (|{ 'ModuleInfo: Creator: globals transporter hackney printer.\n' }
>                 { 'ModuleInfo: Module: hackney InitialContents: InitializeToExpression: (())'
>                 alreadyPrinted <- nil.
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 cleanAnnotation: a = ( (a replace: '\n' With: '\\n') replace: '\'' With: '\\\'').
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 defaultFitnessTest: o = ( 
>                     m creatorPathIfPresent: [m creatorPath == nullPath] 
>                                   IfAbsent: [m isMorph && [m morphTypeName = 'worldMorph'] ]
>                 ).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlotVisibility: private'
>                 hackneyFitnessTest: o = ( 
>                     root = o ifTrue: [^ true].
>                     (root lookupKey: 'hackneyFitnessTest:') isEmpty
>                       ifTrue: [defaultFitnessTest: o]
>                        False: [root reflectee hackneyFitnessTest: o]).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 indent: i = ( 0 to: i Do: [output: output, '        ']).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: InitializeToExpression: (\'\')'
>                 output <- ''.
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 parent* = traits clonable.
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 print = ( 
>                     alreadyPrinted: dictionary copy.
>                     printObj: root Named: '' Indent: 0.
>                     output).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlotVisibility: public'
>                 printAll: o = ( root: reflect: o. print).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 printCoreSlot: s Named: n Indent: i = ( 
>                     indent: i.
>                     output: output, s longerKeyWithAssigner, ' '.
>                     printObj: s value Named: (n, ' ', s key) Indent: i + 1).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 printObj: r Named: n Indent: i = ( | a |
>                     "We treat these as unique in Self"
>                     r isReflecteeInteger ifTrue: [
>                       output: output, r reflectee printString, '.\n'. ^ self ].
>                     r isReflecteeMethod ifTrue: [
>                       output: output, (r evalName indent: i * 8) shrinkwrapped, '.\n'.  
>                       ^ self ].
> 
>                     "Is this outside object?"
>                     (hackneyFitnessTest: r) ifFalse: [
>                       output: output, r evalName, '.\n'. ^ self ].
> 
>                     "Have we been here before?"
>                     (alreadyPrinted includesKey: r) ifTrue: [
>                       output: output, '(| r* = transporter carrier registrar. v = \'', (alreadyPrinted at: r), '\'|).\n'. ^self ].
> 
>                     "No? Then let's begin"
>                     alreadyPrinted at: r Put: n. 
>                     r isReflecteeString ifTrue: [ 
>                       output: output, '\'', r reflectee escaped, '\'.\n'.
>                       ^ self ].
>                     r isReflecteeVector ifTrue: [| rs |
>                       rs: (r reflecteeSizeIfFail: [error: 'Unknown vector size']).
>                       0 to: rs - 1 Do: [ output: output, '(' ].
>                       output: output, '(vector copySize: ', rs asString, '\n'.
>                       0 to: rs - 1 Do: [|:vi |
>                         indent: i.
>                         output: output, ') at: ', vi asString, ' Put: '.
>                         printObj: (r reflecteeMirrorAt: vi IfFail: [error: 'Huh?']) value Named: n Indent: i + 1.
>                         ].
>                       indent: i.
>                       output: output, ') asVector.\n'.
>                       ^ self].
> 
>                     "We are a simple list of slots, like we should be"
>                     output: output, '(|'. 
>                       a: cleanAnnotation: (r annotationIfFail: '') asString.
>                       a == '' ifTrue: [output: output, '\n'] False: [output: output, '{ \'', a, '\' }\n'].
>                       r do: [| :e | printSlot: e Named: n Indent: i].
>                     output: output, ('|).\n' indent: i * 8)).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 printSlot: s Named: n Indent: i = ( | a |
>                     s isAssignment ifFalse: [
>                       a: cleanAnnotation: ((s annotationIfFail: [ ^ printCoreSlot: s Named: n Indent: i ]) asString).
>                       a = '' ifTrue: [ ^ printCoreSlot: s Named: n Indent: i ].
>                       indent: i.
>                       output: output, '{ \'', a, '\'\n'.
>                       printCoreSlot: s Named: n Indent: i.
>                       indent: i.
>                       output: output, '}\n'.
>                     ]).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: InitializeToExpression: (nil.)'
>                 root <- nil.
>                 }
>         |).
>         }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>         reader = (|{ 'ModuleInfo: Creator: globals transporter hackney reader.\n' }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 constructInternalReferences = ( | e |
>                     e: enumerating references copy filterBlock: [|:r| r includesKey: 'r' ].
>                     (e enumerate: reflect: transporter hackney registrar) 
>                       do: [|:r. no | 
>                         no: (r holder reflectee v evalInContext: (reflect: o) FileName: '<eval>').
>                         r holder define: (reflect: no).
>                     ]).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: InitializeToExpression: (())'
>                 o <- 0 _AsObject.
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 parent* = traits clonable.
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 parseObject = ( o: s eval).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>                 read: st = ( 
>                     s: st copy. 
>                     parseObject.
>                     constructInternalReferences.
>                     o).
>                 }
>                 { 'ModuleInfo: Module: hackney InitialContents: InitializeToExpression: (\'\')'
>                 s <- ''.
>                 }
>         |).
>         }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlot'
>         registrar = (|{ 'ModuleInfo: Creator: globals transporter hackney registrar.\n' }
>         |).
>         }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlotVisibility: public'
>         save: o As: n = ( | f |
>             f: os_file openForWriting: n.
>             f write: toString: o.
>             f close).
>         }
>         { 'ModuleInfo: Module: hackney InitialContents: FollowSlotVisibility: public'
>         toString: o = ( printer copy printAll: o).
>         }
> |).



On 04/01/2011, at 10:18 AM, Russell Allen wrote:

> 
> Sorry, being opaque :)
> 
> It's a reference to http://www.erights.org/   http://en.wikipedia.org/wiki/E_(programming_language)
> 
> Croquet's Islands are a sort of Smalltalk derivative.
> 
> On 04/01/2011, at 9:00 AM, Josh Flowers wrote:
> 
>>  
>> 
>> Quick question as I digest this - what's E Vat niceness?
>> 
>>> 
>>> 
>>> The VM holds references to a number of objects in the system. From http://docs.selflanguage.org/vmref.html#the-initial-self-world this includes nil, true, false, prototype string, mirrors etc.
>>> 
>>> This complicates having completely separate worlds living in the one vm. For example, if you read from stdin the vm has to create a string object representing the input. To do this, it needs to know what a string is - this makes it tricky if there are multiple worlds all with different implementations of string (say one with unicode, one without etc)
>>> 
>>> I'd love separate lobbies because we could possibly get some of the E Vat niceness, but as it stands the single world seems to be a natural level of granularity in Self.  
>>> 
>>> One way forward would be to make a really nice IPC mechanism and run different worlds in different VMs.  Share nothing, message pass between them. This gets us multicore of sorts. We've got tonnes of memory in modern systems.
>>> 
>>> Alternatively, create a kernel world which intermediates between the VM and the subworlds. Like L4 microkernels, the subworlds only access the VM primitives by sending messages to the kernel. Each subworld could register its string prototype with the kernel etc.
>>> 
>>> - Russell
>>> 
>>> On 03/01/2011, at 8:43 AM, Josh Flowers wrote:
>>> 
>>>> This sounds great Russell. The transporter was a point of 
>>>> unsureness when I worked on the IRC client, so I'll be looking at 
>>>> your code with interest.
>>>> 
>>>> Your e-mail brings up a question I've been pondering (when I have 
>>>> time to ponder Self) - could we load multiple snapshots into a single 
>>>> running VM? Last time I played with Squeak it had the concept of 
>>>> Projects (least that's what I think they were called) which were 
>>>> almost like separate worlds within a single VM. Is it technically 
>>>> possible to do something similar in Self? Is there anything about the 
>>>> VM that precludes having multiple, separate lobbies? Or traits? 
>>>> true's and false's?
>>>> 
>>>> > All the talk about object saving etc inspired me to throw together a rough sketch of a framework for object saving as a exercise in building stuff in Self. The code builds upon the transporter's facilities but ignores modules.
>>>> > 
>>>> > All it does is take a object root, map out the bounds of the object cluster using a fitness test, then write out the set of objects on the file in a pleasing indented manner. It more or less handles internal loops; but a nice mechanism for that depends on moving the parser from the VM into Self. It has a hardcoded limit of 1000 objects to iterate over, just to make development easier by preventing accidentally iterating over the entire image.
>>>> > 
>>>> > The current fitness test is simply whether (a) the sub-object has a creatorPath and (b) whether it is a worldMorph. Playing with this is a good illustration of Dave's point that the tricky question is where to stop!
>>>> > 
>>>> > This is a rough outline of a framework for testing stuff (in particular there aren't any tests and the code is ugly :) - it probably isn't particularly useful.
>>>> > 
>>>> > Things I missed while writing this: a streams library, a unit testing framework, a modifiable Self parser 
>>>> > 
>>>> > If you take a clean snapshot and put the attached hackney.self file in the same directory, you can load it by:
>>>> > 
>>>> > bootstrap read: 'hackney' From: ''
>>>> > 
>>>> > and then save objects as:
>>>> > 
>>>> > transporter hackney save: myObject As: fileName
>>>> > 
>>>> > and load by getting the results of:
>>>> > 
>>>> > transporter hackney read: fileName
>>>> > 
>>>> > Have fun, Russell
>>>> > 
>>>> > 
>>>> > 
>>>> > 
>>>> > ------------------------------------
>>>> > 
>>>> > Yahoo! Groups Links
>>>> > 
>>>> > 
>>>> > 
>>>> 
>>>> 
>>> 
>>> 
>>> 
>> 
>> 
> 
> 
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.selflanguage.org/pipermail/self-interest/attachments/20110104/28fecb3d/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/x-ygp-stripped
Size: 168 bytes
Desc: not available
URL: <http://lists.selflanguage.org/pipermail/self-interest/attachments/20110104/28fecb3d/attachment.bin>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.selflanguage.org/pipermail/self-interest/attachments/20110104/28fecb3d/attachment-0001.html>


More information about the Self-interest mailing list