From: ········@hotmail.com
Subject: Implementing State(305) pattern
Date: 
Message-ID: <848jl5$m64$1@nnrp1.deja.com>
Hi, I'm looking at implementing the State pattern found in /Design
Patterns/ pp 305-313.  I can implement it fine in C++ (because the
examples are in C++), but is there a (much) simpler implementation
using Common Lisp?

Here's the problem:  I've got three boolean options, one, and only one,
must be set/selected (e.g. print to debug, error, info).  Chosing none
or more than one print option signals an exception.  When the user
calls print on the state object, the operation resolves to the
appropriate print message on the logger.

class LOGGER has three fns:
(print-to-debug msg)
(print-to-error msg)
(print-to-info mesg)

How do I use State to call the appropriate fn on LOGGER given the above
constraints?

-----

I've read Peter Norvig's paper _Design Patterns In Dynamic
Programming_.  He said the State pattern is easier because of First
Class Objects, but he didn't go into any details.  Implementors:  how
have you implemented State?

Sincerely,
Douglas M. Auclair


Sent via Deja.com http://www.deja.com/
Before you buy.

From: Ian Wild
Subject: Re: Implementing State(305) pattern
Date: 
Message-ID: <38687C4A.5D12C314@eurocontrol.be>
········@hotmail.com wrote:
> 
> Hi, I'm looking at implementing the State pattern found in /Design
> Patterns/ pp 305-313.

That's 9 pages.

 
> Here's the problem:  I've got three boolean options, one, and only one,
> must be set/selected (e.g. print to debug, error, info).

No - you've got one option: "where to print"


Did it *really* take nine pages to implement a case statement?
You must have the "large print" edition or something.
From: Chris Double
Subject: Re: Implementing State(305) pattern
Date: 
Message-ID: <wkn1qvxsit.fsf@double.co.nz>
········@hotmail.com writes:

> How do I use State to call the appropriate fn on LOGGER given the
> above constraints?

I'm not sure I understand what you are trying to do, can you expand on
it a bit?

From what I can tell you have a LOGGER class that has three methods:

  PRINT-TO-DEBUG
  PRINT-TO-ERROR
  PRINT-TO-INFO

And you have an object that you want to call another method, PRINT, on
that ends up using LOGGER to log a message. The method of LOGGER to
call depends on some state that has been set. Is this right?

Chris.
From: ········@hotmail.com
Subject: Re: Implementing State(305) pattern
Date: 
Message-ID: <84e44a$gav$1@nnrp1.deja.com>
Quoth Chris:
>
> I'm not sure I understand what you are trying to do, can you expand on
> it a bit?
>
> From what I can tell you have a LOGGER class that has three methods:
>
>   PRINT-TO-DEBUG
>   PRINT-TO-ERROR
>   PRINT-TO-INFO

Well, actually, Erann (see my post (msg 5, I think)), rightfully
pointed out that in CLOS, classes don't have fns, fns specialize on
objects ... thinking in C++ when I say, "LOGGER has three fns".  But,
you're correct, there are three generic fns that specialize on LOGGER:
(print-to-debug ((log logger) msg))
(print-to-error ((log logger) msg))
(print-to-info  ((log logger) msg))

An implementation issue:  these print fns don't print to the
console/shell, they output msg (a string) to a database.

>
> And you have an object that you want to call another method, PRINT, on
> that ends up using LOGGER to log a message. The method of LOGGER to
> call depends on some state that has been set. Is this right?

Yes, that's correct.  I've got it implemented in C++ fine, but it's
switch ugly (one switch to set the appropriate boolean, and then,
later, another switch to fire the appropriate print command).  I
wondered if Common Lisp provides an elegant/flexible/beautiful way to
do this using the State pattern (specialization on singletons).

Sincerely,
Doug Auclair


Sent via Deja.com http://www.deja.com/
Before you buy.
From: Tim Bradshaw
Subject: Re: Implementing State(305) pattern
Date: 
Message-ID: <ey3aemvp9te.fsf@cley.com>
* dauclair  wrote:

> How do I use State to call the appropriate fn on LOGGER given the above
> constraints?

I think you just do it the same way you would in C++ -- have a slot in
the object which holds a state, and then do a dispatch based on that.
You might well want to use a multiply dispatching method:

	(defmethod print-thing ((thing logger) ...)
	  ;; this could probably be an inline function unless you want
	  ;; additional behaviour here
	  (do-print-thing thing (thing-state thing) ...))

	(defmethod do-print-thing ((thing logger) (state exploded) ...)
          ...)

You may want to either intern state objects somehow, or perhaps use
symbols and EQL methods:

	(defgeneric thing-state (thing))
	(defmethod thing-state (thing)
          'normal)

	(defmethod do-print-thing ((thing logger) (state (eql 'normal)) ...)
          ...)

The True CLOS way *might* be to use CHANGE-CLASS on LOGGER to change
the state, but I suspect that is prohibitively slow in most
implementations.

--tim
From: ········@hotmail.com
Subject: Re: Implementing State(305) pattern
Date: 
Message-ID: <84e4cp$ge8$1@nnrp1.deja.com>
In article <···············@cley.com>,
  Tim Bradshaw <···@cley.com> wrote:
> [snip description of state pattern and using eql for singletons using
symbols]
>
> The True CLOS way *might* be to use CHANGE-CLASS on LOGGER to change
> the state, but I suspect that is prohibitively slow in most
> implementations.
>
> --tim
>
Thank you, Tim:  never thought of CHANGE-CLASS (C++ doesn't have that
built in), and using symbols instead of creating singleton subclasses
of State is another neat idea.

Sincerely,
Doug Auclair


Sent via Deja.com http://www.deja.com/
Before you buy.
From: ········@hotmail.com
Subject: Re: Implementing State(305) pattern -- an interesting reply from Erann Gat
Date: 
Message-ID: <84e3f0$fr5$1@nnrp1.deja.com>
I guess this reply never made it to comp.lang.lisp (I received the
email), so here it is for general review.  Erann show how to return a
fn from a fn to tackle the issue:


>From: ···@jpl.nasa.gov (Erann Gat)
>To: ········@hotmail.com
>Subject: Re: Implementing State(305) pattern
>Date: Mon, 27 Dec 1999 16:40:42 -0800
>
>(A copy of this message has also been posted to the following
newsgroups:
>comp.lang.lisp)
>
>In article <············@nnrp1.deja.com>, ········@hotmail.com wrote:
>
> > Hi, I'm looking at implementing the State pattern found in /Design
> > Patterns/ pp 305-313.  I can implement it fine in C++ (because the
> > examples are in C++), but is there a (much) simpler implementation
> > using Common Lisp?
> >
> > Here's the problem:  I've got three boolean options, one, and only
one,
> > must be set/selected (e.g. print to debug, error, info).  Chosing
none
> > or more than one print option signals an exception.  When the user
> > calls print on the state object, the operation resolves to the
> > appropriate print message on the logger.
> >
> > class LOGGER has three fns:
> > (print-to-debug msg)
> > (print-to-error msg)
> > (print-to-info mesg)
> >
> > How do I use State to call the appropriate fn on LOGGER given the
above
> > constraints?
>
>The phrase "Class logger has three fns" doesn't really make sense, and
>indicates that you aren't really asking the question you mean to ask.
>Here's an answer based on a guess about what you really mean:
>
>; Define the class - the state is kept in a slot
>; The value of the state is the print function to use
>; This is only possible because functions are first-class
>; objects in Lisp
>;
>(DEFCLASS LOGGER () ((PRINT-FN :INITFORM 'PRINT-TO-DEBUG)))
>
>; Define the print method that uses that state
>;
>(DEFMETHOD LOGGER-PRINT ((L LOGGER) MSG)
>   (WITH-SLOTS (PRINT-FN) L (FUNCALL PRINT-FN MSG)))
>
>; An example.  Make a logger object
>;
>(setf logger1 (make-instance 'logger))
>
>; Set the print function
>;
>(setf (slot-value logger1 'print-fn) 'print-to-error)
>
>; For this to work we have to actually define print-to-error
>;
>(defun print-to-error (msg) (format t "PRINT-TO-ERROR: ~A" msg))
>
>; Call it
>;
>(logger-print logger1 "Foo!")
>
>
> > I've read Peter Norvig's paper _Design Patterns In Dynamic
> > Programming_.  He said the State pattern is easier because of First
> > Class Objects, but he didn't go into any details.  Implementors:
how
> > have you implemented State?
>
>You can sort of do the example above in C++ using function pointers.
>But here's an example of something you can't do in C++:
>
>; This function returns another function
>;
>(defun make-logger-print-function (message-prefix stream)
>   (lambda (msg) (format stream "~A: ~A" message-prefix msg)))
>
>; Set the print function of logger1 to be the result of
>; calling make-logger-print-function
>;
>(setf (slot-value logger1 'print-fn)
>       (make-logger-print-function "LOGGER DEBUG" *debug-io*))


Sent via Deja.com http://www.deja.com/
Before you buy.
From: ········@hotmail.com
Subject: Re: Implementing State(305) pattern -- an interesting reply from Erann Gat
Date: 
Message-ID: <84e4sk$gqd$1@nnrp1.deja.com>
> >From: ···@jpl.nasa.gov (Erann Gat)

> >The phrase "Class logger has three fns" doesn't really make sense,
and
> >indicates that you aren't really asking the question you mean to ask.

Right!  Switching to thinking in terms of covariant inheritance can be
a big leap.  Thank you for pointing out my narrowed thinking here.

> > [snip fn pointer implementation]
> >
> >You can sort of do the example above in C++ using function pointers.
> >But here's an example of something you can't do in C++:
> >
> >; This function returns another function
> >;
> >(defun make-logger-print-function (message-prefix stream)
> >   (lambda (msg) (format stream "~A: ~A" message-prefix msg)))
> >
> >; Set the print function of logger1 to be the result of
> >; calling make-logger-print-function
> >;
> >(setf (slot-value logger1 'print-fn)
> >       (make-logger-print-function "LOGGER DEBUG" *debug-io*))
>

WOW!  Returning fns from fns is something I must get comfortable with
(back to Paul Graham's /On Lisp/ ...).  Thank you for your Lispy
response to my C++ questions.

Sincerely,
Douglas M. Auclair


Sent via Deja.com http://www.deja.com/
Before you buy.