Hi Guys,
For some experimentation I wanted to have the ability to have *any* object act as a compiled method, so that it can be 'invoked' as if it were a function. I've just published a package for this at SqueakMap.
http://map2.squeakfoundation.org/sm/package/b6a0d3eb-1241-4e3c-b790-e1995b59 9784
From the description:
Nothing for the faint-hearted. This package is a VM modification which allows arbitrary objects to 'act' like CompiledMethods. In other words, if you want to have some object to act like a method you merely add it to the appropriate method dictionary, like in:
Object addSelector: #foo:bar: withMethod: FooBarAlgorithm.
When you now say something like:
someObject foo: 42 bar: 'mumble'.
the special message #run:with:in: will be sent to FooBarAlgorithm so you could handle it like this:
FooBarAlgorithm class>>run: originalSelector with: argsArray in: aReceiver "Run the FooBarAlgorithm when invoked via originalSelector from aReceiver. argsArray contains the arguments passed along with the original invokation."
Pretty cool, eh? Needless to say, the package requires a new VM. Without it, the supplied tests will horribly crash your system.
Cheers, - Andreas
*Very* cool. What are the performance implications?
For the 'regular' sends, zero. There is one (very cheap) test during the full (non-cached) message lookup which determines if the thing is a compiled method[*]. If it isn't, a 'special primitive' index is assigned (which later on does the actual re-invokation). The test itself takes advantage of CompiledMethod's special object format so the cost is very close to zero here - if you take the mcache hit rate into account it's exactly zero (as in: not measurable).
For the 'object invokation' itself the cost is in the range of a #perform: (as it does almost the same thing). However, due to my dirty little 'primitive trick' the 'function object' can stay in the mcache which means that in practice the performance should be pretty close to a 'regular' send.
[*] One might even argue that the test should be there to begin with since without it the VM will crash if you ever store anything but CMs in the method dictionaries.
Cheers, - Andreas
PS. It just so occured to me that going this way one might have a completely different interpreter/bytecode set running next to the current one. Even methods compiled completely to native code. Sort of like a trap. Hm...
On Sat, 17 May 2003, Andreas Raab wrote:
*Very* cool. What are the performance implications?
For the 'regular' sends, zero.
Great. Is it too early to lobby for this to be made part of the stock VM? As you point out, it enables all kinds of wonderful experimentation. (Yes, I know MethodWrappers provides very similar possibilities, but this is just so much cleaner).
A somewhat related question I've had for a long time - why is there no primitive for invoking a CompiledMethod without first installing it in a method dictionary? To keep the interfaces consistent, this could of course be used by CompiledMethod>>run:with:in:...
It seems like this might be useful to play with some optimizations like inline caches, at the Smalltalk level. But this is hardly my area of expertise.
Avi
Hi all
Yes having a primitive to directly invoke compiled methods would be really cool.
A somewhat related question I've had for a long time - why is there no primitive for invoking a CompiledMethod without first installing it in a method dictionary? To keep the interfaces consistent, this could of course be used by CompiledMethod>>run:with:in:...
Stef www.iam.unibe.ch/~ducasse/ [ | ]
Avi,
Great. Is it too early to lobby for this to be made part of the stock VM?
Personally, I feel pretty good about it. There are a couple of things that one needs to keep in mind when playing with this kind of stuff but the VM level changes itself are very small and quite obvious (well, for someone knowing her way around the VM ;)
A somewhat related question I've had for a long time - why is there no primitive for invoking a CompiledMethod without first installing it in a method dictionary?
Well, there is. At least if I understand Anthony's work on the closure compiler correctly. If I'm not mistaken then he uses CompiledMethods as representations for closures which means that he's got to have a primitive for invoking them somehow. So that you might be able to get away with wrapping a CM into a closure and just evaluate it.
To keep the interfaces consistent, this could of course be used by CompiledMethod>>run:with:in:...
It really should! Then one could use this to 'jump' from one kind of interpreter to another where the Squeak Bytecode interpreter sends #run:with:in: to any non-CompiledMethod and the IDunnoWhatInterpreter sends #run:with:in: if it encounters a CompiledMethod.
Heh, heh. I'm just starting to imagine the possibilities here and it makes me grin like a cheshire cat 8-)))
Cheers, - Andreas
On Sat, 17 May 2003, Andreas Raab wrote:
A somewhat related question I've had for a long time - why is there no primitive for invoking a CompiledMethod without first installing it in a method dictionary?
Well, there is. At least if I understand Anthony's work on the closure compiler correctly. If I'm not mistaken then he uses CompiledMethods as representations for closures which means that he's got to have a primitive for invoking them somehow. So that you might be able to get away with wrapping a CM into a closure and just evaluate it.
Ok, so let's get that primitive and your modifications into the 3.6 VM and start having fun.
It really should! Then one could use this to 'jump' from one kind of interpreter to another where the Squeak Bytecode interpreter sends #run:with:in: to any non-CompiledMethod and the IDunnoWhatInterpreter sends #run:with:in: if it encounters a CompiledMethod.
Heh, heh. I'm just starting to imagine the possibilities here and it makes me grin like a cheshire cat 8-)))
Yup :). Incidentally, does anyone know of prior art for doing that kind of jumping from VM to meta-interpreter and back, in Smalltalk or other similar (OO, bytecode) systems? There's a company doing exactly that to enable call/cc in Java, and I'm curious if their patent application has any validity.
Avi
On Sat, May 17, 2003 at 01:18:37PM -0700, Avi Bryant wrote:
Yup :). Incidentally, does anyone know of prior art for doing that kind of jumping from VM to meta-interpreter and back, in Smalltalk or other similar (OO, bytecode) systems? There's a company doing exactly that to enable call/cc in Java, and I'm curious if their patent application has any validity.
I did some experiments with smalltalk/x in this direction (playing with implementing an interpreter for Smalltalk in Smalltalk)
If I remember correctly, this worked somewhat like this:
In Smalltalk/X the vm sends "cannotInterpret" to the CompiledMethod if there are no Bytecodes in the compiledMethod. CompiledMethods are real Objects in SmalltalkX, the bytecodes are stored in a ByteArray which is referenced in a instVar of the CompiledMethod.
And so you can simply make a subclass that has an aditional instVar for your new set of bytecodes, "cannotInterpret" then would call the interpreter for these bytecodes...
Marcus
Interesting idea...
"Andreas Raab" andreas.raab@gmx.de wrote:
The test itself takes advantage of CompiledMethod's special object format so the cost is very close to zero here - if you take the mcache hit rate into account it's exactly zero (as in: not measurable).
I hope this stays true if the clean CompiledMethod stuff is used; 'twould be a pity otherwise.
[*] One might even argue that the test should be there to begin with since without it the VM will crash if you ever store anything but CMs in the method dictionaries.
I'm reasonably sure I agree with that.
PS. It just so occured to me that going this way one might have a completely different interpreter/bytecode set running next to the current one. Even methods compiled completely to native code. Sort of like a trap. Hm...
I haven't had time to look at your code and won't have time today as I have to run off to a party RealSoonNow but it sounds from your description that this is not quite what one might want for supporting a native code method facility. Sure, one could compile bytecodes to native and _replace_ the original method this way but you'd have to do some extra stuff to keep the original around (assuming you have any need for it in the future - depends on caching etc). Then again I suspect that wasn't quite what you were thinking of at the time anyway.
tim
Hi Tim,
The test itself takes advantage of CompiledMethod's special object format so the cost is very close to zero here - if you take the mcache hit rate into account it's exactly zero (as in: not measurable).
I hope this stays true if the clean CompiledMethod stuff is used; 'twould be a pity otherwise.
I'm pretty sure it would. The current test uses the format of the CM but one could equally well just compare the class - which is *slightly* slower if you start counting cycles but I'd expect this to be neglectable considering that we're in the full lookup anyways.
PS. It just so occured to me that going this way one might have a completely different interpreter/bytecode set running next to the current one. Even methods compiled completely to native code. Sort of like a trap. Hm...
I haven't had time to look at your code and won't have time today as I have to run off to a party RealSoonNow but it sounds from your description that this is not quite what one might want for supporting a native code method facility.
Oh it depends on what you're after. I could (for example) imagine that for a numeric compiler there's a 'special kind of stub' instead of the CMs which holds both on to the byte code representation as well as the native representation. Probably not what you want to do for the general case but quite powerful (and simple!) if you are looking at relatively few methods.
Sure, one could compile bytecodes to native and _replace_ the original method this way but you'd have to do some extra stuff to keep the original around (assuming you have any need for it in the future - depends on caching etc).
See above. In some situations the overhead for housekeeping is absolutely acceptable, in fact advantageous (as one could lazily switch between representations depending on the environmental factors).
Then again I suspect that wasn't quite what you were thinking of at the time anyway.
No, certainly not ;-) Actually, I was thinking about E and it's dual function/object representation. I wanted to be able to experiment along those lines.
Cheers, - Andreas
Hi,
I'm a Squeak/Smalltalk newbie with some experience of doing OO in other languages, chiefly VB (which is not at all great for that purpose) and Python (which is rather better, but not in use in my place of work), and a smattering of FP that's still not settled in my mind. I'm trying to get my head round a couple of things in Smalltalk, and the documentation I've browsed so far hasn't helped much: my queries more to do with idiom than anything else. Can anyone give me a clue as to where I might find some answers to questions like these:
* If I want to expose an instance's private fields, do I have to code accessor methods every time? Is there an alternative to writing
getFoo ^ foo
and
setFoo: newFoo foo := newFoo
over and over again?
* Is the best way to make what in C++ or Java you'd call "constructors" to write class methods that create, initialize and then return an instance, e.g.
newFooWithBar: initialBar | newFoo | newFoo := Foo new; setBar: initialBar. ^ newFoo
or is there a more concise way?
* Can I treat blocks as first-class entities, e.g. return them from methods, pass them around etc? Can I use them to implement LISP-like closures? Even if I can, is this a "natural" smalltalky way to do things?
* What about function/method pointers? Can I treat one of an instance's methods as a block, or do I have to make a new block and call the method inside that?
Finally,
* Is this list a good place to ask questions like this? If it isn't, is there a more suitable one?
thanks, Dominic
On Sun, May 18, 2003 at 12:27:41AM +0100, Dominic Fox wrote:
Hi,
I'm a Squeak/Smalltalk newbie with some experience of doing OO in other languages, chiefly VB (which is not at all great for that purpose) and Python (which is rather better, but not in use in my place of work), and a smattering of FP that's still not settled in my mind. I'm trying to get my head round a couple of things in Smalltalk, and the documentation I've browsed so far hasn't helped much: my queries more to do with idiom than anything else. Can anyone give me a clue as to where I might find some answers to questions like these:
- If I want to expose an instance's private fields, do I have to code accessor
methods every time? Is there an alternative to writing
getFoo ^ foo
and
setFoo: newFoo foo := newFoo
over and over again?
Yes, there is an alternative. If you open the Preferences browser, the "general" section has a pref named "autoAccessors" that might do what you want.
- Is the best way to make what in C++ or Java you'd call "constructors" to
write class methods that create, initialize and then return an instance, e.g.
newFooWithBar: initialBar | newFoo | newFoo := Foo new; setBar: initialBar. ^ newFoo
or is there a more concise way?
That looks about right.
- Can I treat blocks as first-class entities, e.g. return them from methods,
pass them around etc? Can I use them to implement LISP-like closures? Even if I can, is this a "natural" smalltalky way to do things?
Yes, yes, and yes. The second yes is dependent on the block closure work done by Anthony Hannan. No URL 'cause I'm in a hurry, but check the list archives for the past couple of months.
- What about function/method pointers? Can I treat one of an instance's
methods as a block, or do I have to make a new block and call the method inside that?
The latter. You might also be interested in Object>>perform:/perform:with:, and the class MessageSend.
Finally,
- Is this list a good place to ask questions like this? If it isn't, is there
a more suitable one?
This is the right place. Joshua
thanks, Dominic
- Is the best way to make what in C++ or Java you'd call "constructors" to
write class methods that create, initialize and then return an instance, e.g.
newFooWithBar: initialBar
| newFoo |
newFoo := Foo new; setBar: initialBar. ^ newFoo
or is there a more concise way?
OK, I've got this one already. ^ super new init. Had me puzzled for a while (why would I want to return a new instance of the *superclass*?) until I figured out what the superclass was the superclass *of*...
Dominic
Hi dominic
When you send the message foo to aA (instance of A)
aA foo
The message is looked up in the class of aA => A foo can be implemented in any superclass of A as Object for example.
Then the method argument receiver is bound to the actual receiver aA in our case.
Now for your question
Foo class>>newFooWithBar: initialBar
| newFoo |
newFoo := Foo new.
newFoo setBar: initialBar.
^ newFoo
the receiver of foo is a CLASS, the semantics of new is: "return an instance of the receiver"
so #new can be implemented in any the superclass of the class FOO ***class*** (ultimately Behavior) (because we send a message to the object that represent the class FOO so we look in its class)
So new is found Then the method argument receiver is bound to the actual receiver Foo in our case. and new returns an instance of Foo.
By the way I suggest you to read the chapter of one my forthcoming book http://scgwiki.iam.unibe.ch:8080/StephaneDucasseWiki/5
On Sunday, May 18, 2003, at 01:58 AM, Dominic Fox wrote:
- Is the best way to make what in C++ or Java you'd call
"constructors" to write class methods that create, initialize and then return an instance, e.g.
newFooWithBar: initialBar
| newFoo |
newFoo := Foo new; setBar: initialBar. ^ newFoo
or is there a more concise way?
OK, I've got this one already. ^ super new init. Had me puzzled for a while (why would I want to return a new instance of the *superclass*?) until I figured out what the superclass was the superclass *of*...
Dominic
On Sun, 18 May 2003 00:27:41 +0100, Dominic Fox dominic.fox1@ntlworld.com wrote:
- If I want to expose an instance's private fields, do I have to code
accessor methods every time? Is there an alternative to writing
getFoo ^ foo
and
setFoo: newFoo foo := newFoo
over and over again?
You can write code that generates the accessor and generator methods. You can add such code to the Browser, and provide menu options that run the code for any selected set of instance variables.
An example of the necessary code:
| names | names := MyClass instVarNames. 1 to: names size do: [:index | | name capitalizedName | name := localNames at: index. capitalizedName := name withFirstCharCapitalized. MyClass compile: 'set', capitalizedName, ': a', capitalizedName, ' ', name, ' := a', capitalizedName classified: #accessing]
Also, you can use the #instVarAt: and #instVarAt:put: primitives:
'Hello' asText instVarAt: 1 "Evaluates to the String contained in the 'string' instance variable of a Text."
- Is the best way to make what in C++ or Java you'd call "constructors"
to write class methods that create, initialize and then return an instance, e.g.
newFooWithBar: initialBar | newFoo | newFoo := Foo new; setBar: initialBar. ^ newFoo
or is there a more concise way?
Class methods are the way to go, unless one also wants to use the Strategy pattern to dynamically vary how instances get initialized--in which case explicit "factory" objects might be called for.
A note on the syntax in your example: 'Foo new; setBar: initialBar' does not do what you think it does. It results in sending the message #setBar: to the class Foo, not to the instance you've created in the previous message send. To code what you intended, use one of the following:
1: self basicNew setBar: initialBar "use when #setBar: is fully responsible for initializing the instance" 2: self new setBar: initialBar "use when #setBar: is NOT fully responsible for initializing the instance"
Usually, the #new class method answers an initialized instance. It should be coded in an abstract superclass (so that all the subclasses inherit it) as follows:
new ^self basicNew initialize
By convention, the method #basicNew always answers a new but uninitialized object. Using #basicNew therefore guarantees that a) there won't be any unexpected recursion in the class methods that participate in constructing initialized instances, and b) there won't be any unecessary duplication of work, or creation of throw-away objects, during the initialization process.
- Can I treat blocks as first-class entities, e.g. return them from
methods, pass them around etc? Can I use them to implement LISP-like closures? Even if I can, is this a "natural" smalltalky way to do things?
Yes, in most Smalltalk implementations. Unfortunately, Squeak does not yet fully support blocks as closures. Blocks as full closures were first implemented in Smalltalk in the 80's by a company known as ParcPlace. A version of Smalltalk descended from ParcPlace's implementation is still available as the VisualWorks product form Cincom. Both Squeak and VisualWorks are direct descendents of the original ST-80 described in the "Blue Book."
- What about function/method pointers? Can I treat one of an instance's
methods as a block, or do I have to make a new block and call the method inside that?
The latter. And it is relatively trivial to create classes with Block-like APIs that internally invoke some method with some object as the receiver. See, for example, Object>perform:, Object>perform:with: and Object>withArguments:
Finally,
- Is this list a good place to ask questions like this? If it isn't, is
there a more suitable one?
This list is one place to ask such questions. Another option would be the newsgroup comp.lang.smalltalk.
On Sat, 17 May 2003 18:49:47 -0700, sourcery <squeak-dev.sourcery@forum- mail.net> wrote:
Object>withArguments:
That should be "Object>perform:withArguments:"
It's what you might call a failure to "perform:". Ahem.
On Sat, 17 May 2003 18:49:47 -0700, sourcery <squeak-dev.sourcery@forum- mail.net> wrote:
You can write code that generates the accessor and generator methods.
Should be: '...accessor and **mutator** methods...'.
An example of the necessary code:
| names | names := MyClass instVarNames. 1 to: names size do: [:index | | name capitalizedName | name := localNames at: index. capitalizedName := name withFirstCharCapitalized. MyClass compile: 'set', capitalizedName, ': a', capitalizedName, ' ', name, ' := a', capitalizedName classified: #accessing]
'localNames' => 'names'
The #instVarNames message answers the names of the instance variables locally defined by the class. There is also the message #allInstVarNames, that answers the full set of instance variable names (i.e., including the ones inherited from superclasses.)
Hopefully, I remembered to take my Freudian Slippers off before posting, this time around :-)
What a fantastically comprehensive (if not exhaustive) set of answers. Thanks especially to Stephane for the book links.
Mention of the strategy pattern, factory methods etc. confirms something i started thinking when I started playing with class methods, namely that some of the GoF patterns make a kind of intuitive sense in Smalltalk, more so than they do in C++. I've read objections to _Design Patterns_, particularly from the FP corner, which basically argue that the implementation code for many of them is a kind of boilerplate that ought to be abstracted into the language itself ("you wouldn't need to write this over and over again if your language supported proper macros / higher order functions / closures / continuations / whatever"). These objections seem more pertinent when you look at the C++ code than they do when you look at the Smalltalk code, which is generally more concise and less contorted.
The idea of coding support for auto-accessors into the browser suggests that Smalltalk *does* give you macros, after a fashion; although you could argue that, in that case, so does VB with its IDE add-ins. It surely helps, though, that the Smalltalk syntax is so minimal (VB's is a dreadfully inconsistent clutter). I'll have to look into this some more...
Stephane's explanation of why "^ super new init" works tallies with what I'd been able to figure out by browsing over Kernel-Object and Kernel-Classes. Just having the system visible in this way certainly helps: I've spent all of two afternoons with Smalltalk so far, and already a lot of things are dropping nicely into place.
thanks again to all - I'll be back... Dominic
Hi dominic
What I learned over time is that Smalltalk is really adapted for people that can learn alone and are clever because it is uniform. So do not hesitate to ask and have fun.
Pay attention Squeak has some dark corners, but this is improving.
Stef
On Sunday, May 18, 2003, at 02:16 PM, Dominic Fox wrote:
What a fantastically comprehensive (if not exhaustive) set of answers. Thanks especially to Stephane for the book links.
Mention of the strategy pattern, factory methods etc. confirms something i started thinking when I started playing with class methods, namely that some of the GoF patterns make a kind of intuitive sense in Smalltalk, more so than they do in C++. I've read objections to _Design Patterns_, particularly from the FP corner, which basically argue that the implementation code for many of them is a kind of boilerplate that ought to be abstracted into the language itself ("you wouldn't need to write this over and over again if your language supported proper macros / higher order functions / closures / continuations / whatever"). These objections seem more pertinent when you look at the C++ code than they do when you look at the Smalltalk code, which is generally more concise and less contorted.
The idea of coding support for auto-accessors into the browser suggests that Smalltalk *does* give you macros, after a fashion; although you could argue that, in that case, so does VB with its IDE add-ins. It surely helps, though, that the Smalltalk syntax is so minimal (VB's is a dreadfully inconsistent clutter). I'll have to look into this some more...
Stephane's explanation of why "^ super new init" works tallies with what I'd been able to figure out by browsing over Kernel-Object and Kernel-Classes. Just having the system visible in this way certainly helps: I've spent all of two afternoons with Smalltalk so far, and already a lot of things are dropping nicely into place.
thanks again to all - I'll be back... Dominic
On Sunday 18 May 2003 12:21 pm, Stephane Ducasse wrote:
Hi dominic
What I learned over time is that Smalltalk is really adapted for people that can learn alone and are clever because it is uniform. So do not hesitate to ask and have fun.
Thanks Stephane.
Smalltalk seems to reward cleverness by making you feel even cleverer. I like languages that do that ;). But it's also accessible to more than one approach: I guess that when young children first get hold of it, they often use it a bit like Logo to begin with, sending messages to some on-screen avatar and watching what it does in response. It might be a bit advanced still for my three-year-old son, but I'd like to see if I can make him some toys in Squeak to play with once he starts getting a bit more confident with the mouse.
Dominic
Am Sonntag, 18.05.03 um 14:16 Uhr schrieb Dominic Fox:
The idea of coding support for auto-accessors into the browser
Actually, there is already support for auto accessors. You just have to enable them in the preference panel. When you send an accessor for an instance variable which is not already defined, you are asked if it should be created for you. As easy as it can get ;-)
-- Bert
Hi
dominic I suggest you to read the free book available on my web page: Smalltalk by example then after Kent Beck Best Smalltalk practices Online Free Books at http://www.iam.unibe.ch/~ducasse/WebPages/FreeBooks.html
Free books for Universities at http://www.esug.org/sponsoring/promotionProgram.html
Stef
On Sunday, May 18, 2003, at 01:27 AM, Dominic Fox wrote:
Hi,
I'm a Squeak/Smalltalk newbie with some experience of doing OO in other languages, chiefly VB (which is not at all great for that purpose) and Python (which is rather better, but not in use in my place of work), and a smattering of FP that's still not settled in my mind. I'm trying to get my head round a couple of things in Smalltalk, and the documentation I've browsed so far hasn't helped much: my queries more to do with idiom than anything else. Can anyone give me a clue as to where I might find some answers to questions like these:
- If I want to expose an instance's private fields, do I have to code
accessor methods every time? Is there an alternative to writing
getFoo ^ foo
and
setFoo: newFoo foo := newFoo
over and over again?
- Is the best way to make what in C++ or Java you'd call
"constructors" to write class methods that create, initialize and then return an instance, e.g.
newFooWithBar: initialBar | newFoo | newFoo := Foo new; setBar: initialBar. ^ newFoo
or is there a more concise way?
- Can I treat blocks as first-class entities, e.g. return them from
methods, pass them around etc? Can I use them to implement LISP-like closures? Even if I can, is this a "natural" smalltalky way to do things?
- What about function/method pointers? Can I treat one of an instance's
methods as a block, or do I have to make a new block and call the method inside that?
Finally,
- Is this list a good place to ask questions like this? If it isn't,
is there a more suitable one?
thanks, Dominic
Prof. Dr. Stephane DUCASSE [ | ] http://www.iam.unibe.ch/~ducasse/ "if you knew today was your last day on earth, what would you do different? ... especially if, by doing something different, today might not be your last day on earth" Calvin&Hobbes
OK, now this is quite fun.
Part of my interest in Smalltalk has to do with a more general curiosity about what happens when you add things like reflection and metaclasses to an object oriented system (or don't take them away in the first place). This is one of the things I find myself missing when I'm coding in VB. I like the fact that in Python, for instance, it's trivially easy to create an object that acts as a facade for any other objects you tell it to: you just intercept messages sent to that object using __setattr__ and __getattr__, and pass them on to the first of the sub-objects that can receive them (or to all of them, one after another, possibly sequencing their return values into a list or tuple). Such an object would act as a kind of dynamic proxy; and of course you can start intercepting those method calls and hooking all sorts of side-effects up to them as well, if you want to.
So far, in Smalltalk, I have a class "Interceptor" with a private variable "log" that's initialized to be a Bag. Interceptor has a method "intercept:" which looks like this:
intercept: aBlock ^ [message: | self log add: message. aBlock value: message]
You pass in a block (that takes a single parameter) and get a block back that does the same thing, except that Interceptor logs the parameter that was passed to it. Now for an object foo with a method bar, we can create a block that passes a message to foo's bar, and intercept *that*:
interceptedFooBar := myInterceptor intercept: [:message | foo bar: message]
and so on ad nauseam.
Is there, in fact, a Smalltalk equivalent to __getattr__/__setattr__? If not, how do you do dynamic proxies (e.g. proxies that don't know until you tell them what they're proxies for)?
Dominic
On Monday 19 May 2003 03:37 pm, Dominic Fox wrote:
Is there, in fact, a Smalltalk equivalent to __getattr__/__setattr__? If not, how do you do dynamic proxies (e.g. proxies that don't know until you tell them what they're proxies for)?
We have #doesNotUnderstand: aMessage. Your proxy can override this and then decide what to do with the message, somehow.
Hi dominic
I suggest you to have a look at: http://www.iam.unibe.ch/~ducasse/WebPages/Publications.html
Stéphane Ducasse, Evaluating Message Passing Control Techniques in Smalltalk, In JOOP (Journal of Object - Oriented Programming), N 6, jun, Vol 12, SIGS Press, pp. 39-44, 1999. online pdf file
also look at instVarAt: and instVarAt:put:
Stef
On Tuesday, May 20, 2003, at 12:37 AM, Dominic Fox wrote:
OK, now this is quite fun.
Part of my interest in Smalltalk has to do with a more general curiosity about what happens when you add things like reflection and metaclasses to an object oriented system (or don't take them away in the first place). This is one of the things I find myself missing when I'm coding in VB. I like the fact that in Python, for instance, it's trivially easy to create an object that acts as a facade for any other objects you tell it to: you just intercept messages sent to that object using __setattr__ and __getattr__, and pass them on to the first of the sub-objects that can receive them (or to all of them, one after another, possibly sequencing their return values into a list or tuple). Such an object would act as a kind of dynamic proxy; and of course you can start intercepting those method calls and hooking all sorts of side-effects up to them as well, if you want to.
So far, in Smalltalk, I have a class "Interceptor" with a private variable "log" that's initialized to be a Bag. Interceptor has a method "intercept:" which looks like this:
intercept: aBlock ^ [message: | self log add: message. aBlock value: message]
You pass in a block (that takes a single parameter) and get a block back that does the same thing, except that Interceptor logs the parameter that was passed to it. Now for an object foo with a method bar, we can create a block that passes a message to foo's bar, and intercept *that*:
interceptedFooBar := myInterceptor intercept: [:message | foo bar: message]
and so on ad nauseam.
Is there, in fact, a Smalltalk equivalent to __getattr__/__setattr__? If not, how do you do dynamic proxies (e.g. proxies that don't know until you tell them what they're proxies for)?
Dominic
On Tuesday 20 May 2003 7:10 am, Stephane Ducasse wrote:
Hi dominic
I suggest you to have a look at: http://www.iam.unibe.ch/~ducasse/WebPages/Publications.html
I was there earlier today, reading about Traits. Lots of good stuff, thanks.
Dominic
Hi Dominic,
You can play with MetaclassTalk (http://csl.ensm-douai.fr/MetaclassTalk). It provides a running MOP that enhances Squeak reflective facilities. So, you can have a meta-object that controls how instance variables reads and write are done for an arbitrary set of objects, control message sends/reception, method look-up and evaluation...
Noury
Dominic Fox a écrit:
OK, now this is quite fun.
Part of my interest in Smalltalk has to do with a more general curiosity about what happens when you add things like reflection and metaclasses to an object oriented system (or don't take them away in the first place). This is one of the things I find myself missing when I'm coding in VB. I like the fact that in Python, for instance, it's trivially easy to create an object that acts as a facade for any other objects you tell it to: you just intercept messages sent to that object using __setattr__ and __getattr__, and pass them on to the first of the sub-objects that can receive them (or to all of them, one after another, possibly sequencing their return values into a list or tuple). Such an object would act as a kind of dynamic proxy; and of course you can start intercepting those method calls and hooking all sorts of side-effects up to them as well, if you want to.
So far, in Smalltalk, I have a class "Interceptor" with a private variable "log" that's initialized to be a Bag. Interceptor has a method "intercept:" which looks like this:
intercept: aBlock ^ [message: | self log add: message. aBlock value: message]
You pass in a block (that takes a single parameter) and get a block back that does the same thing, except that Interceptor logs the parameter that was passed to it. Now for an object foo with a method bar, we can create a block that passes a message to foo's bar, and intercept *that*:
interceptedFooBar := myInterceptor intercept: [:message | foo bar: message]
and so on ad nauseam.
Is there, in fact, a Smalltalk equivalent to __getattr__/__setattr__? If not, how do you do dynamic proxies (e.g. proxies that don't know until you tell them what they're proxies for)?
Dominic
On Tuesday 20 May 2003 1:18 pm, Noury Bouraqadi wrote:
Hi Dominic,
You can play with MetaclassTalk (http://csl.ensm-douai.fr/MetaclassTalk). It provides a running MOP that enhances Squeak reflective facilities. So, you can have a meta-object that controls how instance variables reads and write are done for an arbitrary set of objects, control message sends/reception, method look-up and evaluation...
Noury
One to get back to when I've more of a handle on things, I think, but it sounds intriguing.
I've nicked my copy of Design Patterns back from work, and notice that the Chain of Responsibility pattern mentions Smalltalk's #doesNotUnderstand as a way of intercepting messages that can't be handled at the current link in the chain and need to be forwarded on.
What do I want this kind of thing for? Well, I use a dynamic proxy every time I connect to a web service with a VB client: the MS SOAP Toolkit supplies a component that can be configured at run-time by passing it a WSDL document, and then works more or less like a DCOM proxy only with SOAP messages passing along the wire. A more banal example is the DHTML support in Microsoft's HTML library: in order to simulate Javascript syntax, e.g. document.all.NameOfAnElement.click(), the collection objects dynamically resolve unknown method calls into indexed retrieval, e.g. document.all.items("NameOfAnElement").click(). This is the kind of trick you can pull in COM/C++ by customising the IDispatch code, but can't do at all in straight VB.
More generally, if you're working in an environment where resources and services are dynamically discovered and accessed, as they sometimes are when you consume web pages or services, then it's helpful to be able to use the native syntax of the language to work with generic components that mould their interfaces to suit that environment. An alternative would be to subclass the generic components and add the resource- or service- specific methods by hand (or via some nifty code generation), but sometimes it's more comfortable to have the component sort these things out for you on demand.
I'm going to shut up now and go and do some actual Smalltalk coding - let you know next time I get stuck...
thanks, Dominic
Hi dominic
I suggest to read the smalltalk companion design pattern this is excellent and you have all kinds of discussion on using or not reflecting features.
Some drafts are available on my books pages
Stef On Wednesday, May 21, 2003, at 12:27 AM, Dominic Fox wrote:
On Tuesday 20 May 2003 1:18 pm, Noury Bouraqadi wrote:
Hi Dominic,
You can play with MetaclassTalk (http://csl.ensm-douai.fr/MetaclassTalk). It provides a running MOP that enhances Squeak reflective facilities. So, you can have a meta-object that controls how instance variables reads and write are done for an arbitrary set of objects, control message sends/reception, method look-up and evaluation...
Noury
One to get back to when I've more of a handle on things, I think, but it sounds intriguing.
I've nicked my copy of Design Patterns back from work, and notice that the Chain of Responsibility pattern mentions Smalltalk's #doesNotUnderstand as a way of intercepting messages that can't be handled at the current link in the chain and need to be forwarded on.
What do I want this kind of thing for? Well, I use a dynamic proxy every time I connect to a web service with a VB client: the MS SOAP Toolkit supplies a component that can be configured at run-time by passing it a WSDL document, and then works more or less like a DCOM proxy only with SOAP messages passing along the wire. A more banal example is the DHTML support in Microsoft's HTML library: in order to simulate Javascript syntax, e.g. document.all.NameOfAnElement.click(), the collection objects dynamically resolve unknown method calls into indexed retrieval, e.g. document.all.items("NameOfAnElement").click(). This is the kind of trick you can pull in COM/C++ by customising the IDispatch code, but can't do at all in straight VB.
More generally, if you're working in an environment where resources and services are dynamically discovered and accessed, as they sometimes are when you consume web pages or services, then it's helpful to be able to use the native syntax of the language to work with generic components that mould their interfaces to suit that environment. An alternative would be to subclass the generic components and add the resource- or service- specific methods by hand (or via some nifty code generation), but sometimes it's more comfortable to have the component sort these things out for you on demand.
I'm going to shut up now and go and do some actual Smalltalk coding - let you know next time I get stuck...
thanks, Dominic
On Sat, May 17, 2003 at 08:42:31PM +0200, Andreas Raab wrote:
Pretty cool, eh? Needless to say, the package requires a new VM. Without it, the supplied tests will horribly crash your system.
Has anyone build a new Mac VM with this changeset? I just tried (3.5, changeset 5180), but the Vm crashes in when running the tests:
Thread 2 Crashed: #0 0x000161ec in lookupMethodInClass (interp.c:8852) #1 0x00009868 in findNewMethodInClass (interp.c:3486) #2 0x00027c60 in primitiveRun (interp.c:16671) #3 0x000277a8 in primitiveResponse (interp.c:16064) #4 0x000108cc in interpret (interp.c:6541) #5 0x90020d48 in _pthread_body
On Mon, May 19, 2003 at 04:06:54PM +0200, Marcus Denker wrote:
On Sat, May 17, 2003 at 08:42:31PM +0200, Andreas Raab wrote:
Pretty cool, eh? Needless to say, the package requires a new VM. Without it, the supplied tests will horribly crash your system.
Has anyone build a new Mac VM with this changeset? I just tried (3.5, changeset 5180), but the Vm crashes in when running the tests:
I am dumb... forgot to do "Smalltalk recreateSpecialObjectsArray". Now it works.
Marcus
On Sat, May 17, 2003 at 08:42:31PM +0200, Andreas Raab wrote:
Hi Guys,
For some experimentation I wanted to have the ability to have *any* object act as a compiled method, so that it can be 'invoked' as if it were a function. I've just published a package for this at SqueakMap.
http://map2.squeakfoundation.org/sm/package/b6a0d3eb-1241-4e3c-b790-e1995b59 9784
I would like to see this included in the main VM: It makes really nice experiments possible. I'm using this, it seems to be stable.
Maybe this is nothing for 3.6, but definitly something to think about for 3.7alpha....
Marcus
On 11/07/03 07:43, "Marcus Denker" marcus@ira.uka.de wrote:
On Sat, May 17, 2003 at 08:42:31PM +0200, Andreas Raab wrote:
Hi Guys,
For some experimentation I wanted to have the ability to have *any* object act as a compiled method, so that it can be 'invoked' as if it were a function. I've just published a package for this at SqueakMap.
http://map2.squeakfoundation.org/sm/package/b6a0d3eb-1241-4e3c-b790-e1995b59 9784
For some unknow reason, I can't connect to this.
Andreas, Markus, exist some place to read more about this ? A place to download ?
Thanks.
edgar
http://map1.squeakfoundation.org/sm/package/b6a0d3eb-1241-4e3c-b790-e1995b59 9784
-----Original Message----- From: squeak-dev-bounces@lists.squeakfoundation.org [mailto:squeak-dev-bounces@lists.squeakfoundation.org] On Behalf Of Lic. Edgar J. De Cleene Sent: Friday, July 11, 2003 1:24 PM To: squeakdev Subject: Re: [Fun][Weird][VM] Objects as compiled methods ( this is great )
On 11/07/03 07:43, "Marcus Denker" marcus@ira.uka.de wrote:
On Sat, May 17, 2003 at 08:42:31PM +0200, Andreas Raab wrote:
Hi Guys,
For some experimentation I wanted to have the ability to
have *any* object
act as a compiled method, so that it can be 'invoked' as
if it were a
function. I've just published a package for this at SqueakMap.
http://map2.squeakfoundation.org/sm/package/b6a0d3eb-1241-4e3c
-b790-e1995b59
9784
For some unknow reason, I can't connect to this.
Andreas, Markus, exist some place to read more about this ? A place to download ?
Thanks.
edgar
On Fri, 11 Jul 2003, Marcus Denker wrote:
On Sat, May 17, 2003 at 08:42:31PM +0200, Andreas Raab wrote:
Hi Guys,
For some experimentation I wanted to have the ability to have *any* object act as a compiled method, so that it can be 'invoked' as if it were a function. I've just published a package for this at SqueakMap.
http://map1.squeakfoundation.org/sm/package/b6a0d3eb-1241-4e3c-b790-e1995b59...
I would like to see this included in the main VM: It makes really nice experiments possible.
I agree, and so I'm changing the subject to include [ENH] (I don't think [Fun][Weird][VM] is one of the standard BFAV prefixes... ;).
It's a nice idea but it's going to be fun to integrate with all the other changes being considered. It shows up how we really need better change handling tools; why on earth do we end up with a full spec for the class just to add a new class var? Sigh.
A quick look at the code makes me wonder why it couldn't work via the perform[with] code. That would make it pass on the same message, which might be good or bad depending on your needs.
tim -- Tim Rowledge, tim@sumeru.stanford.edu, http://sumeru.stanford.edu/tim Useful random insult:- Both oars in the water, but on the same side of the boat.
Tim,
A quick look at the code makes me wonder why it couldn't work via the perform[with] code. That would make it pass on the same message, which might be good or bad depending on your needs.
Two reasons for not using #perform:[withArguments:] a) It doesn't pass along the receiver of the message. For some of the things I wanted to do this was critical and using "thisContext sender receiver" was too ugly a hack for my taste. b) It would imply that there's a 1-on-1 match between the message sent and the (then implicit) #run: message. I thought about this but didn't like it very much as I could think about cases where I wanted to use #run: in one context and #perform: within another.
Cheers, - Andreas
"Andreas Raab" andreas.raab@gmx.de wrote:
Two reasons for not using #perform:[withArguments:]
Fair enough. The prim (it will work as a normal prim, won't it? Looks like it should) would be a good candidate for using any non-filling allocate that John comes up with and probably ought to be renamed - #primitiveRun seems a bit generic and more like a prim that ought to run any arbitrary method. How about something like #primitiveDeferToNonMethodCode ? A bit long perhaps but descriptive.
tim -- Tim Rowledge, tim@sumeru.stanford.edu, http://sumeru.stanford.edu/tim Useful random insult:- People around her are at risk of second hand idiocy.
Tim,
Two reasons for not using #perform:[withArguments:]
Fair enough. The prim (it will work as a normal prim, won't it? Looks like it should)
Yes, it would (though I haven't found a good reason for using it as a "real" prim ;-)
would be a good candidate for using any non-filling allocate that John comes up with and probably ought to be renamed - #primitiveRun seems a bit generic and more like a prim that ought to run any arbitrary method. How about something like #primitiveDeferToNonMethodCode ? A bit long perhaps but descriptive.
Y'er right - the name is probably too generic. Perhaps #primitiveInvokeNonMethod would be appropriate?
Cheers, - Andreas
squeak-dev@lists.squeakfoundation.org