[comp.lang.smalltalk] Tracking Interaction Histories

abbott@aerospace.aero.org (Russell J. Abbott) (08/18/89)

One feature I want to include in a browsing system I'm building is to
let users capture, edit, and then replay sequences of browsing
operations.  Is there a good way to do that in smalltalk?


-- 


-- (Russ) abbott@itro3.aero.org

abbott@aerospace.aero.org (Russell J. Abbott) (08/19/89)

In article <56231@aerospace.AERO.ORG> I wrote:
> One feature I want to include in a browsing system I'm building is to
> let users capture, edit, and then replay sequences of browsing
> operations.  Is there a good way to do that in smalltalk?

This seems to be a special case of a more general problem.  I've also
been thinking about how to implement Prolog-like logical variables in
Smalltalk.  The obvious thing would be to define a class called Variable
with one instance variable for the variable's referenced value, if any.
The problem this raises is that one wants to be able to send to Variable
objects messages to be passed on to the variable's referent.  But in
order for the variable to be able to do that it has to have built into
it selectors for all the possible calls it's referents may ever receive,
which is impossible.  What is really needed is some sort of meta-method
that can handle any call.  But as far as I know, smalltalk doesn't
support such a thing.  (Is that true?  I'm really just a smalltalk
novice.)

One would need a similar capability if one wanted to write some sort of
interpreter which could accept any call at all.  If one had such an
interpreter one could build the history maintainer I asked for
originally.  How does the smalltalk world handle the need for this sort
of thing?-- 
-- Russ abbott@itro3.aero.org

bnfb@Apple.COM (Bjorn Freeman-Benson) (08/19/89)

In article <56248@aerospace.AERO.ORG> (Russell J. Abbott) writes:
> ...
>objects messages to be passed on to the variable's referent.  But in
>order for the variable to be able to do that it has to have built into
>it selectors for all the possible calls it's referents may ever receive,

You can do this by reimplementing 
    doesNotUnderstand: aMessage
for your Variable class.  When an object gets sent a message that it
does not have a method for, it calls this routine.  The default
behavior (in Object) is to put up an error notification.  For your
Variable class, the method would be:
    doesNotUnderstand: aMessage
	^referent perform: aMessage selector withArguments: aMessage arguments

And then, of course, you get into the problem of "the name of a
thing" versing itself".  When you send "getReferent" to the Variable
it handles the message.  But what if you wanted to send
"getReferent" to the Variable's referent?  Arg.

But, that's a seperate problem...
Bjorn N. Freeman-Benson

arshad@lfcs.ed.ac.uk (Arshad Mahmood) (08/21/89)

In article <56248@aerospace.AERO.ORG> abbott@aero.UUCP (Russell J. Abbott) writes:
>In article <56231@aerospace.AERO.ORG> I wrote:
>> One feature I want to include in a browsing system I'm building is to
>> let users capture, edit, and then replay sequences of browsing
>> operations.  Is there a good way to do that in smalltalk?
>
>This seems to be a special case of a more general problem.  I've also
>been thinking about how to implement Prolog-like logical variables in
>Smalltalk.  The obvious thing would be to define a class called Variable
>with one instance variable for the variable's referenced value, if any.
>The problem this raises is that one wants to be able to send to Variable
>objects messages to be passed on to the variable's referent.  But in
>order for the variable to be able to do that it has to have built into
>it selectors for all the possible calls it's referents may ever receive,
>which is impossible.  What is really needed is some sort of meta-method
>that can handle any call.  But as far as I know, smalltalk doesn't
>support such a thing.  (Is that true?  I'm really just a smalltalk
>novice.)
>
>One would need a similar capability if one wanted to write some sort of
>interpreter which could accept any call at all.  If one had such an
>interpreter one could build the history maintainer I asked for
>originally.  How does the smalltalk world handle the need for this sort
>of thing?-- 
>-- Russ abbott@itro3.aero.org


Try trapping the message in Object.

doesNotUnderstand: aMessage 
	"First check for a compound selector.  If found, try copying down code
	into the receiver's class.  If this is unsuccessful,
	announce that the receiver does not understand the argument, aMessage,
	as a message.  The default behavior is to create a Notifier containing the 
	appropriate message and to allow the user to open a Debugger. 
	Subclasses can override this message in order to modify this behavior."
	| status gripe |

	status _ self class tryCopyingCodeFor: aMessage selector.
	status==#OK ifTrue:
		[^self perform: aMessage selector withArguments: aMessage arguments].

	gripe _ status==#HierarchyViolation
		ifTrue: [aMessage selector classPart , ' is not one of my superclasses: ']
		ifFalse: ['Message not understood: '].
	NotifierView
		openContext: thisContext
		label: gripe , aMessage selector
		contents: thisContext shortStack.
	"Try the message again if the programmer decides to proceed."
	^self perform: aMessage selector withArguments: aMessage arguments


------
	This is the method which notifies you of the fact that the message
	is not understood.

	The message itself is in aMessage and you can do pretyy much anything 
	you like with it.


	Hope this helps.

	Note: I have not had a chance to try this on our machines since
	they're rather heavily used, but there is no reason why
	this shouldn't work.

A. Mahmood
Laboratory for Foundations of Computer Science
Edinburgh University
Scotland
e-mail: arshad@lfcs.edinburgh.ac.uk

arshad@lfcs.ed.ac.uk (Arshad Mahmood) (08/21/89)

oops, he notices just after his sent it that some kind soul has answered the
same question on comp.land.smalltalk.

But since the prolog people may not read the smalltalk bb, it may still be
of minute use.

sorry.

bruce@servio.UUCP (Bruce Schuchardt) (08/22/89)

In article <34138@apple.Apple.COM> bnfb@Apple.COM (Bjorn Freeman-Benson) writes:
>In article <56248@aerospace.AERO.ORG> (Russell J. Abbott) writes:
>> ...
>>objects messages to be passed on to the variable's referent.  But in
>>order for the variable to be able to do that it has to have built into
>>it selectors for all the possible calls it's referents may ever receive,
>
>You can do this by reimplementing 
>    doesNotUnderstand: aMessage
>for your Variable class.  When an object gets sent a message that it
>does not have a method for, it calls this routine.  The default
>behavior (in Object) is to put up an error notification.  For your
>Variable class, the method would be:
>    doesNotUnderstand: aMessage
>	^referent perform: aMessage selector withArguments: aMessage arguments
>
>And then, of course, you get into the problem of "the name of a
>thing" versing itself".  When you send "getReferent" to the Variable
>it handles the message.  But what if you wanted to send
>"getReferent" to the Variable's referent?  Arg.
>

There are some pitfalls in using proxy objects like this that you should
be aware of.  The first is *speed degradation*.  The second is *special
messages*.

When you use the "doesNotUnderstand:" route of trapping messages, you are
introducing some serious extra processing into your system.  The interpreter
must hunt through the forwarder's class hierarchies method dictionaries
to determine that the message has not been implemented.  It must then build
a message object (to hold the selector and arguments) and search the
hierarchy again for your "doesNotUnderstand:" method.

I would not recommend using this approach for compute-intensive applications.
In any case, it can be made most efficient by nilling out the superclass
of the forwarder class after it has been created.  This is more work, but
you will end up with a faster forwarder.

The second problem concerns special messages.  You all probably saw the
message last week about the "value" method in contexts.  In Smalltalk-80,
and evidently Smalltalk/V, some messages are treated extra special by the
compiler/interpreter.  They don't go through message lookup, but are
trapped and executed immediately.  Examples are "value" and "==".
ParcPlace Smalltalk-80 keeps a list of special selectors in a class
variable in SystemDictionary.  YOU WILL NOT BE ABLE TO TRAP THESE
MESSAGES unless you change the compiler or recompile everything to use
different selectors.



-- 
 --------                         --------------
| Bruce Schuchardt          Ph: (503) 629-8383  |
| Beaverton, OR             uunet!servio!bruce  |
 --------------                         --------

foote@p.cs.uiuc.edu (08/22/89)

It is possible to use doesNotUnderstand: to wrap code around a given
Smalltalk object, but doing this seamlessly can be tricky.  Problems arise
because doesNotUndertand: is not invoked until after all methods defined
for a given object have been considered for execution.  This means
that common methods defined by Object will not be passed to
a Variable object's referent, but will be executed by the Variable
object itself.  An insidious scheme for circumenting this problem
was described by Geoffrey Pascoe in an OOPSLA '86 paper on what he
called Encapsulators.  He created a hierarchy of objects that do not
include Object as a superclass and hence respond to a minimal number of 
messages.  As a result, nearly all messages can be intercepted using 
doesNotUnderstand: and forwarded to the Encapsulator's referent.  This paper
also describes how Pascoe dealt with the parts of the programmer interface 
that break when one creates objects like this.

Another potential problem with the Variable object approach is that
the wrapper will in effect stick to the value rather than the
object owning the variable if references to the owning object's
instance variables are not carefully controlled.  That is to say,
the approach being discussed creates active values rather than active
variables.  As a result, copies of the wrapped value with the wrapper
still in place can "leak" out of an object.  (Of course, for some applications,
this may be just what is needed.)

To create active variables, one must change the way
that objects reference their variables so that messages like value and value:
are sent to variable objects in place of explicit loads and stores.  One
way to do this is to modify the compiler to generate such code when
appropriate.  Were Smalltalk's scheme for accessing an object's representation
an explicit part of its metalevel architecture then making selective
modifications to it might be easier.  Since the instance access protocol
has largely been subsumed into the virtual machine, this is not the case.

	Brian Foote
	Dept. of CS, U. of Illinois @ Urbana-Champaign

eliot@cs.qmc.ac.uk (Eliot Miranda) (08/25/89)

In article <162@servio.UUCP> bruce@servio.UUCP (Bruce Schuchardt) writes:
>There are some pitfalls in using proxy objects like this that you should
>be aware of.  The first is *speed degradation*.  The second is *special
>messages*.

                .....

>I would not recommend using this approach for compute-intensive applications.
>In any case, it can be made most efficient by nilling out the superclass
>of the forwarder class after it has been created.  This is more work, but
>you will end up with a faster forwarder.
>
>The second problem concerns special messages.  You all probably saw the
>message last week about the "value" method in contexts.  In Smalltalk-80,
>and evidently Smalltalk/V, some messages are treated extra special by the
>compiler/interpreter.  They don't go through message lookup, but are
>trapped and executed immediately.  Examples are "value" and "==".
>ParcPlace Smalltalk-80 keeps a list of special selectors in a class
>variable in SystemDictionary.  YOU WILL NOT BE ABLE TO TRAP THESE
>MESSAGES unless you change the compiler or recompile everything to use
>different selectors.


It isn't necessarily the case that you can't trap special
selector messages in Smalltalk-80. he blue-book specification
implements the == and class messages directly without a lookup.
 All other special selector messages are defined to workwithout
a lookup only for specific class-selector pairs, e.g. BlockContext
and value.

Both PPS's Smalltalk-80 VM & my BrouHaHa Smalltalk-80 VM will
only execute == and class for a small set of classes that are
known and used by the VM, e.g. Array, Message, SmallInteger,
MethodContext, True etc.

At QMC we have used encapsulators for inter-machine
communication & monitor objects (encapsulators that use a
critical section to serialise message sends to the object they
wrap up).

The BrouHaHa VM also caches doesNotUnderstand: message lookups
in the message lookup cache so that nopt every message that
will not be understood will be looked up.
(sounds complete gobbledegook I'm sure!)

In summary, there is no reason why encapsulators should be a
performance bottleneck.  Almost everything can be optimised!


-- 
Eliot Miranda				email:		eliot@cs.qmc.ac.uk
Dept of Computer Science		Tel:		01 975 5220
Queen Mary Westfield College		International:	+44 1 975 5220
Mile End Road
LONDON E1 4NS