From: Tim Bradshaw
Subject: Secret wonders of CL
Date: 
Message-ID: <ey3k7t0mqgo.fsf@cley.com>
Since there's been so much flamage recently, I thought I'd write
this...

I sometimes am just amazed by what you can do with CL.

I'm writing a system which I want to be able to be patched at
runtime. I wanted some way of loading patches without multiply loading
them and so on. I also want to be able to record what patches are
loaded, where they were compiled & loaded and so on.

Well, obviously the mere ability to load code into a native-compiled
system which redefines things such as classes and functions on the fly
and has a chance of working is fairly unusual to CL, even now (the
redefining classes and having it work bit).

And having a hierarchical patch system so you can define what you're
patching and what you are superseding and so on is fairly easy.

But the clever bit is recording patch information in the patch file
and avoiding reloading.  What I want to be able to do is say something
like this at the start of a file:

    (declare-patch (:foo :bar 1)
      :commentary ("Better test patch"
                   "Soup added")
      :supersedes ((:foo :bar 0)
                   (:foo :fish 0))
      :vc-info "$Id$")

(the lists are `paths' of patches which identify them to the system),
and have it be able to avoid multiply-loading the file, and also to
allow it to be able to say:

    > (describe-loaded-patches)
    Patch /foo/bar/1 ($Id$)
     Supersedes /foo/bar/0, /foo/fish/0
     Compiled from D:\home\tfb\work\weld\play\supergrunge.lisp
      on KINGSTON at Tue 26-Feb-2002 11:01:48 +0 by tfb
     Loaded from D:\home\tfb\work\weld\play\supergrunge.fsl
      at Tue 26-Feb-2002 11:02:06 +0
     Better test patch
     Soup added

This requires two things: it must detect reloading and avoid it, and
somehow it must snarf information from the compiler so it can record
when the patch was compiled.

The first bit is easy: the macro expands to code which, at load time,
checks for the patch already existing in the registry, and if so does
a THROW to a given tag.  The function that loads patches establishes a
catcher for the tag, so this has the effect of painlessly aborting a
LOAD.

The second bit is really devious.  The trick is to create a `patch'
object at compile time, using information like
*COMPILE-FILE-PATHNAME*, and then write this literal object into the
fasl file.  This is done by two things:

There's a macro called LITERAL-PATCH, whose expansion is a patch
object - not a form to create one, but a patch object.  This macro is
used in the expansion of DECLARE-PATCH, which causes it to include a
literal patch object, and if it's been processed by the compiler, this
object will contain information known at compile time.

Then there is a MAKE-LOAD-FORM method for patch objects, which lets
them be dumped to a file.  This MAKE-LOAD-FORM is mostly
MAKE-LOAD-FORM-SAVING-SLOTS, but it also initializes some slots with
load-time information such at the *LOAD-PATHNAME*.

Finally there's some stuff with EVAL-WHEN to make sure that things
actually happen when they should.

As far as I know the only non-portable thing in all this code is the
fact that it notes the username who did the compilation.

I really think that this kind of stuff would be terribly hard in most
languages - there's extensive reasoning going on about things
happening at various times like compile-time, and use of
MAKE-LOAD-FORM and so on to do slightly non-trivial things.  I'm sure
things like perl can do it (although can they do class redefinition
right?), I'd be interested to know if Java can, as user code.

--tim

(and before anyone asks: no, it's not available, sorry).

From: Duane Rettig
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <4r8n8fasj.fsf@beta.franz.com>
Tim Bradshaw <···@cley.com> writes:

 [ ... ]

> I'm writing a system which I want to be able to be patched at
> runtime. I wanted some way of loading patches without multiply loading
> them and so on. I also want to be able to record what patches are
> loaded, where they were compiled & loaded and so on.

  [ description of patch system ... ]

> (and before anyone asks: no, it's not available, sorry).

Allegro CL provides a facility for defining and loading patches.
It centers around sys:defpatch:
http://www.franz.com/support/documentation/6.1/doc/pages/operators/system/defpatch.htm

and sys:load-patches:
http://www.franz.com/support/documentation/6.1/doc/pages/operators/system/load-patches.htm

I agree with your assessment that CL makes patching systems (even while
running) almost trivial.

-- 
Duane Rettig          Franz Inc.            http://www.franz.com/ (www)
1995 University Ave Suite 275  Berkeley, CA 94704
Phone: (510) 548-3600; FAX: (510) 548-8253   ·····@Franz.COM (internet)
From: Tim Bradshaw
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <ey31yf8m9j2.fsf@cley.com>
* Duane Rettig wrote:
> Allegro CL provides a facility for defining and loading patches.
> It centers around sys:defpatch:
> http://www.franz.com/support/documentation/6.1/doc/pages/operators/system/defpatch.htm

> and sys:load-patches:
> http://www.franz.com/support/documentation/6.1/doc/pages/operators/system/load-patches.htm

Yes, I wasn't trying to imply that the commercial (or free) systems
don't have the facility - mine just has some special stuff to support
the application I'm working on.

> I agree with your assessment that CL makes patching systems (even while
> running) almost trivial.

This is the wonder: you can write this amazingly complex stuff really
quickly...

--tim
From: Martin Simmons
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <3c7d0617$0$231$ed9e5944@reading.news.pipex.net>
"Tim Bradshaw" <···@cley.com> wrote in message ····················@cley.com...
> The second bit is really devious.  The trick is to create a `patch'
> object at compile time, using information like
> *COMPILE-FILE-PATHNAME*, and then write this literal object into the
> fasl file.  This is done by two things:
>
> There's a macro called LITERAL-PATCH, whose expansion is a patch
> object - not a form to create one, but a patch object.  This macro is
> used in the expansion of DECLARE-PATCH, which causes it to include a
> literal patch object, and if it's been processed by the compiler, this
> object will contain information known at compile time.
>
> Then there is a MAKE-LOAD-FORM method for patch objects, which lets
> them be dumped to a file.  This MAKE-LOAD-FORM is mostly
> MAKE-LOAD-FORM-SAVING-SLOTS, but it also initializes some slots with
> load-time information such at the *LOAD-PATHNAME*.
>
> Finally there's some stuff with EVAL-WHEN to make sure that things
> actually happen when they should.

Just wondering: why do you need the patch object, rather than just
macroexpanding to a call to some function to make the patch object at load-time
(with the compile-time value of *COMPILE-FILE-PATHNAME* as one of its
arguments)?
--
Martin Simmons, Xanalys Software Tools
······@xanalys.com
rot13 to reply
From: Tim Bradshaw
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <ey3u1s2lppz.fsf@tfeb.org>
* Martin Simmons wrote:

> Just wondering: why do you need the patch object, rather than just
> macroexpanding to a call to some function to make the patch object at load-time
> (with the compile-time value of *COMPILE-FILE-PATHNAME* as one of its
> arguments)?

Dang.  I don't, do I.  Every time I look at it it gets simpler!

--tim
From: Thomas F. Burdick
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <xcvk7sywu2q.fsf@famine.OCF.Berkeley.EDU>
Tim Bradshaw <···@tfeb.org> writes:

> * Martin Simmons wrote:
> 
> > Just wondering: why do you need the patch object, rather than just
> > macroexpanding to a call to some function to make the patch object at load-time
> > (with the compile-time value of *COMPILE-FILE-PATHNAME* as one of its
> > arguments)?
> 
> Dang.  I don't, do I.  Every time I look at it it gets simpler!

Yeah, but having the macro expand into the patch object itself is cooler.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Frank A. Adrian
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <3Djf8.126$XA5.354489@news.uswest.net>
Tim Bradshaw wrote:
 
> Dang.  I don't, do I.  Every time I look at it it gets simpler!

Yet Another Wonder...

faa
From: Paolo Amoroso
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <DVl+PDTQiZW4XHdNzWzqqCh7gTTE@4ax.com>
On 26 Feb 2002 11:29:11 +0000, Tim Bradshaw <···@cley.com> wrote:

> I'm writing a system which I want to be able to be patched at
> runtime. I wanted some way of loading patches without multiply loading

How much effort did it take--or it is taking, if it's not complete yet--you
to develop it?


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://www.paoloamoroso.it/ency/README
[http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/]
From: Tim Bradshaw
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <ey3k7sxjuo3.fsf@cley.com>
* Paolo Amoroso wrote:

> How much effort did it take--or it is taking, if it's not complete yet--you
> to develop it?

The patch system?  Under a day.  The whole system somewhat longer...

--tim
From: Will Deakin
Subject: OT [Re: Secret wonders of CL]
Date: 
Message-ID: <3C7E9722.8000504@hotmail.com>
Hmmm. I think I need help but every time I read a post in this thread 
Elvis starts to sing "The Wonder of You" -- from his Vegas period -- 
in my head.

More sleep I think,

:)w
From: Paolo Amoroso
Subject: Re: Secret wonders of CL
Date: 
Message-ID: <w5N=PHEDCmopbSLUUrinfAcZwuZ3@4ax.com>
On 26 Feb 2002 11:29:11 +0000, Tim Bradshaw <···@cley.com> wrote:

> I'm writing a system which I want to be able to be patched at
> runtime. I wanted some way of loading patches without multiply loading
[...]
> I really think that this kind of stuff would be terribly hard in most
> languages - there's extensive reasoning going on about things
> happening at various times like compile-time, and use of
> MAKE-LOAD-FORM and so on to do slightly non-trivial things.  I'm sure
> things like perl can do it (although can they do class redefinition
> right?), I'd be interested to know if Java can, as user code.

Here is a possibly relevant paper:

  "Dynamic C++ Classes - How do you upgrade parts of a running system
  without shutting it down? Very carefully"
  Robert S. Gray, Gisli Hjalmtysson
  C/C++ Users Journal - Vol. 17, n. 10, Oct 1999, page 50

The source code should be available at:

  http://www.research.att.com/~gisli/dynamic
  ftp://actcomm.dartmouth.edu/dynamic

and at the journal's site:

  http://www.cuj.com


Paolo
-- 
EncyCMUCLopedia * Extensive collection of CMU Common Lisp documentation
http://www.paoloamoroso.it/ency/README
[http://cvs2.cons.org:8000/cmucl/doc/EncyCMUCLopedia/]