From: Alan Crowe
Subject: Nested case statements
Date: 
Message-ID: <86wu7tfoqx.fsf@cawtech.freeserve.co.uk>
Background
----------
There are various autoformat tools for composing HTML.
They transform a "convenience language" into HTML.
An example of what they do is transforming
"That's /really/ cool :->" to
"That's <i>really</i> cool :-&gt;"

Well, it's a nice idea, but if one pursues it, one will end
up with a style sheet, specifying the transformation. The 
convenience language and the style sheet language will be two
new computer languages. The last thing the world needs is
more computer languages.

So I thought "how about just having some Lisp code?". The
convenience language is deliberately incomplete and
underspecified to the point of barely existing. If it would
be convenient to have a particular feature, for the pages
one is working on this week, one hacks it into the Lisp
code, and hacks it out again when it has served its
purpose. Thus the Lisp code plays the role of the style
sheet.

Problem
-------
My Lisp code is turning into a big state machine.

(case state
  (paragraph (case line-type
               (plain ...
               (bullet ...)))
  (blockquote (case line-type
                (plain ...

this is going to be too messy to use as a style sheet,
unless I get a grip on the code somehow.

I've various ideas, but I'm not experienced with Lisp, so
I'm looking for criticism.

1)The nested case statements sprawl into
  ugliness due to having a snippet of code at each leaf

Perhaps I can terminate the tree of case statements in a
function call

(case state
  (paragraph (case line-type
               (plain (continue-paragraph))
               (bullet (start-list)))
  (blockquote (case line-type
               ((plain bullet)(continue-blockquote)); no lists in blockquote

and have a pile of defuns spelling out how to continue a
paragraph, how to continue a block quote, etc. Then I can
read my code and keep my bearings even as it gets complicated

Sub-issue: defun or defmacro?

My functions will have to access lexical variables, for
example to update the state or write to the correct
stream. I've at least four options.

     1)Parameterise my calls eg (continue-paragraph state stream)
     2)Make relevant variables global
     3)Make them special, then all my defuns begin
	  (defun foo()
	    (declare (special state stream))
	    .....
       I would define a macro defsun as a wrapper round defun to
       do that for me
     4)Use defmacro, so that I'm using defmacro in a trivial way
       just to organise things like continue-paragraph in a tidy
       minded way while abusing lexical scope

2)An alternative idea to using a tree of case statements is write
methods specialized on individual states and line classifications.

(defmethod state-machine ((state (eql 'paragraph))
                          (line-type (eql 'plain)))
  "Continue paragraph"
  ...)

This feels like ripping the class dispatch mechanism out of
CLOS to use on its own. Is it a daft idea?

Alan Crowe
Edinburgh
Scotland

From: Pascal Costanza
Subject: Re: Nested case statements
Date: 
Message-ID: <bu5vje$pa8$1@newsreader2.netcologne.de>
Alan Crowe wrote:

> 2)An alternative idea to using a tree of case statements is write
> methods specialized on individual states and line classifications.
> 
> (defmethod state-machine ((state (eql 'paragraph))
>                           (line-type (eql 'plain)))
>   "Continue paragraph"
>   ...)
> 
> This feels like ripping the class dispatch mechanism out of
> CLOS to use on its own. Is it a daft idea?

No, I think it's an excellent idea, and probably the Right Thing (tm) 
for your purposes.

Classes and generic functions are pretty much independent features in 
CLOS, and each of them has advantages that you can benefit from without 
necessarily making use of the other.


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Frank A. Adrian
Subject: Re: Nested case statements
Date: 
Message-ID: <pan.2004.01.15.22.01.49.559787@ancar.org>
On Thu, 15 Jan 2004 11:13:58 +0000, Alan Crowe wrote:


> Sub-issue: defun or defmacro?
> 
> My functions will have to access lexical variables, for
> example to update the state or write to the correct
> stream. I've at least four options.
> 
>      1)Parameterise my calls eg (continue-paragraph state stream)
>      2)Make relevant variables global
>      3)Make them special, then all my defuns begin
> 	  (defun foo()
> 	    (declare (special state stream))
> 	    .....
>        I would define a macro defsun as a wrapper round defun to
>        do that for me
>      4)Use defmacro, so that I'm using defmacro in a trivial way
>        just to organise things like continue-paragraph in a tidy
>        minded way while abusing lexical scope

If you use macros to generate the case statements, it would allow the
simple access to lexical values.  You can also possibly use this FSM
generator in other places.  It is also your most efficient solution,
should this be an issue. These are the reasons why I'd prefer this method.


> 2)An alternative idea to using a tree of case statements is write
> methods specialized on individual states and line classifications.
> 
> (defmethod state-machine ((state (eql 'paragraph))
>                           (line-type (eql 'plain)))
>   "Continue paragraph"
>   ...)
> 
> This feels like ripping the class dispatch mechanism out of CLOS to use
> on its own. Is it a daft idea?

No, but I prefer the case formulation because of the following:

The class formulation kills simple access to lexical vars shared between
the transition code.
The class formulation is slower.
The distributed definition of the state machine makes it a bit
easier to muck things up accidentally by getting parts of the machine out
of sync.
I think of an FSM as an object that's state-oriented with transitions
associated with states, rather than as a set of disjoint states and
transitions - as the class dispatch method would make it - and prefer to
see the definition in a similar form, within a single state-oriented
definition.
The set of state classes tend to bloat the conceptual space of classes.
The use of a heavy item like a class when a simple symbol would do also
seems like a bit of overkill to me.

faa
From: Tim Bradshaw
Subject: Re: Nested case statements
Date: 
Message-ID: <ey3llo7iktr.fsf@lostwithiel.cley.com>
* Frank A Adrian wrote:

> The class formulation kills simple access to lexical vars shared between
> the transition code.

True.

> The class formulation is slower.

This is *doing IO*.  Even if it isn't, it's never worth optimising
something until you have to, and you can almost certainly take
something that takes the class-based definition and builds a
completely optimised machine from it.  This is Lisp!

> The distributed definition of the state machine makes it a bit
> easier to muck things up accidentally by getting parts of the machine out
> of sync.

But it makes really cool things, like being able to load, dynamically,
bits of the state machine, really easy.

Sorry if this seems a bit snippy.  I've just spent half a day trying
to persuade people that my perl script that can generate 200,000
redirects a second doesn't need optimising any more, we need < 10
redirects per second, while desperately trying to suppress the urge to
scream while watching people look in *completely* the wrong place for
memory problems in their Java system (no, it's *not* ephemeral
allocation from string operations which never make it outside the
nursury and get collected instantly, it's thousands of long-lived
session objects which end up tenured...)

--tim
From: Tayssir John Gabbour
Subject: Re: Nested case statements
Date: 
Message-ID: <866764be.0401161919.70b8b148@posting.google.com>
Tim Bradshaw <···@cley.com> wrote in message news:<···············@lostwithiel.cley.com>...
> Sorry if this seems a bit snippy.  I've just spent half a day trying
> to persuade people that my perl script that can generate 200,000
> redirects a second doesn't need optimising any more, we need < 10
> redirects per second, while desperately trying to suppress the urge to
> scream while watching people look in *completely* the wrong place for
> memory problems in their Java system (no, it's *not* ephemeral
> allocation from string operations which never make it outside the
> nursury and get collected instantly, it's thousands of long-lived
> session objects which end up tenured...)

Maybe I miss what you mean but a simple java memory debugger like
jprobe could save thousands in costs.  Assuming they're simply
perturbing code and seeing if their mem problems magically disappear,
having meetings about it and all that.

In the ideal world you'd get referral fees for such tools, but maybe
in the dilbert world you'd just have nominated yourself for all the
debugging.
From: Tim Bradshaw
Subject: Re: Nested case statements
Date: 
Message-ID: <ey3d69ivkfq.fsf@lostwithiel.cley.com>
* Tayssir John Gabbour wrote:

> Maybe I miss what you mean but a simple java memory debugger like
> jprobe could save thousands in costs.  Assuming they're simply
> perturbing code and seeing if their mem problems magically disappear,
> having meetings about it and all that.

No, they're using some kind of memory thing, but they're looking at
allocation rates (lots of strings) not object lifetimes & GC
behaviour.

--tim
From: Tayssir John Gabbour
Subject: Re: Nested case statements
Date: 
Message-ID: <866764be.0401180148.56fbc10a@posting.google.com>
Tim Bradshaw <···@cley.com> wrote in message news:<···············@lostwithiel.cley.com>...
> No, they're using some kind of memory thing, but they're looking at
> allocation rates (lots of strings) not object lifetimes & GC
> behaviour.

Unless their tool interacts with the GC to obscure problems, this
madness actually requires some effort.  Even cheap Java tools make
pretty graphs and say things like, "Monkey, you've got 80 megs wrapped
up in instances of class Frobule."
From: james anderson
Subject: Re: Nested case statements
Date: 
Message-ID: <40069ED3.A806FA84@setf.de>
Alan Crowe wrote:
> ...
> 
> 2)An alternative idea to using a tree of case statements is write
> methods specialized on individual states and line classifications.
> 
> (defmethod state-machine ((state (eql 'paragraph))
>                           (line-type (eql 'plain)))
>   "Continue paragraph"
>   ...)


if you use singletons rather than eql specializers, you have more options when
combining methods.

...
From: Alan Crowe
Subject: Re: Nested case statements
Date: 
Message-ID: <86u12xf8i7.fsf@cawtech.freeserve.co.uk>
james anderson wrote:
> if you use singletons rather than eql specializers, you
> have more options when combining methods.

Aaargh, that suggestion exposes a gap in my knowledge. The
hyperspec only says:

     singleton adj. (of a sequence) having only one element. 
     ``(list 'hello) returns a singleton list.''

which doesn't sound right. Is the idea that I set things up

(defclass paragraph () ())
(defclass list ()())

(defclass plain ()())

(defmethod state-machine ((state paragraph)
                          (line-type plain))
  "Continue paragraph"
  ...)
  
Then code like this

(let ((state (make-instance 'paragraph))
      (line-type (make-instance 'plain)))
  (state-machine state line-type))

That looks neater and more maintainable. Thankyou for the
suggestion.

Alan Crowe
Edinburgh
Scotland
  
From: james anderson
Subject: Re: Nested case statements
Date: 
Message-ID: <40071F05.A9C0A8AD@setf.de>
Alan Crowe wrote:
> 
> james anderson wrote:
> > if you use singletons rather than eql specializers, you
> > have more options when combining methods.
> 
> Aaargh, that suggestion exposes a gap in my knowledge. The
> hyperspec only says:
> 
>      singleton adj. (of a sequence) having only one element.
>      ``(list 'hello) returns a singleton list.''
> 

in this context, the intended meaning is closer to that which is common in the
programming patterns texts[0].

> which doesn't sound right. Is the idea that I set things up
> 
> (defclass paragraph () ())
> (defclass list ()())
> 
> (defclass plain ()())
> 
> (defmethod state-machine ((state paragraph)
>                           (line-type plain))
>   "Continue paragraph"
>   ...)

to wit:

(defvar paragraph (make-instance 'paragraph))
(defvar plain (make-instance 'plain))

> 
> Then code like this
> 
> (let ((state (make-instance 'paragraph))
>       (line-type (make-instance 'plain)))
>   (state-machine state line-type))
> 

which yields code like 

 (let ((state paragraph)
       (line-type plain))
   (state-machine state line-type))

which leaves more freedom for subsequent variation and augmentation than the
eql specialized implementation.

...

[0] http://www.google.de/search?hl=de&ie=ISO-8859-1&q=singleton+gof+java&meta=
From: Tim Bradshaw
Subject: Re: Nested case statements
Date: 
Message-ID: <fbc0f5d1.0401160438.162a29fa@posting.google.com>
james anderson <··············@setf.de> wrote in message news:<·················@setf.de>...
> 
> (defvar paragraph (make-instance 'paragraph))
> (defvar plain (make-instance 'plain))
> 

I think a better approach is something like (completely untested code)

(declaim (inline singleton))

(defun singleton (class-name &rest initargs)
  (declare (dynamic-extent initargs)) ;?
  (or (get class-name 'singleton)
      (setf (get class-name 'singleton)
            (apply #'make-instance class-name initargs))))

then you can just say:

(defclass foo (...) ...)

... (singleton 'foo ...) ...

which will create an instance on demand but only once.
From: Marco Antoniotti
Subject: Singleton (Re: Nested case statements)
Date: 
Message-ID: <pRWNb.419$Nq.107866@typhoon.nyu.edu>
Tim Bradshaw wrote:
> james anderson <··············@setf.de> wrote in message news:<·················@setf.de>...
> 
>>(defvar paragraph (make-instance 'paragraph))
>>(defvar plain (make-instance 'plain))
>>
> 
> 
> I think a better approach is something like (completely untested code)
> 
> (declaim (inline singleton))
> 
> (defun singleton (class-name &rest initargs)
>   (declare (dynamic-extent initargs)) ;?
>   (or (get class-name 'singleton)
>       (setf (get class-name 'singleton)
>             (apply #'make-instance class-name initargs))))
> 
> then you can just say:
> 
> (defclass foo (...) ...)
> 
> ... (singleton 'foo ...) ...
> 
> which will create an instance on demand but only once.

Beautiful.  No MOP. Similar to CONSTANTLY.

Cheers
--
marco
From: Kaz Kylheku
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <cf333042.0401161617.e06524b@posting.google.com>
Marco Antoniotti <·······@cs.nyu.edu> wrote in message news:<···················@typhoon.nyu.edu>...
> Tim Bradshaw wrote:
> > james anderson <··············@setf.de> wrote in message news:<·················@setf.de>...
> > 
> >>(defvar paragraph (make-instance 'paragraph))
> >>(defvar plain (make-instance 'plain))
> >>
> > 
> > 
> > I think a better approach is something like (completely untested code)
> > 
> > (declaim (inline singleton))
> > 
> > (defun singleton (class-name &rest initargs)
> >   (declare (dynamic-extent initargs)) ;?
> >   (or (get class-name 'singleton)
> >       (setf (get class-name 'singleton)
> >             (apply #'make-instance class-name initargs))))
> > 
> > then you can just say:
> > 
> > (defclass foo (...) ...)
> > 
> > ... (singleton 'foo ...) ...
> > 
> > which will create an instance on demand but only once.
> 
> Beautiful.  No MOP. Similar to CONSTANTLY.

I can't help but observe that global module initializations, which
include the once-only creation of singletons is what LOAD-TIME-VALUE
is for. Actually, no, that special case is really what DEFVAR an
DEFPARAMETER are for. These are adequate tools for making global
variables.

The one apparent advantage of the above SINGLETON is that it is lazy.
The initargs can come from the values of lexical variables established
at the latest possible time. At least on the first invocation, that
is! On the second and subsequent invocations, the initargs are
ignored. Rather than an advantage, this could be a source of obscure
programming errors. You write (singleton 'foo :property-bar 42) and
instead get something with a PROPERTY-BAR value of 3, because your
expression was not the first one to call SINGLETON on the FOO class.

The ideas behind the so-called Singleton Design Pattern are basically
a braindamaged mish-mash of workarounds for C++-specific concerns. C++
programmers write a class with private or protected constructors to
prevent users of a class from making instances, and then provide a
static Instance() function that returns a single instance. Why don't
they just declare a global pointer at file scope?

   CMyClass *g = new CMyClass;

because now the constructor has to be public, so anyone can make
instances of the class, which for some psychological reason is to be
forbidden. Perhaps more importantly, C++ won't help you in
establishing an order among such global initializations, other than
that if they appear in the same translation unit, they are done top to
botttom. If you have two such initializations in separately compiled
units, which one is done first is at the mercy of the implementation.
It's probably whichever one happens to be fed to the linker first. If
you wrap the initialization behind a function, you can work around
this problem: your Instance() function can call the Instance()
functions of all other singletons that your singleton depends on,
thereby establishing an initialization graph (one that is hopefully
acyclic!)

  CMouth *CMouth::Instance()
  {
    // Ensure non-null brain pointer available for use by mouth!
    (void) CBrain::Instance();
    
     if (!mouthInstance) 
       mouthInstance = new CMouth();

    return mouthInstance;
  }

We don't have the dependency problem in Lisp, since module load order
is under programmer control. One module's DEFVAR can refer to another
DEFVAR in another module. If they are loaded in the wrong order, you
get an unbound variable condition. (Other languages still sort out the
module initialization order for you from declared module dependencies,
at the price of gross inflexibility).

About that other concern, if you really must prevent users from making
instances via MAKE-INSTANCE, analogous to a private or protected
constructor in C++, there are ways to hack that. Not exporting the
class symbol from your package is one possibility. This makes it
slightly harder not only to instantiate, but to specialize new
methods.
From: Steven E. Harris
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <q67fzebr513.fsf@L75001820.us.ray.com>
···@ashi.footprints.net (Kaz Kylheku) writes:

>   CMouth *CMouth::Instance()
>   {
>     // Ensure non-null brain pointer available for use by mouth!
>     (void) CBrain::Instance();
>     
>      if (!mouthInstance) 
>        mouthInstance = new CMouth();
>
>     return mouthInstance;
>   }

That one leaks and makes the caller wonder if the singleton may not
really be there. I prefer

CMouth& CMouth::Instance()
{
   static CMouth instance;  // CMouth ctor calls CBrain::Instance()
                            // if necessary.
   return instance;
}

But really I prefer to avoid singletons altogether and make these
dependencies on other objects explicit.

-- 
Steven E. Harris        :: ········@raytheon.com
Raytheon                :: http://www.raytheon.com
From: james anderson
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <40083FA4.59B2E724@setf.de>
Marco Antoniotti wrote:
> 
> Tim Bradshaw wrote:
> > james anderson <··············@setf.de> wrote in message news:<·················@setf.de>...
> >
> >>(defvar paragraph (make-instance 'paragraph))
> >>(defvar plain (make-instance 'plain))
> >>
> >
> >
> > I think a better approach is something like (completely untested code)
> >
> > (declaim (inline singleton))
> >
> > (defun singleton (class-name &rest initargs)
> >   (declare (dynamic-extent initargs)) ;?
> >   (or (get class-name 'singleton)
> >       (setf (get class-name 'singleton)
> >             (apply #'make-instance class-name initargs))))
> >
> > then you can just say:
> >
> > (defclass foo (...) ...)
> >
> > ... (singleton 'foo ...) ...
> >
> > which will create an instance on demand but only once.
> 
> Beautiful.  No MOP. Similar to CONSTANTLY.

again, to what advantage?
From: Marco Antoniotti
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <PHBOb.435$Nq.109175@typhoon.nyu.edu>
james anderson wrote:

> 
> Marco Antoniotti wrote:
> 
>>Tim Bradshaw wrote:
>>
>>>james anderson <··············@setf.de> wrote in message news:<·················@setf.de>...
>>>
>>>
>>>>(defvar paragraph (make-instance 'paragraph))
>>>>(defvar plain (make-instance 'plain))
>>>>
>>>
>>>
>>>I think a better approach is something like (completely untested code)
>>>
>>>(declaim (inline singleton))
>>>
>>>(defun singleton (class-name &rest initargs)
>>>  (declare (dynamic-extent initargs)) ;?
>>>  (or (get class-name 'singleton)
>>>      (setf (get class-name 'singleton)
>>>            (apply #'make-instance class-name initargs))))
>>>
>>>then you can just say:
>>>
>>>(defclass foo (...) ...)
>>>
>>>... (singleton 'foo ...) ...
>>>
>>>which will create an instance on demand but only once.
>>
>>Beautiful.  No MOP. Similar to CONSTANTLY.
> 
> 
> again, to what advantage?

Well, IMHO it is better to do

	(let ((x (singleton 'foo))) ...)

than

	(let ((x *the-foo*)) ...)

Retorting, I could ask what are the disadvantages of the (SINGLETON ...) 
idiom. (Not that this is all that important: I guess I would use both 
idioms here and there in my code)

I am not sure, but all of this reminds me the "problems" with 
DEFCONSTANT (which is whi you write *THE-FOO* and not +THE-FOO+ :) )
I.e. if I remeber correctly it is not really kosher to write

	(defconstant +the-foo+ (make-instance 'foo))


Cheers
--
Marco
From: Pascal Costanza
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <bu9gr9$bdh$1@newsreader2.netcologne.de>
Marco Antoniotti wrote:
> 
> Tim Bradshaw wrote:
> 
>> james anderson <··············@setf.de> wrote in message 
>> news:<·················@setf.de>...
>>
>>> (defvar paragraph (make-instance 'paragraph))
>>> (defvar plain (make-instance 'plain))
>>
>> I think a better approach is something like (completely untested code)
>>
>> (declaim (inline singleton))
>>
>> (defun singleton (class-name &rest initargs)
>>   (declare (dynamic-extent initargs)) ;?
>>   (or (get class-name 'singleton)
>>       (setf (get class-name 'singleton)
>>             (apply #'make-instance class-name initargs))))
>>
>> then you can just say:
>>
>> (defclass foo (...) ...)
>>
>> ... (singleton 'foo ...) ...
>>
>> which will create an instance on demand but only once.
> 
> Beautiful.

No, not really. In a multi-threaded system, two (or more) threads might 
call SINGLETON for the same class at more or less the same time, which 
can result in the creation of two instances when the calls of GET and 
SETF of the involved threads interfere in unfortunate ways.

This is a source for a potential bug you don't want to have. (One might 
object that this is very unlikely to occur, but that's exactly the 
reason why you don't want that: It would be a bug that would be 
extremely hard to reproduce.)

As a remedy, you would need to synchronize calls to SINGLETON which 
would make the program less portable and needlessly less efficient.

I agree with James, a DEFVAR is the best "implementation" of the 
Singleton pattern in Common Lisp. ;)


Pascal

P.S.: The most criticized aspect of the Singleton pattern in the "pure 
OO" communities is that most of the time, it is misused as a way to 
introduce global variables. Thank god I have switched to a more liberal 
language. ;)

P.P.S.: You can find more information about why they had to fix the Java 
memory model because of this issue at 
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

P.P.P.S.: I recall hearing Erich Gamma say that he wouldn't include the 
Singleton pattern in the pattern book anymore because it is too 
complicated. I guess this is because of these problems.

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Tim Bradshaw
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <ey3ptdjil8w.fsf@lostwithiel.cley.com>
* Pascal Costanza wrote:

> This is a source for a potential bug you don't want to have. (One
> might object that this is very unlikely to occur, but that's exactly
> the reason why you don't want that: It would be a bug that would be
> extremely hard to reproduce.)

> As a remedy, you would need to synchronize calls to SINGLETON which
> would make the program less portable and needlessly less efficient.

Yes.  Lots of changes need to be made to programs to work in
multithreaded systems, of course.

> I agree with James, a DEFVAR is the best "implementation" of the
> Singleton pattern in Common Lisp. ;)

Lots of completely spurious global variables cluttering up the place,
lovely!

If you really can't hack synchronising SINGLETON, then do this:

(defmacro define-singleton-class (cn supers &body forms)
  `(progn
     (defclass ,cn ,supers ,@forms)
     (setf (get ',cn 'singleton) (make-instance ',cn))
     (find-class ',cn)))

(defun singleton (cn) (get ',cn 'singleton))

--tim
From: james anderson
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <40086DB1.BE2D6B30@setf.de>
Tim Bradshaw wrote:
> 
> * Pascal Costanza wrote:
> 
> > This is a source for a potential bug you don't want to have. (One
> > might object that this is very unlikely to occur, but that's exactly
> > the reason why you don't want that: It would be a bug that would be
> > extremely hard to reproduce.)
> 
> > As a remedy, you would need to synchronize calls to SINGLETON which
> > would make the program less portable and needlessly less efficient.
> 
> Yes.  Lots of changes need to be made to programs to work in
> multithreaded systems, of course.
> 
> > I agree with James, a DEFVAR is the best "implementation" of the
> > Singleton pattern in Common Lisp. ;)
> 
> Lots of completely spurious global variables cluttering up the place,
> lovely!

why would one think that the global bindings are necessarily spurious?
if the fear is that they might claim eminently desirable variable names, would
it not suffice to put them in their own package?
From: Tim Bradshaw
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <ey38yk6vjk5.fsf@lostwithiel.cley.com>
* james anderson wrote:

> why would one think that the global bindings are necessarily spurious?
> if the fear is that they might claim eminently desirable variable names, would
> it not suffice to put them in their own package?

Well. 

Why do you need two names when you could have one?  You have a class
name already, now you have a variable name *as well*.  So, OK you
could fix that by using the unadorned class name as the variable name.
It would look a bit weird because it wouldn't be obvious to casual
inspection it was a global variable, unless you named your classes
strangely.

Now you've defined variables, not constants: does it make sense to
bind these things?  Probably not.  Is this clear in the code? No.  Is
it even clear you're using singletons in the code? No.  You should at
least use constants to avoid the binding issues.  Except now exciting
things may happen at compile-time: can instances of the class even be
made then?  Do they need to be?  Who knows?

And your variable definitions are separate from your class
definitions.  Make sure you change everything in two places (or, hmm,
write a macro to do both).

Packages are a non-solution: you either need to use explicit package
prefixes everywhere, or you use the package.  But the issue isn't
really namespace clutter.

So instead of doing all this you could do a couple of things:

Use a special defining form which secretes the singleton somewhere,
and then use a SINGLETON form to get at it.  No issues of mismatch,
extra spurious names, and anyone reading the code can instantly see
that this is a singleton class, because it says so, right where it's
used.  This method has the problem that you have to be careful about
definition order - forward referenced classes won't work, because the
macro will try to make the instance too early.

Use a standard defining form (or a special one if it makes the code
clearer, which it probably does), and a SINGLETON form which creates
the instance on demand.  This has no issues with definition order,
which is good, makes the code clear to the reader, which is good, but
SINGLETON needs to be synchronised for multithreaded programs.  It
also has first-time-performance issues, which probably aren't a
problem, but need to be watched for (it is very bad for programs to be
slow the first time they run: no one ever runs them a second time).


A couple of final notes.  Passing initargs to SINGELTON is bogus, as
others have pointed out.  LOAD-TIME-VALUE is a non-solution for a
couple of reasons: SINGLETON can't be evaluated at load time in cases
like:

  (defun foo (state)
    (grind (singleton state)))

Secondly, anything which does things at load time has definition-order
problems: you may not be able to make instances of classes until the
whole program is loaded.

--tim
From: james anderson
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <40096EAA.9D70D92@setf.de>
Tim Bradshaw wrote:
> 
> * james anderson wrote:
> 
> > why would one think that the global bindings are necessarily spurious?
> > if the fear is that they might claim eminently desirable variable names, would
> > it not suffice to put them in their own package?
> 
> Well.
> 
> Why do you need two names when you could have one?

we agree.

>    You have a class
> name already, now you have a variable name *as well*.

yes, but they may well be the same symbol.

>    So, OK you
> could fix that by using the unadorned class name as the variable name.

yes, we agree.

> It would look a bit weird because it wouldn't be obvious to casual
> inspection it was a global variable, unless you named your classes
> strangely.

i suspect that most have managed to get over any initial impression, that
terms such as most-negative-single-float, char-code-limit, or
internal-time-units-per-second posess any supernatural powers. i suspect also,
that few find the use of global variables to name functions either exotic or unfathomable.

whether one were successful with an idiom which named functions with a
combination (static-name x class*) and expressed function calls as a list with
a static name in the operator position and variables bound to appropriately
typed instances in (some of) the successive positions is more likely an issue
of clarity in formulation and documentation and of fit to the problem domain
than it is one of adherence to convention.


> 
> Now you've defined variables, not constants: does it make sense to
> bind these things?  Probably not.  Is this clear in the code? No.  Is
> it even clear you're using singletons in the code? No.  You should at
> least use constants to avoid the binding issues.  Except now exciting
> things may happen at compile-time: can instances of the class even be
> made then?  Do they need to be?  Who knows?
> 

in the original post, a.crowe alluded to a problem domain which encompasses
numerous narrower problems. it is not clear exactly which of these narrower
problems concerned him. given which, statements about probable suitability
warrant further explanation.

if it should turn out that the implementation needs neither variation nor
extension, then static case statements would be appropriate. if the
implementation needs extension, then a method-based implementation might be
more suitable. if, in addition, it were to turn out that it was useful to
express variation succinctly, then it might be approriate to encode the state
components in higher level functions, whereby their appearance as constant
values only would be an unwarranted constraint. in this regard formulations
such as

  (...
            (foo (singleton 'sky))
            ...)

sacrifice the ability to abstract the implementation, and one would be more
likely to express abstract implementations as

(...
            (foo (singleton sky))
            ...)

given which, the distinction between (singleton sky) and state.sky or
singleton:sky remains a mystery.

> And your variable definitions are separate from your class
> definitions.  Make sure you change everything in two places (or, hmm,
> write a macro to do both).
> 
> Packages are a non-solution: you either need to use explicit package
> prefixes everywhere, or you use the package.  But the issue isn't
> really namespace clutter.

we agree.

...
From: Tim Bradshaw
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <ey3ad4kgjje.fsf@lostwithiel.cley.com>
* james anderson wrote:

> i suspect that most have managed to get over any initial impression,
> that terms such as most-negative-single-float, char-code-limit, or
> internal-time-units-per-second posess any supernatural powers. i
> suspect also, that few find the use of global variables to name
> functions either exotic or unfathomable.

I'd certainly be happier if the language had chosen some more clearly
constant names for MOST-NEGATIVE-SINGLE-FLOAT &co (say
+MOST-NEGATIVE-SINGLE-FLOAT+).

I can't think of any cases in CL where unadorned global variables are
bound to functions. If you mean that symbols without any special
indicators name global functions, well I think you may be thinking of
Scheme, because in CL (or other Lisp-n for n > 1), functions *do* have
special indicators of course: either they are the car of a form or
they are wrapped in FUNCTION.  In fact all I'm doing is creating yet
another namespace for singletons.

Never mind, I can't pretend I care enough about this any more.

--tim
From: james anderson
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <400C7F7C.663B66F3@setf.de>
Tim Bradshaw wrote:
> ...
> 
> I'd certainly be happier if the language had chosen some more clearly
> constant names for MOST-NEGATIVE-SINGLE-FLOAT &co (say
> +MOST-NEGATIVE-SINGLE-FLOAT+).
> 
> I can't think of any cases in CL where unadorned global variables are
> bound to functions. If you mean that symbols without any special
> indicators name global functions, well I think you may be thinking of
> Scheme, because in CL (or other Lisp-n for n > 1), functions *do* have
> special indicators of course: either they are the car of a form or
> they are wrapped in FUNCTION.  In fact all I'm doing is creating yet
> another namespace for singletons.

no, i was thinking more of this: http://oopweb.com/LISP/Documents/cltl/Volume/clm/node77.html

> 
> Never mind, I can't pretend I care enough about this any more.
>

...
From: Tim Bradshaw
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <ey33cab3qu0.fsf@cley.com>
* james anderson wrote:

> no, i was thinking more of this: http://oopweb.com/LISP/Documents/cltl/Volume/clm/node77.html

The spec (glossary): 

    variable n. a binding in the ``variable'' namespace. See Section
    3.1.2.1.1 (Symbols as Forms).

What CLtL said isn't really relevant.

--tim
From: james anderson
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <400D6867.322D6BA7@setf.de>
Tim Bradshaw wrote:
> 
> * james anderson wrote:
> 
> > no, i was thinking more of this: http://oopweb.com/LISP/Documents/cltl/Volume/clm/node77.html
> 
> The spec (glossary):
> 
>     variable n. a binding in the ``variable'' namespace. See Section
>     3.1.2.1.1 (Symbols as Forms).
> 
> What CLtL said isn't really relevant.

oh.

> 
> --tim
From: Pascal Costanza
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <bua1uc$91r$1@newsreader2.netcologne.de>
Tim Bradshaw wrote:

> * Pascal Costanza wrote:
>
>>I agree with James, a DEFVAR is the best "implementation" of the
>>Singleton pattern in Common Lisp. ;)
> 
> Lots of completely spurious global variables cluttering up the place,
> lovely!
> 
> If you really can't hack synchronising SINGLETON, then do this:
> 
> (defmacro define-singleton-class (cn supers &body forms)
>   `(progn
>      (defclass ,cn ,supers ,@forms)
>      (setf (get ',cn 'singleton) (make-instance ',cn))
>      (find-class ',cn)))
> 
> (defun singleton (cn) (get ',cn 'singleton))

I think this issue becomes clearer when giving examples. When I hear 
"Singleton" I think of the examples given in the GoF book. Here are some:

(defclass filesystem ...)

(defvar *the-filesystem* (make-instance 'filesystem ...))

(defclass mouse ...)

(defvar *the-mouse* (make-instance ...))


I think in these examples, "cluttering the place" with global variables 
doesn't hurt.

The examples that have started this discussion are close:

(defclass paragraph ...)
(defclass plain ...)

(defvar paragraph ...)
(defvar plain ...)

(...as suggested by James without asterisks - this should probably be 
changed, shouldn't it?)

Under the assumption that these things end up in the right packages I 
don't see a real issue here. After all, the terms "filesystem", "mouse", 
"paragraph", "plain", and so on, are already attached to concrete 
concepts within the ontologies of the respective programs, so it's 
probably not a good idea to reuse the names for other concepts in the 
same programs.

Or do you have a different problem in mind?


Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Rob Warnock
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <A-ydndWL_8zhWJXdRVn-ug@speakeasy.net>
Pascal Costanza  <········@web.de> wrote:
+---------------
| I think this issue becomes clearer when giving examples. When I hear 
| "Singleton" I think of the examples given in the GoF book. Here are some:
| 
| (defclass filesystem ...)
| 
| (defvar *the-filesystem* (make-instance 'filesystem ...))
| 
| (defclass mouse ...)
| 
| (defvar *the-mouse* (make-instance ...))
+---------------

But both of those are *BAD* examples of singletons!!  E.g., I have both
multiple filesystems (UFS, FAT, ISO9660) and multiple mice (PS/2, USB)
on my laptop...


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Karl A. Krueger
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <bua3s2$c7u$1@baldur.whoi.edu>
Pascal Costanza <········@web.de> wrote:
> Tim Bradshaw wrote:
>> Lots of completely spurious global variables cluttering up the place,
>> lovely!
	[snippage]
> I think this issue becomes clearer when giving examples. When I hear 
> "Singleton" I think of the examples given in the GoF book. Here are some:
	[snippage]
> (defclass mouse ...)
> (defvar *the-mouse* (make-instance ...))

I think it's perfectly reasonable to have multiple meeces and mice
pointers.  If I plug two USB mouses into my Macintosh, it would be
perfectly sane behavior for the operating system to throw two meece
pointers on the screen.

It doesn't do so, of course, but I regard that as a failure of
creativity rather than an impossibility.  :)

-- 
Karl A. Krueger <········@example.edu>
Woods Hole Oceanographic Institution
Email address is spamtrapped.  s/example/whoi/
"Outlook not so good." -- Magic 8-Ball Software Reviews
From: Rob Warnock
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <Z72dnW3soo5BW5XdRVn-uA@speakeasy.net>
Karl A. Krueger <········@example.edu> wrote:
+---------------
| Pascal Costanza <········@web.de> wrote:
| > (defclass mouse ...)
| > (defvar *the-mouse* (make-instance ...))
| 
| I think it's perfectly reasonable to have multiple meeces and mice
| pointers.  If I plug two USB mouses into my Macintosh, it would be
| perfectly sane behavior for the operating system to throw two meece
| pointers on the screen.
| 
| It doesn't do so, of course, but I regard that as a failure of
| creativity rather than an impossibility.  :)
+---------------

When I have both the "PS/2" mouse (touchpad, actually) and a USB
mouse active on my laptop [running XFree86 with "moused"], what
happens is that the single mouse pointer is moved by *either*
mouse moving. This happens to be what *I* want[1], though certainly
your taste may vary.  ;-}


-Rob

[1] In particular, so I can use the touchpad when I'm doing fast
    editing (less motion) yet when doing massive pure text input
    turn it off (to avoid dragging my palms on it accidentally)
    and use the UCB mouse more in that case. Also, doing lots of
    middle-clicking is easier on the 3-button USB wheel mouse than
    on the touchpad (which has only 3-button emulation by clicking
    both left & right at once).

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Costanza
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <buat73$ole$1@newsreader2.netcologne.de>
Karl A. Krueger wrote:

> Pascal Costanza <········@web.de> wrote:
> 
>>Tim Bradshaw wrote:
>>
>>>Lots of completely spurious global variables cluttering up the place,
>>>lovely!
> 
> 	[snippage]
> 
>>I think this issue becomes clearer when giving examples. When I hear 
>>"Singleton" I think of the examples given in the GoF book. Here are some:
> 
> 	[snippage]
> 
>>(defclass mouse ...)
>>(defvar *the-mouse* (make-instance ...))
> 
> 
> I think it's perfectly reasonable to have multiple meeces and mice
> pointers.  If I plug two USB mouses into my Macintosh, it would be
> perfectly sane behavior for the operating system to throw two meece
> pointers on the screen.

Sure, this is one of the reasons why the Singleton pattern isn't a 
particularly good idea in many cases. But that's besides the point of 
the current discussion.


Thanks anyway for pointing this out.

Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: Rahul Jain
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <87u12swo0v.fsf@nyct.net>
"Karl A. Krueger" <········@example.edu> writes:

> I think it's perfectly reasonable to have multiple meeces and mice
> pointers.  If I plug two USB mouses into my Macintosh, it would be
> perfectly sane behavior for the operating system to throw two meece
> pointers on the screen.

Back when I had my Mac IIcx, I used to have two mice and one trackball
connected to it. Oh, and of course, there was MouseKeys, too. This
combination made "hotseat" type games very easy to play and made it easy
to have hours of tangential fun attempting to mess with the player
currently taking his turn. Of course, he who had the keyboard won.

-- 
Rahul Jain
·····@nyct.net
Professional Software Developer, Amateur Quantum Mechanicist
From: james anderson
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <4009058E.2A2D3362@setf.de>
Pascal Costanza wrote:
> 
> Tim Bradshaw wrote:
> 
> > * Pascal Costanza wrote:
> >
> >>I agree with James, a DEFVAR is the best "implementation" of the
> >>Singleton pattern in Common Lisp. ;)
> >
> > Lots of completely spurious global variables cluttering up the place,
> > lovely!
> >
> ...
> 
> The examples that have started this discussion are close:
> 
> (defclass paragraph ...)
> (defclass plain ...)
> 
> (defvar paragraph ...)
> (defvar plain ...)
> 
> (...as suggested by James without asterisks - this should probably be
> changed, shouldn't it?)
> 

perhaps not. in this situation, they act (in combination) as extensible (in
that their values can be specialized) function bindings. this more than any
role as a variable. the ability to rebind them dynamically notwithstanding.
furthermore, since, as you noted in your message, their role in the respective
ontology is clear, and since it is likely that they would appear unstarred in
document models, it is not clear that the "*" convention should apply.

...
From: Tim Bradshaw
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <ey34quuvjg1.fsf@lostwithiel.cley.com>
* Pascal Costanza wrote:

> Under the assumption that these things end up in the right packages I
> don't see a real issue here. After all, the terms "filesystem",
> "mouse", "paragraph", "plain", and so on, are already attached to
> concrete concepts within the ontologies of the respective programs, so
> it's probably not a good idea to reuse the names for other concepts in
> the same programs.

The problem is that if I see something like

(...
            (foo *sky*)
            ...)

How on earth am I meant to know that *sky* is a singleton instance of
something?

If I see

(...
            (foo (singleton 'sky))
            ...)

it is all very clear.

--tim
From: Joe Marshall
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <smie8p9c.fsf@comcast.net>
Tim Bradshaw <···@cley.com> writes:

> The problem is that if I see something like
>
> (...
>             (foo *sky*)
>             ...)
>
> How on earth am I meant to know that *sky* is a singleton instance of
> something?

How about if you saw:

> (...
>             (foo *the-sky*)
>             ...)


-- 
~jrm
From: Marco Antoniotti
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <xBBOb.434$Nq.108138@typhoon.nyu.edu>
Pascal Costanza wrote:
> Marco Antoniotti wrote:
> 
>>
>> Tim Bradshaw wrote:
>>
>>> james anderson <··············@setf.de> wrote in message 
>>> news:<·················@setf.de>...
>>>
>>>> (defvar paragraph (make-instance 'paragraph))
>>>> (defvar plain (make-instance 'plain))
>>>
>>>
>>> I think a better approach is something like (completely untested code)
>>>
>>> (declaim (inline singleton))
>>>
>>> (defun singleton (class-name &rest initargs)
>>>   (declare (dynamic-extent initargs)) ;?
>>>   (or (get class-name 'singleton)
>>>       (setf (get class-name 'singleton)
>>>             (apply #'make-instance class-name initargs))))
>>>
>>> then you can just say:
>>>
>>> (defclass foo (...) ...)
>>>
>>> ... (singleton 'foo ...) ...
>>>
>>> which will create an instance on demand but only once.
>>
>>
>> Beautiful.
> 
> 
> No, not really. In a multi-threaded system, two (or more) threads might 
> call SINGLETON for the same class at more or less the same time, which 
> can result in the creation of two instances when the calls of GET and 
> SETF of the involved threads interfere in unfortunate ways.

(defun singleton (class-name &rest initargs)
   (xxx:synchronized ; for an appropriate definition of "SYNCHRONIZE"
       (or (get class-name 'singleton)
           (setf (get class-name 'singleton)
                 (apply #'make-instance class-name initargs))))

> This is a source for a potential bug you don't want to have. (One might 
> object that this is very unlikely to occur, but that's exactly the 
> reason why you don't want that: It would be a bug that would be 
> extremely hard to reproduce.)
> 
> As a remedy, you would need to synchronize calls to SINGLETON which 
> would make the program less portable and needlessly less efficient.

In a multithreaded implementation DEFVAR itself is complicated.  You are 
just assuming more functionality in the underlying implementation.

> I agree with James, a DEFVAR is the best "implementation" of the 
> Singleton pattern in Common Lisp. ;)

Not really.  IMHO the "best" way would be to have the SINGLETON thingy 
done with the MOP.  Oh well...

Cheers
--
Marco
From: Pascal Costanza
Subject: Re: Singleton (Re: Nested case statements)
Date: 
Message-ID: <bueqio$1je$1@newsreader2.netcologne.de>
Marco Antoniotti wrote:

>> No, not really. In a multi-threaded system, two (or more) threads 
>> might call SINGLETON for the same class at more or less the same time, 
>> which can result in the creation of two instances when the calls of 
>> GET and SETF of the involved threads interfere in unfortunate ways.
> 
> (defun singleton (class-name &rest initargs)
>   (xxx:synchronized ; for an appropriate definition of "SYNCHRONIZE"
>       (or (get class-name 'singleton)
>           (setf (get class-name 'singleton)
>                 (apply #'make-instance class-name initargs))))

This probably works. But it's tempting to optimize this into the 
following code.

(defun singleton (class-name &rest initargs)
   (or (get class-name 'singleton)
       (xxx:synchronized ; for an appropriate definition of "SYNCHRONIZE"
          (or (get class-name 'singleton)
              (setf (get class-name 'singleton)
                    (apply #'make-instance class-name initargs)))))

...and chances are that this is not correct. At least, Java has a 
detailed specification for a memory model that doesn't do this right, 
and this doesn't seem to me one of the typical "Java sucks" examples. 
It's just hard to get right.

>> This is a source for a potential bug you don't want to have. (One 
>> might object that this is very unlikely to occur, but that's exactly 
>> the reason why you don't want that: It would be a bug that would be 
>> extremely hard to reproduce.)
>>
>> As a remedy, you would need to synchronize calls to SINGLETON which 
>> would make the program less portable and needlessly less efficient.
> 
> In a multithreaded implementation DEFVAR itself is complicated.  You are 
> just assuming more functionality in the underlying implementation.

Exactly. I am trying to reuse the engineering efforts other people have 
put into such issues. DEFVAR must be implemented correctly in a 
multi-threaded scenario. Why risk going beyond that?


However, I think the trade-offs are clear enough by now.



Pascal

-- 
Tyler: "How's that working out for you?"
Jack: "Great."
Tyler: "Keep it up, then."
From: james anderson
Subject: Re: Nested case statements
Date: 
Message-ID: <400814F5.43884716@setf.de>
Tim Bradshaw wrote:
> 
> james anderson <··············@setf.de> wrote in message news:<·················@setf.de>...
> >
> > (defvar paragraph (make-instance 'paragraph))
> > (defvar plain (make-instance 'plain))
> >
> 
> I think a better approach is something like (completely untested code)
> 
> (declaim (inline singleton))
> 
> (defun singleton (class-name &rest initargs)
>   (declare (dynamic-extent initargs)) ;?
>   (or (get class-name 'singleton)
>       (setf (get class-name 'singleton)
>             (apply #'make-instance class-name initargs))))
> 
> then you can just say:
> 
> (defclass foo (...) ...)
> 
> ... (singleton 'foo ...) ...
> 
> which will create an instance on demand but only once.

is it to be preferred for any reason other than this?