From: Kenny Tilton
Subject: Cello Shots (cont'd)
Date: 
Message-ID: <403539B5.60407@nyc.rr.com>
http://www.tilton-technology.com/cellophane.html

First new one is linked under "faster textures".

The raindrops look awesome when the cube is spinning. That is Nehe 
Lesson 6, btw.

The new lighting panel shows window texture used as skin for buttons. 
The cool thing is that as the window gets resized the skin stretcjes and 
the button continues to be continuous with the underlying image. AM I 
spending hours on important stuff or what!

Cloucell the graphical inspector debuts. The cluster of little colored 
squares near the top left let you navigate the DAG/ "You are here" is 
the green square, which corresponds to the object being viewed. The blue 
square is its parents, the yellow squares its children. Gray squares are 
siblings at the same level.

Left right arrrows scroll thru navigation history. the class of the 
object is shown above the slots. that can be clicked to inspect the 
class. the object print name appears to the right of the history 
navigation arrows, and that is a broken popup menu of the inspection 
history.

you can make out a tab bar just above the slots. I am quite pleased with 
that, because today I realized I could  overload sliders if I allowed 
sliders to have more than one draggable puck. After ten minutes I was 
able to toss the specific ct-tap-stop-bar. woo-hoo!

Each slot can be clicked to navigate to the slot value. I think I will 
add a column soon to show the slot value type. etc etc.

Now as soon as I port a textedit widget I can make it into a repl. :)

kenny


-- 

  clinisys, inc
  http://www.tilton-technology.com/
  ---------------------------------------------------------------
"[If anyone really has healing powers,] I would like to call
them about my knees."
                     --  Tenzin Gyatso, the Fourteenth Dalai Lama

From: André Thieme
Subject: Re: Cello Shots (cont'd)
Date: 
Message-ID: <c13pre$n8v$1@ulric.tng.de>
Kenny Tilton wrote:

> Now as soon as I port a textedit widget I can make it into a repl. :)

I think I begin to realize what "The whole language always available" 
means (http://www.paulgraham.com/diff.html).
So Kenny, if you would have a textedit widget and include a repl, could 
you then change the application (creating a second text-field somewhere 
in the window) while it is running?


Regards,
Andr�
--
"If Java is your hammer, every problem looks like a thumb"
From: Kenny Tilton
Subject: Re: Cello Shots (cont'd)
Date: 
Message-ID: <V7fZb.61907$Lp.39802@twister.nyc.rr.com>
Andr� Thieme wrote:
> Kenny Tilton wrote:
> 
>> Now as soon as I port a textedit widget I can make it into a repl. :)
> 
> 
> I think I begin to realize what "The whole language always available" 
> means (http://www.paulgraham.com/diff.html).
> So Kenny, if you would have a textedit widget and include a repl, could 
> you then change the application (creating a second text-field somewhere 
> in the window) while it is running?

Yes. One of the best things about Cells (hence Cello) is that the very 
structure of runtime instances can be controlled by rules. I have a 
workhorse Family class with a "kids" slot and there is a lot of code 
that sees to the orderly "birth" and "death" of new objects in the 
hierarchy, whether it be the GUI hierarchy of Cello or the model 
hierarchy of RoboCup.

The top of the Cello hierarchy is a system instance meant to correspond 
to the computer system on which Cello is running. Clearly I need to add 
a "world" parent so Cello can model networks (I am a bit of a dinosaur). 
The children of System are windows (tho I once had a layer for 
Application which then had Windows as its kids.

So to add a widget to a window (at the top level of the hierarchy 
modeling the window), at the repl:

    (push (make-instance 'widget :px 100 :py 200) (car (kids *sys*)))

...and hello widget. Now in normal practice this would be hard because 
the kids of gui structures are almost invariably expressed as formulas, 
and Cell internals enforce a discipline that says "make up your mind! 
does this rule define the semantics of this slot or not!!?" <g> So to 
play this game you would have to create some container somewhere using 
what I call a "variable" cell for kids, and those can be setf'ed by 
imperative code. Somewhere in the window hierarchy you would need to have:

     (make-instance 'container :md-name 'open-bucket :kids (cv nil))

and then you could:

     (push <new widget> (kids (fm-other! 'open-bucket
                                 :family (car (kids *sys*)))))

kenny

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: a
Subject: Re: Cello Shots (cont'd)
Date: 
Message-ID: <Z9fZb.64485$vn.183069@sea-read.news.verio.net>
I can't speak for Kenny's code but that's certainly the way it works for my
code. Under Win32 it is worthwhile in new or exploratory code to keep window
handles (HWND's) and so forth in special variables or arrays, hashes,
structures, CLOS class instances, symbol properties or whatever so long as
they are accessible via symbols from the REPL. I create the window from the
REPL and have all the HWND's accessible. I can call send-message,
create-window, move-window, show-window or any other Win32 API and have
access to all the parameters I need. There is a good feeling of power to
have that line-at-a-time, interactive programming style accessible from the
REPL and to watch the windows system respond with every API call.

Once the code is working, I rewrite as appropriate to use fewer special
variables except where they are needed or handy.


"Andr� Thieme" <······································@justmail.de> wrote in
message ·················@ulric.tng.de...
> Kenny Tilton wrote:
>
> > Now as soon as I port a textedit widget I can make it into a repl. :)
>
> I think I begin to realize what "The whole language always available"
> means (http://www.paulgraham.com/diff.html).
> So Kenny, if you would have a textedit widget and include a repl, could
> you then change the application (creating a second text-field somewhere
> in the window) while it is running?
>
>
> Regards,
> Andr�
> --
> "If Java is your hammer, every problem looks like a thumb"
From: Christophe Rhodes
Subject: Re: Cello Shots (cont'd)
Date: 
Message-ID: <sqbrnu192c.fsf@lambda.dyndns.org>
André Thieme <······································@justmail.de> writes:

> Kenny Tilton wrote:
>
>> Now as soon as I port a textedit widget I can make it into a repl. :)
>
> I think I begin to realize what "The whole language always available"
> means (http://www.paulgraham.com/diff.html).
> So Kenny, if you would have a textedit widget and include a repl,
> could you then change the application (creating a second text-field
> somewhere in the window) while it is running?

Absolutely.  Being able to change running applications "on the fly",
be they web servers or score engravers, is an absolute joy in
comparison with the alternative.  (Usually you don't need a textedit
widget for this unless you are exposing the functionality to the
end-user, though; an emacs in the background generally works just as
well).  Go Lisp.

Christophe
-- 
http://www-jcsu.jesus.cam.ac.uk/~csr21/       +44 1223 510 299/+44 7729 383 757
(set-pprint-dispatch 'number (lambda (s o) (declare (special b)) (format s b)))
(defvar b "~&Just another Lisp hacker~%")    (pprint #36rJesusCollegeCambridge)
From: Artem Baguinski
Subject: dynamicness (dinamicity?) of lisp and its practical side [was: Cello Shots (cont'd)]
Date: 
Message-ID: <87smh6qako.fsf_-_@caracolito.lan>
i hear a lot about dynamic this and dynamic that of lisp and although
it all sounds exciting and all, i haven't figured yet the practical
implications of "the whole language always available". it must be the
years of c coding in vi ;-)

so i've learned how to use emacs, installed cmucl and slime and i
have repl inside emacs next to my source files. what do i do next to
feel the power of the dynamic nature of lisp? 

say, i'm working on a package that provides some useful functionality,
i type it in an editor window, save, jump to repl window,
(use-package "USEFUL-PACKAGE") and i can try the functions of the
module interactivelly. is that what it's all about, or am i missing
some magic? 

then i've found that useful-function is buggy, what do i do now?
change the definition in repl window? or in a text window and then
eval-last-defun and try that out? 

i guess what i'm looking for is a description of other peoples
everyday lisp programming routines... so i can incorporate bits of
your experience in my programming practices ;-)

Christophe Rhodes <·····@cam.ac.uk> writes:
> André Thieme <······································@justmail.de> writes:
>> Kenny Tilton wrote:
>>
>>> Now as soon as I port a textedit widget I can make it into a repl. :)
>>
>> I think I begin to realize what "The whole language always available"
>> means (http://www.paulgraham.com/diff.html).
>> So Kenny, if you would have a textedit widget and include a repl,
>> could you then change the application (creating a second text-field
>> somewhere in the window) while it is running?
>
> Absolutely.  Being able to change running applications "on the fly",
> be they web servers or score engravers, is an absolute joy in
> comparison with the alternative.  (Usually you don't need a textedit
> widget for this unless you are exposing the functionality to the
> end-user, though; an emacs in the background generally works just as
> well).  Go Lisp.



-- 
gr{oe|ee}t{en|ings}
artm 
From: Joe Marshall
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <n07dn6sz.fsf@ccs.neu.edu>
Artem Baguinski <····@v2.nl> writes:

> What do I do next to feel the power of the dynamic nature of lisp? 

Learn to use the debugger.

When your program encounters an error --- an undefined function for
instance --- rather than `abort to top level' and restart, stay within
the error handler.  Define the missing function right now (add it to
the sources where appropriate, and eval-last-defun), test it out a
little from the error-handler repl, and when you are happy with it,
continue from the error.

Or maybe the function is too hairy to define right now, but the answer
you want back is fairly easy to describe.  Use the error handler to
continue as if the function worked by returning a value.  Debug it
later.

Typo in a base class?  Just fix and reload.  No need to recompile
megabytes of sources.  Need to change the class topology?  Go ahead,
it works.  Typo in a function name?  Just stuff the symbol-function of
the correct name into the symbol function of the misspelled one and
continue. 
From: Edi Weitz
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <m3znbehv6m.fsf@bird.agharta.de>
On Fri, 20 Feb 2004 12:01:11 +0100, Artem Baguinski <····@v2.nl> wrote:

> i hear a lot about dynamic this and dynamic that of lisp and
> although it all sounds exciting and all, i haven't figured yet the
> practical implications of "the whole language always available". it
> must be the years of c coding in vi ;-)
>
> so i've learned how to use emacs, installed cmucl and slime and i
> have repl inside emacs next to my source files. what do i do next to
> feel the power of the dynamic nature of lisp?
>
> say, i'm working on a package that provides some useful
> functionality, i type it in an editor window, save, jump to repl
> window, (use-package "USEFUL-PACKAGE") and i can try the functions
> of the module interactivelly. is that what it's all about, or am i
> missing some magic?

No, there's no magic involved. (USE-PACKAGE "FOO") just means that you
can write MY-FUN instead of FOO:MY-FUN if you have exported MY-FUN
from the FOO package.

> then i've found that useful-function is buggy, what do i do now?
> change the definition in repl window? or in a text window and then
> eval-last-defun and try that out?

A common way would be to change the function's definition directly in
the source code and then from there eval-last-defun so the new
function is immediately available in the REPL (together with
everything else that you've loaded and evaluated) so you can check if
it works now.

> i guess what i'm looking for is a description of other peoples
> everyday lisp programming routines... so i can incorporate bits of
> your experience in my programming practices ;-)

Well, maybe not directly related to your question but at least to
"whole language always available:" I've programmed a web-based soccer
sweepstakes. It was originally written in PHP (yuck!) but soon
thereafter converted to Common Lisp (sitting behind an Apache using
Marc Battyani's mod_lisp). I mostly play with a couple of friends but
I've also sold it to a commercial customer who used it successfully
for about 500 of his clients.

Anyway, the game grew more complicated every year and we're always
trying to tune the rules to make it more fun. During this season's
winter break (December 2003) I had to implement some new rules which
took effect in January. After trying out these new rules on my laptop
I connected to the server using Dan Barlow's detachtty and was in my
REPL. There I loaded the new functions, compiled them, and that was
it. It's still the same application that was started last June, all
the objects (players, matches, bets) are still identical to what they
were half a year ago. I think this is quite cool and virtually
impossible with most other languages.

Edi
From: Artem Baguinski
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <87k72ivtwo.fsf@caracolito.lan>
Edi Weitz <···@agharta.de> writes:
> No, there's no magic involved. (USE-PACKAGE "FOO") just means that you
> can write MY-FUN instead of FOO:MY-FUN if you have exported MY-FUN
> from the FOO package.

i guess i had to do my homework better ;)

>> then i've found that useful-function is buggy, what do i do now?
>> change the definition in repl window? or in a text window and then
>> eval-last-defun and try that out?
>
> A common way would be to change the function's definition directly in
> the source code and then from there eval-last-defun so the new
> function is immediately available in the REPL (together with
> everything else that you've loaded and evaluated) so you can check if
> it works now.

and does it work with clos objects and methods? i vaguely remember
that my lisp was complaining when i would decide that generic
function should have different interface and try to re eval new
definition. i even had some intuitive understanding why ;)

> Well, maybe not directly related to your question but at least to

well, it is. thanks

> Anyway, the game grew more complicated every year and we're always
> trying to tune the rules to make it more fun. During this season's
> winter break (December 2003) I had to implement some new rules which
> took effect in January. After trying out these new rules on my laptop
> I connected to the server using Dan Barlow's detachtty and was in my
> REPL. There I loaded the new functions, compiled them, and that was
> it. 

yep, that's the magic i meant ;) 

are the changes you've made persistent? like if the server has to
reboot are they somewhere in files? and can somebody without your
help understand the emerged over the years code?

i mean in say c i'd have all the sources in text files with comments
and all, but if the changes you make are done in REPL, where do you
insert comments? do you have at all the tendency to comment your code
with this work style? 

> It's still the same application that was started last June, all
> the objects (players, matches, bets) are still identical to what they
> were half a year ago. I think this is quite cool and virtually
> impossible with most other languages.


-- 
gr{oe|ee}t{en|ings}
artm 
From: Mario S. Mommer
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <fzllmyeyhc.fsf@germany.igpm.rwth-aachen.de>
Artem Baguinski <····@v2.nl> writes:
> are the changes you've made persistent? like if the server has to
> reboot are they somewhere in files? and can somebody without your
> help understand the emerged over the years code?
> 
> i mean in say c i'd have all the sources in text files with comments
> and all, but if the changes you make are done in REPL, where do you
> insert comments? do you have at all the tendency to comment your code
> with this work style? 

The way I understood Edi was that he programmed and tested this on his
laptop, and I bet he there put comments where appropriate. What he did
on the server was to compile and load this additional file (or even
just a modified file with the new functionality). And voil�.

The way I do this kind of thing is to check out the last version of
the code, and use asdf or defsystem to compile and load only what has
been modified.



Another advantage that the repl has is that all functions have
immediately a command line interface. This does not only help with
debugging, but also lets you build a collection of utilities that help
you with the task at hand. Making appropriate command line utilities
with C is work; with CLs repl you get that for free.
From: Edi Weitz
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <m3d689cytw.fsf@bird.agharta.de>
On Fri, 20 Feb 2004 13:04:39 +0100, Artem Baguinski <····@v2.nl> wrote:

> Edi Weitz <···@agharta.de> writes:
>> A common way would be to change the function's definition directly
>> in the source code and then from there eval-last-defun so the new
>> function is immediately available in the REPL (together with
>> everything else that you've loaded and evaluated) so you can check
>> if it works now.
>
> and does it work with clos objects and methods?

Yes. You can even change the definition of a class and keep the
existing objects belonging to that class.

> i vaguely remember that my lisp was complaining when i would decide
> that generic function should have different interface and try to re
> eval new definition. i even had some intuitive understanding why ;)

All methods belonging to the same generic function must have congruent
lambda lists. If you want to change the interface, i.e. if you want a
different lambda list, you first have to use FMAKUNBOUND to get rid of
the old generic function (and all of its methods).

>> Anyway, the game grew more complicated every year and we're always
>> trying to tune the rules to make it more fun. During this season's
>> winter break (December 2003) I had to implement some new rules
>> which took effect in January. After trying out these new rules on
>> my laptop I connected to the server using Dan Barlow's detachtty
>> and was in my REPL. There I loaded the new functions, compiled
>> them, and that was it.
>
> are the changes you've made persistent? like if the server has to
> reboot are they somewhere in files? and can somebody without your
> help understand the emerged over the years code?

Others have already commented on this but I'll try to summarize the
options that you have:

1. You just change things interactively in the REPL. That way the
   changes definitely aren't permanent and are lost if you reboot the
   machine or restart the Lisp image.

2. You write your changes into patch files and load them (optionally
   compiling them first). You have to load these patch files in the
   right order if you start anew but the benefit is that you can use
   them as a kind of diary of what you did to your app. You can also
   use this method to patch code you've already delivered to customers
   - just send them a FASL file (containing compiled Lisp code) that
   they can LOAD into their app. (This of course assumes that you've
   provided them with some means to use LOAD.)

3. You use something like MK:DEFSYSTEM or ASDF (similar to make(1))
   which keeps track of dependencies and file access times. Now you
   can make changes directly in your source files and ask the system
   definition utility to re-compile and re-load what's necessary.

4. From time to time, i.e. after you've made significant changes, you
   save the whole Lisp image. This isn't part of the ANSI standard but
   virtually every Lisp supports this. If you have to start anew you
   start from the most recently saved image instead of the default
   image and you're back in business.

> i mean in say c i'd have all the sources in text files with comments
> and all, but if the changes you make are done in REPL, where do you
> insert comments? do you have at all the tendency to comment your
> code with this work style?

Yes, I usually provide comments and documentation strings. Otherwise I
tend not to understand what I wrote some months ago... :)

HTH,
Edi.
From: Christopher C. Stacy
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <u3c957lj6.fsf@news.dtpq.com>
>>>>> On Fri, 20 Feb 2004 12:00:49 +0100, Edi Weitz ("Edi") writes:
 Edi> It's still the same application that was started last June, all
 Edi> the objects (players, matches, bets) are still identical to what
 Edi> they were half a year ago. I think this is quite cool and
 Edi> virtually impossible with most other languages.

You've had a live production server running Apache and 
your Lisp application, and it's been running continuously
for at least six months with users?

What OS and Lisp are you using?  I'm amazed that a Unix/Linux/Windows
box could actually stay up in production for that long in the face of
all the critical kernel patches I see every other week.  (On the other
hand, one of my BSD servers usually stays up for about 3 months.)

How is the memory performance of your Lisp application?

How many people are hitting on this thing?

Are you using a database?
From: Edi Weitz
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <m3smh5y8m5.fsf@bird.agharta.de>
On Fri, 20 Feb 2004 16:39:25 GMT, ······@news.dtpq.com (Christopher C. Stacy) wrote:

> You've had a live production server running Apache and your Lisp
> application, and it's been running continuously for at least six
> months with users?

Almost. My ISP had a power outage about four months ago so the machine
had to be restarted. But apart from that the app is the same one that
was started this summer. (I thought this detail was irrelevant with
respect to the OP's question.)

> What OS and Lisp are you using?

Currently Linux with CMUCL. A former system used FreeBSD with CMUCL. I
had preferred to stay with FreeBSD but I switched from a co-located
machine of my own to a rented machine (it's cheaper) and they don't
offer FreeBSD. (Now, I know there certainly are providers out there
offering FreeBSD machines to rent. It's just that I didn't find one
which was able to match all my other criteria.)

> I'm amazed that a Unix/Linux/Windows box could actually stay up in
> production for that long in the face of all the critical kernel
> patches I see every other week.  (On the other hand, one of my BSD
> servers usually stays up for about 3 months.)

I made sure to update Apache[1] and other important apps but I didn't
patch the kernel. I'm kind of reluctant to do that with a machine I
don't have physical access to.

I don't have any important data on this machine. If someone really
breaks in - bad luck...

> How is the memory performance of your Lisp application?

Here's a snapshot from top(1):

    5:55pm  up 122 days,  8:30,  1 user,  load average: 0.00, 0.00, 0.00
  59 processes: 56 sleeping, 3 running, 0 zombie, 0 stopped
  CPU states:  0.1% user,  0.3% system,  0.0% nice, 99.4% idle
  Mem:   256516K av,  252296K used,    4220K free,       0K shrd,   46028K buff
  Swap:  525288K av,   38260K used,  487028K free                   99976K cached

    PID USER     PRI  NI  SIZE  RSS SHARE STAT %CPU %MEM   TIME COMMAND
   4532 edi       15   0 31636  26M 12112 S     0.0 10.5  81:01 lisp
  26977 nobody    15   0 12200 5252  4532 S     0.0  2.0   0:25 httpd
   7025 nobody    15   0  6420 4484  3652 S     0.0  1.7   0:06 httpd
   7489 nobody    15   0  6424 4476  3668 R     0.0  1.7   0:09 httpd
   7466 nobody    15   0  6392 4436  3628 S     0.0  1.7   0:07 httpd
  10433 nobody    15   0  6108 4084  3456 S     0.0  1.5   0:15 httpd
  14312 nobody    15   0  6064 3908  3244 S     0.0  1.5   0:15 httpd
  26975 nobody    15   0  6036 3872  3204 S     0.0  1.5   0:20 httpd

My app calls (EXT:GC :FULL T) once every 24 hours.

> How many people are hitting on this thing?

The current app only has about 30 users. The previous app (which was
deployed commercially) had about 500 registered users with the same
setup and ran continuously for six months without a problem.

> Are you using a database?

All data that I'm using is in memory but every change is logged to a
file so I can restart the app if something breaks - similar to the
"Prevalence" stuff but home-grown. The 500 users app used a PostgreSQL
database as its fallback store but still had everything in RAM.

Edi.

[1] One of the cool things of Marc's mod_lisp is that you can build a
    new Apache and replace the old one while the Lisp image keeps
    running. The perceived downtime for the users is negligible.
From: Henrik Motakef
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <877jyh8j4y.fsf@aenaeas.internal.henrik-motakef.de>
Edi Weitz <···@agharta.de> writes:

> > What OS and Lisp are you using?
> 
> Currently Linux with CMUCL. A former system used FreeBSD with CMUCL. I
> had preferred to stay with FreeBSD but I switched from a co-located
> machine of my own to a rented machine (it's cheaper) and they don't
> offer FreeBSD. (Now, I know there certainly are providers out there
> offering FreeBSD machines to rent. It's just that I didn't find one
> which was able to match all my other criteria.)

(OT: Some (german) hosters offer pretty cheap "root servers", usually
with SuSE or Red Hat preinstalled, where you can easily install
FreeBSD. 1und1 is one important example. It is pretty easy to install
FreeBSD on such a box; there are pre-made scripts on
http://www.rootforum.de, and the "depenguinator" works well too. Just
don't use UFS2 on the root filesystem, the Debian-based rescue system
doesn't handle it, and be aware that the required network settings
(regarding the standard gateway for exampe) might require to violate
one RFC or the other.)

> The current app only has about 30 users. The previous app (which was
> deployed commercially) had about 500 registered users with the same
> setup and ran continuously for six months without a problem.
> 
> > Are you using a database?
> 
> All data that I'm using is in memory but every change is logged to a
> file so I can restart the app if something breaks - similar to the
> "Prevalence" stuff but home-grown.

If you can, you should consider writing that up as a success story.
Given that you consider it a success, that is :-)
From: Edi Weitz
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <m3llmxb9vu.fsf@bird.agharta.de>
On 20 Feb 2004 23:45:49 +0100, Henrik Motakef <······@aenaeas.internal.henrik-motakef.de> wrote:

> OT: Some (german) hosters offer pretty cheap "root servers", usually
> with SuSE or Red Hat preinstalled, where you can easily install
> FreeBSD. 1und1 is one important example.

Yep, the one I'm talking about is a Debian-based "root server" from
Hetzner. A pretty fast machine, actually.[1]

> It is pretty easy to install FreeBSD on such a box; there are
> pre-made scripts on http://www.rootforum.de, and the "depenguinator"
> works well too.

I saw this right after I had set everything up and moved an important
domain (which someone else is paying for) to the new machine. But even
if I had seen it before I probably wouldn't have done it - I'm a
coward.

> Just don't use UFS2 on the root filesystem, the Debian-based rescue
> system doesn't handle it, and be aware that the required network
> settings (regarding the standard gateway for exampe) might require
> to violate one RFC or the other.

What do you mean by that?

> If you can, you should consider writing that up as a success story.
> Given that you consider it a success, that is :-)

Probably not. It now is a private game for a couple of friends and
it's nothing spiffy.

Well, maybe except for one thing: Most of the pages of this app
consist of large tables (showing bets, standings, quotas, and other
stuff) potentially having thousands of cells each of which has to be
computed before it's displayed.

If you use one of the often-touted "LAMP" systems (i.e. PHP or Perl
with an RDBMS) your only chance is, for each page, to get the base
data out of the database and then compute each cell. (Well, unless
you're doing some very sick stuff with shared memory...)

In my CL app each cell is a slot of a CLOS object (and these objects
are always in RAM, see my other posting). Each slot is initially
unbound and is computed "on demand" with something like:

  (defmethod slot-unbound :around ((class t)
                                   (bet bet)
                                   (slot-name (eql 'win)))
    (cond ((null (toto (match bet)))
            nil)
          (t (setf (slot-value bet 'win)
                     (win-for-bet bet)))))

So, the slot's value is computed exactly once and then re-used by
other pages or subsequent requests to the same page.

On the other hand, care is taken to invalidate these slots when the
data they depend on changes. This might look like:

  (defmethod (setf pcl:slot-value-using-class) :after
      (new-value class (match match) slot)
    (case (pcl:slot-definition-name slot)
      ((category)
        (slot-makunbound match 'value)
        (slot-makunbound match 'win)
        (dolist (bet (bets-for-match match))
          (slot-makunbound bet 'win)))
      ;; and so on...

I'm pretty sure someone else has done this before[2] but I thought
this was rather cool when I "invented" it. It also showed me - once
again - how cool CLOS is.

Cheers,
Edi.


[1] <http://www.hetzner.de/price_performance.htm>
    (see "Best Performance")

[2] Actually, before Kenny Tilton starts his usual marketing rant, I
    should mention that I think this might be the kind of application
    his "Cells" are made for. If only they had reasonable
    documentation such that mere mortals like me could use them... :)
From: Ng Pheng Siong
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <c181e3$ghv$1@reader01.singnet.com.sg>
According to Henrik Motakef  <······@aenaeas.internal.henrik-motakef.de>:
> (OT: Some (german) hosters offer pretty cheap "root servers", usually
> with SuSE or Red Hat preinstalled, where you can easily install
> FreeBSD. 

I spoke with one in Germany and one in US. In both cases CMUCL's startup
RAM requirement is too big.


-- 
Ng Pheng Siong <····@netmemetic.com> 

http://firewall.rulemaker.net -+- Firewall Change Management & Version Control
http://sandbox.rulemaker.net/ngps -+- Open Source Python Crypto & SSL
From: Bulent Murtezaoglu
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <87d6881hle.fsf@cubx.internal>
>>>>> "Ng" == Ng Pheng Siong <····@netmemetic.com> writes:
[...]
    Ng> I spoke with one in Germany and one in US. In both cases
    Ng> CMUCL's startup RAM requirement is too big. [...]

What platform is this?  (what OS, what virtualization SW etc.)  

thanks,

BM
From: Ng Pheng Siong
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <c1d2vd$5pv$1@reader01.singnet.com.sg>
According to Bulent Murtezaoglu  <··@acm.org>:
> >>>>> "Ng" == Ng Pheng Siong <····@netmemetic.com> writes:
>     Ng> I spoke with one in Germany and one in US. In both cases
>     Ng> CMUCL's startup RAM requirement is too big. [...]
> 
> What platform is this?  (what OS, what virtualization SW etc.)  

FreeBSD jails. 

I should point out that the decisions in both cases were business, not
technical.

Anyways I have my own colo boxen now.

Cheers.

-- 
Ng Pheng Siong <····@netmemetic.com> 

http://firewall.rulemaker.net -+- Firewall Change Management & Version Control
http://sandbox.rulemaker.net/ngps -+- Open Source Python Crypto & SSL
From: Bulent Murtezaoglu
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <874qtlbr6e.fsf@cubx.internal>
>>>>> "CCS" == Christopher C Stacy <······@news.dtpq.com> writes:
[...]
    CCS> ... I'm amazed that a
    CCS> Unix/Linux/Windows box could actually stay up in production
    CCS> for that long in the face of all the critical kernel patches
    CCS> I see every other week.  ...

Depends on what those patches are for.  I have a little machine I left
in colo that's been up since Oct 2001.  For a long time it acted as a
port-forwarding firewall for a windows machine alongside handling
mail/web hosting/ftp for a handful of users.  One of the users was a
composer with huge mp3's that saw traffic.  I believe it went through
3 IP changes w/o rebooting also.  I haven't even updated the
distribution on it when debian stopped supporting the version it has
(that latter bit is because I am now thousands of miles away from it
and I don't see the point of doing it).  As folks moved away from it I
firewalled off and turned off services, and when ssh turned out to be
vulnerable I left it open to only a few select IPs.  The kernel
vulnerabilities that I know of have been locally (not remotely)
exploitable in this time period.  (this is Linux kernel 2.2.19).  My
only problem has been that uptime resets after 400+xx days.

The point, other than advertising luck and jinxing it, is that unless
a critical patch affects what you do, it is irrelevant -- you don't
need to patch and reboot.  Besides, unless it is a kernel patch you 
probably don't need to reboot at all.

Check netcraft's uptime thing and you'll see machines staying up a long 
time is not unusual.

cheers,

BM
From: Rob Warnock
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <67KcnfTzIpEV5abd3czS-g@speakeasy.net>
Christopher C. Stacy <······@news.dtpq.com> wrote:
+---------------
| >>>>Edi Weitz ("Edi") writes:
| Edi> It's still the same application that was started last June, all
| Edi> the objects (players, matches, bets) are still identical to what
| Edi> they were half a year ago. I think this is quite cool and
| Edi> virtually impossible with most other languages.
| 
| You've had a live production server running Apache and 
| your Lisp application, and it's been running continuously
| for at least six months with users?
+---------------

You're suprised at that? I'm not. Here's a Linux-based web server I
access a lot that uses Apache (and is soon about to run *my* Lisp
application, too):

    % uname -mrs
    Linux 2.4.3-12.2RS i586
    % uptime
      9:56am  up 295 days,  3:26,  1 user,  load average: 0.35, 0.13, 0.10
    % 

+---------------
| What OS and Lisp are you using?  I'm amazed that a Unix/Linux/Windows
| box could actually stay up in production for that long in the face of
| all the critical kernel patches I see every other week.  (On the other
| hand, one of my BSD servers usually stays up for about 3 months.)
+---------------

*Only* three months?  ;-}  ;-}

    % uname -mnrs
    FreeBSD fast.rpw3.org 4.6-RELEASE i386
    % uptime
     7:52AM  up 434 days,  3:09, 15 users, load averages: 0.00, 0.00, 0.00
    % 

Note: That's my home/business workstation/server. Now that it's been up
for more that a year[1], I suppose I really should take it down long enough
to upgrade to FreeBSD 4.9-RELEASE (which is what's on the laptop).

+---------------
| How many people are hitting on this thing?
+---------------

Not very many at one time, to be sure.  ;-}

+---------------
| Are you using a database?
+---------------

Dunno 'bout Edi, but I am[2]:

    % psql -V
    psql (PostgreSQL) 7.3.4
    % 


-Rob

[1] After five power outages in one weekend in late 2002 -- each much
    less than a minute, but each quite sufficient to crash/reboot the
    machine! -- I finally bought a UPS. It works quite nicely.

[2] From CMUCL, via Eric Marsden's "pg.lisp".

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Daniel Barlow
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <87ad37s7ce.fsf@noetbook.telent.net>
····@rpw3.org (Rob Warnock) writes:

> | How many people are hitting on this thing?
> +---------------
>
> Not very many at one time, to be sure.  ;-}

eval.metacircles.com, the machine that runs cliki (and telent.net and
the ALU Wiki and a bunch of other sites) exists primarily as a host
for www.stargreen.com - a Lisp application using SBCL and Postgres
(I'm using Eric's pg.lisp too).  It sold several thousand tickets for
Red Hot Chili Peppers concerts last Saturday.

Benchmarking suggests it can currently cope with around 1000
orders/hour (each of which represents about ten page requests, plus
associated graphics, and some interesting database queries/updates).
I'm pretty sure I could get more out of it, but there's no obvious
bottleneck in profiling, so right now it'd be cheaper just to throw
hardware at the problem.  It goes a lot faster on static pages
(apache's caching helps, of course) but static pages are essentially
uninteresting on an ecommerce site.

:; attach-stargreen
;;; attachtty: 1077709635: connecting through ssh to [details removed] on [removed]@web.metacircles.com

;;; attachtty: 1077709635: Successfully started
Logged error: 404 Not Found NIL
;;; attachtty: 1077709441: connecting directly to [details removed]

0
0
* (lisp-implementation-version)

"0.8.4.9"


-dan

-- 
"please make sure that the person is your friend before you confirm"
From: Artem Baguinski
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <87u11la8dx.fsf@caracolito.lan>
i reread carefully all the answers, thank you everybody, and i guess
i'm a bit confused how it works. 

say, i have a lisp program that has it's own loop and it has to do
stuff in this loop very actively, e.g. it performs some music
applying effects in realtime. it's pretty autonomous and knows how to
improvise and where to get inspiration, but nevertheless now and then
i'd like to change some aspects of it. say, i want to say (be mozart)
or (be bethoven) in REPL and hear the difference at the next measure. 

what i don't understand is how it is both doing the fast dsp loop and
waits for me to type something in repl. do i have to program it to do
that way or do i get such functionality for free? what manual should
i read to learn how to do something like that?

i guess in a web server your lisp program doesn't have to be in a
main loop, but rather some functions are triggered when apache
receives a request from a client. but still, it's not that different
from my (hypothetical) situation.

Edi Weitz <···@agharta.de> writes:

> Well, maybe not directly related to your question but at least to
> "whole language always available:" I've programmed a web-based soccer
> sweepstakes. It was originally written in PHP (yuck!) but soon
> thereafter converted to Common Lisp (sitting behind an Apache using
> Marc Battyani's mod_lisp). I mostly play with a couple of friends but
> I've also sold it to a commercial customer who used it successfully
> for about 500 of his clients.
>
> Anyway, the game grew more complicated every year and we're always
> trying to tune the rules to make it more fun. During this season's
> winter break (December 2003) I had to implement some new rules which
> took effect in January. After trying out these new rules on my laptop
> I connected to the server using Dan Barlow's detachtty and was in my
> REPL. There I loaded the new functions, compiled them, and that was
> it. It's still the same application that was started last June, all
> the objects (players, matches, bets) are still identical to what they
> were half a year ago. I think this is quite cool and virtually
> impossible with most other languages.
>
> Edi

-- 
gr{oe|ee}t{en|ings}
artm 
From: Peter Seibel
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <m34qtlmv4z.fsf@javamonkey.com>
Artem Baguinski <····@v2.nl> writes:

> i reread carefully all the answers, thank you everybody, and i guess
> i'm a bit confused how it works. 
> 
> say, i have a lisp program that has it's own loop and it has to do
> stuff in this loop very actively, e.g. it performs some music
> applying effects in realtime. it's pretty autonomous and knows how to
> improvise and where to get inspiration, but nevertheless now and then
> i'd like to change some aspects of it. say, i want to say (be mozart)
> or (be bethoven) in REPL and hear the difference at the next measure. 

In a case like this you'll need a multithreaded lisp. So your music
generator will be running in one thread while you can continue to
interact with the REPL in another thread. Because the threads will
share memory, changes made at the REPL will affect the music loop.

> what i don't understand is how it is both doing the fast dsp loop and
> waits for me to type something in repl. do i have to program it to do
> that way or do i get such functionality for free? what manual should
> i read to learn how to do something like that?

It depends how you interact with your Lisp. For instance Allegro's ELI
(Emacs Lisp Integration) provides very straightforward ways to
interact with multiple threads in their Lisp. SLIME is moving in that
direction (or may already have arrived there) for lisps that support
multithreading. And other multithreaded Lisp's that have their own
IDE's presumably provide some mechanism for interacting with different
threads.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Kenny Tilton
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side
Date: 
Message-ID: <PRsZb.161486$cM1.29888223@twister.nyc.rr.com>
Artem Baguinski wrote:

> i reread carefully all the answers, thank you everybody, and i guess
> i'm a bit confused how it works. 
> 
> say, i have a lisp program that has it's own loop and it has to do
> stuff in this loop very actively, e.g. it performs some music
> applying effects in realtime. it's pretty autonomous and knows how to
> improvise and where to get inspiration, but nevertheless now and then
> i'd like to change some aspects of it. say, i want to say (be mozart)
> or (be bethoven) in REPL and hear the difference at the next measure. 

I do that all the time these days. I am using a C package known as 
Freeglut to provide a portable windows/event stream for my CL gui 
(someday someone may replace that with cl-glut and make life a lot 
easier, but that is neither here nor there). Now the way this works is 
that I set up callbacks into Lisp from Freeglut, then call an FG 
function which does not return until I tell it to stop. Unfortunately FG 
has a bug I have yet to address that makes it peg the CPU, I guess 
looping when it should be waiting for events. I'll cut to the chase. 
When my code hits an error, AllegroCL puts up a notice and invites me to 
abort or debug. neither button works, in my experience because Freeglut 
has the pedal to the metal calling me.

Fortunately I /can/ still click on the repl window and execute a command 
that sets a special variable called *stop*. In a bunch of low-level code 
it says (unless *stop*... ). So at the repl I just say (setf *stop* t) 
and now the debug and abort buttons are responsive.

Btw, i am not sure this will work under other CL implementations. If I 
run into one where this does not work, well, I'll just break down and 
debug Freeglut.

kenny

-- 
http://tilton-technology.com

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film

Your Project Here! http://alu.cliki.net/Industry%20Application
From: Eric Blood
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was:  Cello Shots (cont'd)]
Date: 
Message-ID: <c17vld01kuu@enews4.newsguy.com>
Artem Baguinski wrote:
> i guess what i'm looking for is a description of other peoples
> everyday lisp programming routines... so i can incorporate bits of
> your experience in my programming practices ;-)

One thing I think would be neat, is to see a video of a pro in their 
"element"--sort of like Rainer with the Symbolics videos, but using 
everyday tools like Slime with SBCL or Allegro, etc.  For beginners, 
showing off basic things like how to debug code, or create a new package 
with some basic functionality.  For the rest, just show how good you 
are.  =)

It would be important to keep the video short, to talk about what is 
being doing, and the keystrokes.

-- 
eblood
From: Michael Walter
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was:    Cello Shots (cont'd)]
Date: 
Message-ID: <c182it$1fckcj$1@ID-88904.news.uni-berlin.de>
Eric Blood wrote:
> 
> Artem Baguinski wrote:
> 
>> i guess what i'm looking for is a description of other peoples
>> everyday lisp programming routines... so i can incorporate bits of
>> your experience in my programming practices ;-)
> 
> 
> One thing I think would be neat, is to see a video of a pro in their 
> "element"--sort of like Rainer with the Symbolics videos, but using 
> everyday tools like Slime with SBCL or Allegro, etc.  For beginners, 
> showing off basic things like how to debug code, or create a new package 
> with some basic functionality.  For the rest, just show how good you 
> are.  =)
> 
> It would be important to keep the video short, to talk about what is 
> being doing, and the keystrokes.
> 
Yeah, that would be most awesome. Well, IMO a simple "log" of an 
experienced person doing typical work would already be cool if that's 
easier to do -- but something like that would definately rock (and be a 
good possibility to demonstrate to other people lisp's abilities).

Cheers,
Michael
From: rif
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was: Cello Shots (cont'd)]
Date: 
Message-ID: <wj0smh4m6br.fsf@five-percent-nation.mit.edu>
Yeah, I would also find this very valuable.  I've been using CL for
over a year now, and love it, but I stil feel like I'm almost
certainly not making full use of the tools.

rif
From: Rainer Joswig
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was:  Cello Shots (cont'd)]
Date: 
Message-ID: <c366f098.0402220157.2f36d3e5@posting.google.com>
Eric Blood <······@winkywooster.org> wrote in message news:<···········@enews4.newsguy.com>...
> Artem Baguinski wrote:
> > i guess what i'm looking for is a description of other peoples
> > everyday lisp programming routines... so i can incorporate bits of
> > your experience in my programming practices ;-)
> 
> One thing I think would be neat, is to see a video of a pro in their 
> "element"--sort of like Rainer with the Symbolics videos, but using 
> everyday tools like Slime with SBCL or Allegro, etc.  For beginners, 
> showing off basic things like how to debug code, or create a new package 
> with some basic functionality.  For the rest, just show how good you 
> are.  =)
> 
> It would be important to keep the video short, to talk about what is 
> being doing, and the keystrokes.

I've done two videos about LispWorks and one short with MCL.
They are sometimes available on my homepage (determined by a Lisp
function ;-) ).

These videos are not really done as a programmer's introduction.
More like showing a bit look and feel of the IDE.
From: Matthias
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was: Cello Shots (cont'd)]
Date: 
Message-ID: <36w3c95d8si.fsf@goya02.ti.uni-mannheim.de>
Artem Baguinski <····@v2.nl> writes:

> i hear a lot about dynamic this and dynamic that of lisp and although
> it all sounds exciting and all, i haven't figured yet the practical
> implications of "the whole language always available". it must be the
> years of c coding in vi ;-)
> 
> so i've learned how to use emacs, installed cmucl and slime and i
> have repl inside emacs next to my source files. what do i do next to
> feel the power of the dynamic nature of lisp? 

One possibility is to offer (part of the) the power to your user.  I
learned programming in Pascal, and one of the first applications I
tried to do was a program plotting mathematical functions and
fractals.  Had to write a parser & evaluator for formulas (so the user
could enter the formulas to visualize).  Not much fun for a beginner.

With Lisp I would just have called eval.
From: Rob Warnock
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was: Cello Shots (cont'd)]
Date: 
Message-ID: <z6acnWgrQt2fPabd3czS-w@speakeasy.net>
Artem Baguinski  <····@v2.nl> wrote:
+---------------
| then i've found that useful-function is buggy, what do i do now?
| change the definition in repl window? or in a text window and then
| eval-last-defun and try that out? 
+---------------

Yes, but as you've guessed, that probably won't get you very excited.

+---------------
| i guess what i'm looking for is a description of other peoples
| everyday lisp programming routines...
+---------------

O.k., here's where it really wins for me [and I'm sorry for the long
wind-up, but as is typically the case, the advantages don't really show
in the simple cases]:

I'm developing some Lisp-based middleware for a web application -- that is,
there's an Apache web server and a PostgreSQL database and a CMUCL image
in the middle that gets requests from Apache[1] and pokes around in the
database and eventually spits out some HTML via Apache to the browser user.
A typical development session has the following windows open[2]:

- A Netscape browser window.

- An "xterm"[3] to the REPL[4] of the middleware.

- One or more editor windows into the application's Lisp code.

- [Sometimes] Another "xterm" open running "psql", the command-line
  interface to the PostgreSQL database.

Now you might not want to do exactly the following in production,
because running the ASDF[5] "LOAD-OP" does add a few milliseconds
to the access even if it has nothing to do, but during development
the following is *terribly* convenient:

   % cd /usr/local/apache/htdocs/some/path

   % grep -i lisp .htaccess
   # sock.cgi is the little CGI trampoline that connects to the Lisp process.
   Action lisp-handled-pages /sock.cgi
   AddHandler lisp-handled-pages .lhp

   % cat foo.lhp
   ;;; Boilerplate for using ASDF from LHP page.
   (flet ((this-page (http-request)
	    (asdf:operate 'asdf:load-op "foo")  ; Ensure up-to-date each time.
	    ;; Must explicitly INTERN, since package may not exist before now.
	    (funcall (intern "MAIN" "FOO") http-request)))
     (lhp-set-page-function #'this-page))
   % 

Don't worry about all that LHP stuff (it's part of the infrastructure of
the persistent Lisp server), except to note that the very first time the
page <URL://http:my.domain/some/path/foo.lhp> gets accessed, that little
bit of Lisp code gets LOADed and the function #'THIS-PAGE gets registered
as the handler for that URL. Then #'THIS-PAGE will be called, which will
compile & load all of the files in the "FOO" subsystem (via the ASDF call),
and then finally will call FOO::MAIN (which should "do stuff" based on the
data in the HTTP request block and/or the POST data, and emit some HTML).

Now here's the development cycle:

1. Using the Netscape window, access [or later, "Reload"] the page.
   (If nothing has changed, this will just call FOO::MAIN.)

2. In the REPL window, note the logging of the web request, and the
   results of the ASDF:OPERATE (if any). In the Netscape window, see
   if you got the correct HTML results displayed.

3. If there were compile errors, fix them in an editor window, "Save"
   the file [but stay in the editor], and go back to #1, which will
   automatically (thanks to ASDF) re-do the compile & load (but of only
   the sources which changed and the modules that depended on those).

4. If there were logic errors [that is, the output to the browser wasn't
   correct], you can edit the source, save it, and go back to #1, which
   will recompile whatever's needed and try the access again.

As far as *finding* your problem, you can:

1. Use the REPL window to poke at bits at the last web request, e.g.:

	app_srv> (http-request-method *req0*)
	"GET"
	app_srv> (http-request-self *req0*)
	"/~rpw3/foo.lhp"
	app_srv> (http-request-xpath *req0*)
	"/u/rpw3/public_html/foo.lhp"
	app_srv> (let ((h (http-request-handler *req0*)))
		   (uri-handler-function h))
	#<Closure Over ORG.RPW3.CGI.LHP::CACHED-LHP-PAGE-FUNC {48335039}>
	app_srv> 

2. You can trace/untrace one or more routines within the app, then hit
   "Reload" on the browser and watch the call graph flow.

3. You can call the lower-level functions of the application directly
   from the REPL, and look at the results. [It is helpful to have a
   wrapper function that will "clone" an existing HTTP-request block
   and call its handler function, but with output to the REPL stream.]

4. You can hand-code some debugging functions [in another editor window]
   and LOAD them into the image, then edit the app's code to call them
   at strategic points.

5. If you're getting unexpected conditions being thrown, you can cause
   a backtrace to come out on the REPL, and either choose to enter the
   debugger or not. [The wrapper mentioned in #3 is helpful here, too.]

And so on, the usual stuff.

The point is that the it gives you "fingers" into almost every aspect
of the running system. The time around the "try/oops!/debug/fix" loop --
just minutes, sometimes just seconds! -- is *VERY* much shorter than
if you had to do a traditional "make" and restart the whole middleware
server each time. I find it *tremendously* productive!

[And all the while, the part of the web site you're *not* working on can
continue to be accessed without interruption, if you need to do that...]


-Rob

p.s. Oh, and did I mention that all of the HTML gets generated using
Lisp macros[6]?  Displaying the results of a database query in an HTML
table is really easy when you can intermingle your Lisp code and HTML
using a single syntax (S-exprs) for both:

  (let ((column-names (first results))
        (rows (rest results))
	(stream (http-request-stream request)))
    (with-html-output (s stream t)
      (:table (:border 1 :cellspacing 0 :cellpadding 1) ; make compact
        (:tr ()
          (dolist (name column-names)
            (htm (:th (:nowrap) name))))
        (dolist (row rows)
          (htm (:tr ()
                 (dolist (item row)
                   (htm (:td (:nowrap) (esc item))))))))))

==========
Footnotes:
[1] Not exactly the same as "mod_lisp" <URL:http://www.cliki.net/mod_lisp>,
    but close: a *tiny* C-coded CGI trampoline connects to the CMUCL image
    via a Unix-domain socket, then speaks a "mod_lisp"-like protocol to it.

[2] When I was just starting out with using Common Lisp in web apps it was
    using classical CGI, in which a whole fresh CLISP or CMUCL image would
    get fork/exec'd for each page hit. In that case, I found it useful to
    have another "xterm" running "tail -f /usr/local/apache/logs/error_log"
    to see the error messages in realtime. Now, though, with condition
    handlers wrapped around the HTTP request handling code, you can see
    any problems directly on the main REPL window (or in the dribble log
    "detachtty"[3] provides).

[3] Well, the "xterm" is *actually* running "attachtty" connected to a
    "detachtty" <URL:http://www.cliki.net/detachtty> that started the
    Lisp image at boot time, giving REPL access to the detached daemon.
    Note that accesses to the server also get logged there, e.g.:

      ; Feb 24 08:29:45.11 cgi-sock[723]: GET "/lhp/clhs"
      ; Feb 24 08:29:53.69 cgi-sock[724]: GET "/lhp/clhs?state=quick&pat=db"

    and that "detachtty" supports a dribble log file, so that you don't
    miss stuff that happens when you weren't watching. [The script I use to
    run "attachtty" does a "tail -30" of the dribble file before exec'ing
    "attachtty", which provides easy access to some recent history.]

[4] The server supports additional REPLs with a "telnet /path/to/.sock.repl",
    which connects via a different Unix-domain socket to the CMUCL image
    and starts up another top-level REPL thread, but in practice I've
    found I don't really use those much -- the single "attachtty/detachtty"
    is usually enough.

[5] <URL:http://www.cliki.net/asdf>
    <URL:http://www.cliki.net/ASDF%20System>

[6] <URL:http://www.cliki.net/htout>

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Marc Battyani
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was: Cello Shots (cont'd)]
Date: 
Message-ID: <c1gooo$31t@library1.airnews.net>
"Rob Warnock" <····@rpw3.org> wrote

[...]
> Footnotes:
> [1] Not exactly the same as "mod_lisp" <URL:http://www.cliki.net/mod_lisp>,
>     but close: a *tiny* C-coded CGI trampoline connects to the CMUCL image
>     via a Unix-domain socket, then speaks a "mod_lisp"-like protocol to it.

Tss, tss, a CGI trampoline...
mod_lisp is the only mod_lisp ;-)

Marc
From: Rob Warnock
Subject: Re: dynamicness (dinamicity?) of lisp and its practical side [was: Cello Shots (cont'd)]
Date: 
Message-ID: <J9ScnX0MHsWfbqbd3czS-w@speakeasy.net>
Marc Battyani <·············@fractalconcept.com> wrote:
+---------------
| "Rob Warnock" <····@rpw3.org> wrote
| > Footnotes:
| > [1] Not exactly the same as "mod_lisp" <URL:http://www.cliki.net/mod_lisp>,
| >     but close: a *tiny* C-coded CGI trampoline connects to the CMUCL image
| >     via a Unix-domain socket, then speaks a "mod_lisp"-like protocol to it.
| 
| Tss, tss, a CGI trampoline...
| mod_lisp is the only mod_lisp ;-)
+---------------

Yes, yes, I know. (*blush*)  But I at the time I wrote it there were
acceptance issues which made it easier to use Lisp if the existing
Apache server didn't have to be modified (or even restarted!) to add
the Lisp server. And the CGI trampoline ran plenty fast enough on the
target platform, ~100 requests/sec (as measured with "ab"), while
the user load was never expected to be more than ~100 requests/HOUR!
[For comparison, on the same machine, a trivial Perl CGI script got
only ~140 req/sec, not that much better.]  So it seemed a "good enough"
tradeoff.

And once the Lisp server has been running for a while, well, one can
always go back and say, "You know, we could speed this up a bit if
you'd let me install this simple little Apache module..."  ;-}  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607