Howdy,
I have some Smalltalk objects that represent external data and I am looking for a neat way to access them. The data that I am dealing with is C binary objects described by DWARF schemas. So I will load a type declaration like this: struct outer { struct inner { int a, b; }; }; and then I will want to be able to write convenient expressions like: aStruct outer inner a + aStruct outer inner b I have implemented this already but I am not sure that I took the right approach. I have implemented these accessors like #outer #inner #a #b via a messageNotUnderstood: method that looks into the object, so that 'aStruct outer' is equivalent to 'aStruct field: #outer'. My concern is that the names of the C struct fields can collide with existing Smalltalk methods and then I will get totally unexpected results. Is there a canonical solution to this problem? The first idea I have is to add a bit of syntatic sugar, like to write 'aStruct _outer _inner _a' where the leading underscore avoids method name collisions and is then stripped off in messageNotUnderstood. That doesn't seem especially elegant though. I can't quite bring myself to write verbose things like ((aStruct child: #outer) child: #inner) child: #a |
On 4 December 2017 at 00:10, Luke Gorrie <[hidden email]> wrote:
> Howdy, > > I have some Smalltalk objects that represent external data and I am looking > for a neat way to access them. > > The data that I am dealing with is C binary objects described by DWARF > schemas. So I will load a type declaration like this: > > struct outer { > struct inner { > int a, b; > }; > }; > > and then I will want to be able to write convenient expressions like: > > aStruct outer inner a + aStruct outer inner b > > I have implemented this already but I am not sure that I took the right > approach. Seems like a reasonable approach, except difficulties with the broadness of your DSL domain (as you've found.) > I have implemented these accessors like #outer #inner #a #b via a > messageNotUnderstood: method that looks into the object, so that 'aStruct > outer' is equivalent to 'aStruct field: #outer'. My concern is that the > names of the C struct fields can collide with existing Smalltalk methods and > then I will get totally unexpected results. > > Is there a canonical solution to this problem? > > The first idea I have is to add a bit of syntatic sugar, like to write > 'aStruct _outer _inner _a' where the leading underscore avoids method name > collisions and is then stripped off in messageNotUnderstood. That doesn't > seem especially elegant though. > > I can't quite bring myself to write verbose things like > > ((aStruct child: #outer) child: #inner) child: #a > > An easy improvement might be to subclass your DwarfStruct from ProtoObject rather than Object to significantly reduce the surface area of name clashes. * https://github.com/pharo-project/pharo/blob/development/src/Kernel/ProtoObject.class.st But I've not worked much with ProtoObject so I'm not sure what difficulties that might bring. In particular, can anyone comment on extra requirements to support object display in GT Inspector? A naming clash with the remaining ProtoObject methods seems extremely unlikely, and the easiest path would be to just guard against loading such structs. DwarfStruct>>loadStructure ... nameClashes := ProtoObject methodNames. self fieldnames do: [ :f | (nameClashes includes: f) ifTrue: [ self error: 'Seriously!? Your trying awful hard to break me' ] ] Just for the fun of it(!?) you might even try reducing that surface area by renaming that just in your personal Images by renaming ProtoObject methods. (Actually thats any interesting experiment I'll have to try later when I've got Pharo in front of me.) The only other thing I can think of is, presuming you've got a single class (e.g. DwarfStruct) holding the structure as data. for each loaded structure, generate "DwarfStruct subclass: CStruct1" and CStruct1>>fieldname so that method lookup stops at the first class and doesn't run all the way up the class hierarchy. But that would still be susceptible to breaking the system by overloading messages critical to system operation. cheers -ben |
In reply to this post by Luke Gorrie
For proxies/wrappers, you might want to look into how the Ghost framework
interrupts sends. (I don't know the exact details, but I'd guess step 1 is subclassing ProtoObject, rather than Object) For your specific case, isn't there already a *Struct class in the image you can subclass, create a class method containing the fields definition, and then have accessors autogenerated, rather than using doesNotUnderstand:? Usually, that would make the code easier to browse/debug later on, doesn't confuse the syntax highlighter/code critic in uses of an otherwise undefined field, etc. Cheers, Henry -- Sent from: http://forum.world.st/Pharo-Smalltalk-Developers-f1294837.html |
Thanks Ben & Henrik for the ideas!
I will scratch my head a bit and then try to do something sensible. :-) |
Hi Luke, Not only for the details of a particular proxy implementation like Ghost, but also because of all the discussions around it, I think this journal paper [1] we wrote may be of help to you. Cheers, On Mon, Dec 4, 2017 at 5:51 AM, Luke Gorrie <[hidden email]> wrote:
|
Free forum by Nabble | Edit this page |