From: David E. Young
Subject: Watching instance slot access
Date: 
Message-ID: <3AEB1242.F2D9F637@nc.rr.com>
Greetings. This question stems from an issue I must resolve in LISA, my
open-source CLOS Rete implementation (http://lisa.sourceforge.net).

LISA is now capable of reasoning over CLOS instances without requiring
inheritance from some special LISA base class. At issue is the method by
which instances in a LISA knowledge base are kept synchronized when slot
modifications occur outside of LISA's control. To clarifiy; given an
instance of class ROCKY that resides within a knowledge base, any slot
changes to that instance that are not initiated by LISA must be
delivered somehow TO LISA.

Currently, I'm "passing the buck"; if an application modifies an
instance itself it must call a LISA function that synchronizes the
knowledge base with the new instance state. Simple. Works. But, perhaps
a bit intrusive.

I'm considering trying to "automate" this behavior, such that LISA is
able to recognize these types of slot modifications and respond without
help from the application. The MOP appears to provide the mechanism in
the form of
the (SETF SLOT-VALUE-USING-CLASS) generic function. I suppose I could
define an AFTER method on this function that would form the basis of
this new synchronization mechanism, but there are "issues":

1. LISA is intended to be portable, and not all popular Common Lisp
implementations offer this level of MOP support (CLISP comes to mind). I
could retain the manual interface for these platforms.

2. LISA uses (SETF SLOT-VALUE) herself to modify instances. How can I
distinguish a LISA-initiated modification from an external one? This is
an important point, and I would like to avoid a messy "hack" to get this
working.

3. Not all of the ramifications of an automated approach are clear to
me. Might there be good reasons why a manual mechanism is preferable?

So, I'm soliciting comments on how I should proceed. Hopefully I've been
clear enough.

Thanks for your time.

Regards,

--
-----------------------------------------------------------------
David E. Young
Fujitsu Network Communications  (defun real-language? (lang)
(········@computer.org)           (eq lang 'LISP))

"But all the world understands my language."
  -- Franz Joseph Haydn (1732-1809)

From: Sashank Varma
Subject: Re: Watching instance slot access
Date: 
Message-ID: <sashank.varma-2904011355390001@129.59.212.53>
In article <·················@nc.rr.com>, ·······@nc.rr.com wrote:

[snip]
>2. LISA uses (SETF SLOT-VALUE) herself to modify instances. How can I
>distinguish a LISA-initiated modification from an external one? This is
>an important point, and I would like to avoid a messy "hack" to get this
>working.

i don't know if this counts as a messy hack, but you could define a
special variable *in-lisa-context-p* that is t when code is running
in the context of LISA and nil otherwise.  this could be managed by
having all top-level entry points to (i.e., commands of) LISA bind
*in-lisa-context-p* (which is otherwise nil) to t before doing their
work.  then, write the :after method on (setf slot-value) so that
it only calls the manual LISA update function when the setf call is
outside the *in-lisa-context-p* is nil, i.e., when the call to setf
occurs in a non-LISA context.

>3. Not all of the ramifications of an automated approach are clear to
>me. Might there be good reasons why a manual mechanism is preferable?

in similar cases, i have always gone the route of having a manual
mechanism.  it is certainly desirable that your LISA objects and
your common lisp objects be as similar as possible.  having to
call a manual update function when outside the LISA context partially
destroys this similarity, and so is unsatisfactory.  the reason i
have satisfied for this less elegant route is because i am not sure
what other borderline cases need be considered.  perhaps others
would more experience can delineate these.

sashank
From: David Young
Subject: Re: Watching instance slot access
Date: 
Message-ID: <3AED722D.73FE88EE@nc.fnc.fujitsu.com>
Sashank Varma wrote:

> In article <·················@nc.rr.com>, ·······@nc.rr.com wrote:
>
> i don't know if this counts as a messy hack, but you could define a
> special variable *in-lisa-context-p* that is t when code is running
> in the context of LISA and nil otherwise...

Yes, that's right. I wonder how this mechanism will behave in an MP
environment? I must RTFM, but offhand does anyone know how specials behave
across threads? For example, given the following code fragment:

(defvar *rocky* nil)

** thread one **

(let ((*rocky* 'rocky))
   (print *rocky*))

** thread two **

(let ((*rocky* 'boris))
   (print *rocky*))

Can I safely do this?

> in similar cases, i have always gone the route of having a manual
> mechanism...

Yes, this is a good point. I think, when all is said and done, that there
might be too many unforseen possibilities with an automated approach.

Your comments are appreciated.

Regards,

--

-------------------------------------------------------------
David E. Young
Fujitsu Network Communications  (defun real-language? (lang)
(········@computer.org)           (eq lang 'LISP))

"But all the world understands my language."
  -- Franz Joseph Haydn (1732-1809)
From: Tim Bradshaw
Subject: Re: Watching instance slot access
Date: 
Message-ID: <nkjae4ycr9d.fsf@tfeb.org>
David Young <···@nc.fnc.fujitsu.com> writes:

> 
> ** thread one **
> 
> (let ((*rocky* 'rocky))
>    (print *rocky*))
> 
> ** thread two **
> 
> (let ((*rocky* 'boris))
>    (print *rocky*))
> 
> Can I safely do this?
> 

I don't know of any implementations that get this wrong -- I think
that if you bind a special within a thread then that's the binding it
will have in that thread unless you rebind it or assign.  Some
implementations, I think, have ways of setting default bindings for
some specials when a new thread is created, but that's a different
issue.

--tim
From: Janis Dzerins
Subject: Re: Watching instance slot access
Date: 
Message-ID: <87bspempq3.fsf@asaka.latnet.lv>
David Young <···@nc.fnc.fujitsu.com> writes:

> Yes, that's right. I wonder how this mechanism will behave in an MP
> environment? I must RTFM, but offhand does anyone know how specials behave
> across threads? For example, given the following code fragment:
> 
> (defvar *rocky* nil)
> 
> ** thread one **
> 
> (let ((*rocky* 'rocky))
>    (print *rocky*))
> 
> ** thread two **
> 
> (let ((*rocky* 'boris))
>    (print *rocky*))
> 
> Can I safely do this?

I've heard that one can change the behaviour of specials per-thread
and per-special. I know that in ACL it is possible for sure.

-- 
Janis Dzerins

  If million people say a stupid thing it's still a stupid thing.
From: Paolo Amoroso
Subject: Re: Watching instance slot access
Date: 
Message-ID: <zGPsOtFt7N5fiimRtpcaV0lMlK18@4ax.com>
On Sat, 28 Apr 2001 18:58:02 GMT, "David E. Young" <·······@nc.rr.com>
wrote:

> LISA is now capable of reasoning over CLOS instances without requiring
> inheritance from some special LISA base class. At issue is the method by
> which instances in a LISA knowledge base are kept synchronized when slot
> modifications occur outside of LISA's control. To clarifiy; given an
[...]
> I'm considering trying to "automate" this behavior, such that LISA is
> able to recognize these types of slot modifications and respond without
> help from the application. The MOP appears to provide the mechanism in
[...]
> So, I'm soliciting comments on how I should proceed. Hopefully I've been

I include below a message posted to the garnet-users mailing list. A user
dealt with issues similar to yours in an application in which CLOS objects
interacted with KR objects (KR is Garnet's knowledge representation and
object system, which supports automatic constraint maintenance). He needed
to notify KR about changes to CLOS objects, and the message explains how he
solved the problem.

This is more a contribution to brainstorming than a solution to your
problem.


Paolo

---------------------------------------------------------------------------
Date: Wed, 13 Oct 93 17:45:35 PDT
From: "Russell G. Almond" <······@statsci.com>
Subject: Re: KR/CLOS interaction?


   I'm going to resume work on my Serious Object-Oriented Program
   (CarGo/CdrGo), and I'm wondering how bad it would be to try to use
   BOTH CLOS and Garnet.  KR is, as has been pointed out, not the
   greatest thing in the world for major OO applications.  (For example,
   the objects don't automatically know their own names -- you have to
   tell them each time!)  To what extent has this been tried?  Does
   anyone have any tips/pointers/warnings?
   --
   : Peter Dudey, ······@godel.cs.orst.edu


Its actually not that bad.  I've done it for several parts of
GRAPHICAL-BELIEF (in particular the graph layout stuff) and it seems
to work pretty well.  Running the system with Garnet takes more time
than without, but I think a lot of the overhead has to do with X
Windows (or X Windows---Lisp interaction) than with the KR object
system.  

The two hardest problem are (1) the notification problem and (2) the
callback problem.  Note that KR will not notice when a slot changes in
a CLOS object, you must explicitly inform the KR object that the CLOS
object has changed (kr:mark-as-changed often followed by an
opal:update, although that may not be necessary in Garnet 2.2).

Here is how I solve the problems:



+--------+ announcement +----------+ notification  +--------+
|        |------------->| Mediator |-------------->|        |
| CLOS   |              +----------+               | KR     |
| object |    call-back (action function)          | object |
|        |<----------------------------------------|        |
+--------+                                         +--------+

1)  Destructive methods defined on the CLOS object make an annoucement
that a change has occurred.  I usually define this as an after method
on the destructive generic function.  The announcement is sent to a
mediator object which then notifies any display object (KR object)
which has registered interest in the change.  The :initialize and
:destroy-me methods of the KR object take care of setting up this
notification.  This use of a mediator allows multiple views of the
same base object.

2) The action-function for each KR object calls (where appropriate) a
CLOS generic function for operating on the source object with the
source-object as an argument.  (The source-object is usually a slot in
the KR display object).  If this function makes a visible change to
the CLOS object, it will (by protocol 1) make an announcement which
will in turn cause the notification.


Although this seems a bit convoluted, it does provide good
display--object independence.  In fact some discussions I've had with
Smalltalk programmers indicate that this is the currently preferred
shape of Smalltalk programs (I believe they call it the MMVC, or
Model-Model-View-Controller paradigm).

My experience with it has been that it works pretty well.  The limited
profiling I've done seems to indicate that it the Garnet half which is
the bottleneck.  I'm not sure if that is because I haven't looked
closely at the constants and other tuning, overhead due to X windows
calls (creating a window is always slow) or overhead due to KR or
other parts of Garnet.

Good Luck.

			Russell Almond			   
StatSci (a division of MathSoft)
1700 Westlake Ave., N Suite 500, Seattle, WA  98109		
(206) 283-8802	 FAX:  (206) 283-8691  Email: ······@statsci.com	
---------------------------------------------------------------------------


-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/
From: David Young
Subject: Re: Watching instance slot access
Date: 
Message-ID: <3AED87F5.9CFFCE3D@nc.fnc.fujitsu.com>
Paolo Amoroso wrote:

> I include below a message posted to the garnet-users mailing list. A user
> dealt with issues similar to yours in an application in which CLOS objects
> interacted with KR objects (KR is Garnet's knowledge representation and
> object system, which supports automatic constraint maintenance). He needed
> to notify KR about changes to CLOS objects, and the message explains how he
> solved the problem...

Ok. So, if I understand correctly KR employs a generic function that
applications must call whenver slot modifications occur. KR generates an AFTER
method on this function to take care of synchronization issues. Right?

It would seem from this post, and another, that a manual approach is the
"best".

Regards,

--

-------------------------------------------------------------
David E. Young
Fujitsu Network Communications  (defun real-language? (lang)
(········@computer.org)           (eq lang 'LISP))

"But all the world understands my language."
  -- Franz Joseph Haydn (1732-1809)
From: Paolo Amoroso
Subject: Re: Watching instance slot access
Date: 
Message-ID: <v6LuOlEHEOs7yC+2brCS=JSBDjdg@4ax.com>
On Mon, 30 Apr 2001 11:42:45 -0400, David Young <···@nc.fnc.fujitsu.com>
wrote:

> Ok. So, if I understand correctly KR employs a generic function that
> applications must call whenver slot modifications occur. KR generates an AFTER
> method on this function to take care of synchronization issues. Right?

I seem to understand that the :AFTER method (which is used to propagate
changes in CLOS objects to KR objects) is supplied by the programmer, not
generated by KR. The generic function is called by KR to propagate changes
in KR objects to CLOS objects.

Note that KR automatically keeps track of modifications to KR slots. The
protocols described in the message posted to the garnet-users list have
been devised for synchronization in a mixed environment with both CLOS and
KR objects.


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/
From: Jochen Schmidt
Subject: Re: Watching instance slot access
Date: 
Message-ID: <9cmpqf$ejfi4$1@ID-22205.news.dfncis.de>
David E. Young wrote:


> 2. LISA uses (SETF SLOT-VALUE) herself to modify instances. How can I
> distinguish a LISA-initiated modification from an external one? This is
> an important point, and I would like to avoid a messy "hack" to get this
> working.

You may create a generic-function that is responsible for your updates. 
Then you create a primary method in it that dispatches on "t" and do your 
normal updates in that method. Then you create a method that dispatches on 
a special mixin-class and does effectively nothing. So you can mix this 
mixin-class into all of your Lisa-Classes and all should work fine.

I've not tried it but it should work, should it?

Regards,
Jochen
From: Jochen Schmidt
Subject: Re: Watching instance slot access
Date: 
Message-ID: <9cmpue$ejfi4$2@ID-22205.news.dfncis.de>
Jochen Schmidt wrote:

> David E. Young wrote:
> 
> 
>> 2. LISA uses (SETF SLOT-VALUE) herself to modify instances. How can I
>> distinguish a LISA-initiated modification from an external one? This is
>> an important point, and I would like to avoid a messy "hack" to get this
>> working.
> 
> You may create a generic-function that is responsible for your updates.
> Then you create a primary method in it that dispatches on "t" and do your
> normal updates in that method. Then you create a method that dispatches on
> a special mixin-class and does effectively nothing. So you can mix this
> mixin-class into all of your Lisa-Classes and all should work fine.
> 
> I've not tried it but it should work, should it?
> 
> Regards,
> Jochen

I've to add that the created generic-function is meant to be called from 
your (setf slot-value-using-class) :after Method!

Regards,
Jochen