From: ·······@my-deja.com
Subject: Design Patterns and CL
Date: 
Message-ID: <8are4d$30q$1@nnrp1.deja.com>
Me again,
I've heard that the kind of design you find in the Design
Patterns book are C++isms, and that it's not a good idea to implement
them in CL. Is this true? =:O What do you people use? O:)
Thanx


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

From: Stig E. Sandø
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <87snxqtx8x.fsf@palomba.bananos.org>
·······@my-deja.com writes:

> Me again,
> I've heard that the kind of design you find in the Design
> Patterns book are C++isms, and that it's not a good idea to implement
> them in CL. Is this true? =:O What do you people use? O:)

I have also spent quite a lot of time with C++ and Java, and yes, the
DP book is very C++-centric.  This is quite ok imho, as you need those
patterns in C++ one way or the other.  My experience so far with CL
has shown me that I had to rethink a lot to understand CL and rethink
even more to write usable CL code.  Try to forget the DP book while
learning CL, and learn CL on it's own terms and not on another
language's term.


-- 
------------------------------------------------------------------
Stig Erik Sandoe     ····@ii.uib.no    http://www.ii.uib.no/~stig/
From: Barry Margolin
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <%hdA4.50$Hp4.995@burlma1-snr2>
In article <··············@palomba.bananos.org>,
Stig E. Sand� <····@ii.uib.no> wrote:
>·······@my-deja.com writes:
>
>> Me again,
>> I've heard that the kind of design you find in the Design
>> Patterns book are C++isms, and that it's not a good idea to implement
>> them in CL. Is this true? =:O What do you people use? O:)
>
>I have also spent quite a lot of time with C++ and Java, and yes, the
>DP book is very C++-centric.  This is quite ok imho, as you need those
>patterns in C++ one way or the other.  My experience so far with CL
>has shown me that I had to rethink a lot to understand CL and rethink
>even more to write usable CL code.  Try to forget the DP book while
>learning CL, and learn CL on it's own terms and not on another
>language's term.

I've heard it said that Design Patterns were developed as a way to deal
with how hard it is to write C/C++ code, but Lisp doesn't need this crutch.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: William Tanksley
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <slrn8d2vtg.i0o.wtanksle@dolphin.openprojects.net>
On Thu, 16 Mar 2000 22:32:28 GMT, Barry Margolin wrote:
>Stig E. Sand� <····@ii.uib.no> wrote:

>I've heard it said that Design Patterns were developed as a way to deal
>with how hard it is to write C/C++ code, but Lisp doesn't need this crutch.

That's not true -- they aren't coding patterns, they're design patterns ;-).

Lisp doesn't need many of the 'patterns' that C++ needs, because in Lisp
they're directly expressable in the language (or even already provided as
a language feature, as with multiple dispatch).  However, this only allows
us to set aside those primitive design patterns and use some more
sophisticated ones which a C++ coder could not even consider, because his
language would make them too complex.

The "original" Design Patterns book discussed this fact, although in terms
of C versus C++ (for example, "object orientation" is a design pattern
needed by C but not C++).

Now, I don't have my Design Patterns book nearby, so I can't make a list
of "patterns Lisp still needs" (not that this book is the only source of
design patterns; it's merely a convenient standard) -- but I'd love to
read anyone else's take on this issue.

>Barry Margolin, ······@bbnplanet.com

-- 
-William "Billy" Tanksley
From: David Hanley
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <38D25EFF.3A1DF33A@ncgr.org>
I'm somewhat familiar with design patterns in C++.
For starters, I think a lot of the things are fairly
obvious and what a good programmer would use to
do these things anyways.  Still, giving examples can
be good.  It can be bad if you showhorn these patterns
into your designs.

OTOH, in lisp, many of the pattern are so trivial as
to need no explanation.  Some of them are caused by
people's desire to make everything an object.

For example, a big deal is made of the singleton object.
People behave as if it is a clever, special idea.  Here's
a singleton in a nutshell:

(note: all code in this post is just typed in and not checked)

class foo
{
private:
  foo() // no one but me can call the constructor
  int a = 0 , b = 0;
  foo *f = new foo();
public:
  foo *getFoo() { return f; }
  int fooMethod1();
  int fooMethod2();
}

Now, if you really use this with inheretence, it might justify
the use of object orientation in this case.  Might have a few
singleton entities with the same interface floating around.  In
practice, I have *never* seen this occur.  Every instance of the
above pattern I have seen could be implemented as follows:

(let ((a 0)(b 0))
  (defun fooMethod1()(..))
  (defun fooMethod2()(..)))

Which has the advantages of being simpler and more direct
(to me).  The first case is made more complex by it's insistence
on object orientation.  The second case is clearly a group of
functions operating over some hidden variables.

Factories are even a better example.  A factory is started up,
and it produces some kind of data.  Let's say you want to
return the elements of an array until you reach the end.

class IntArrayFactory
{
private:
  int index = -1;
  int len;
  int *ar;
public:
  IntArrayFactory( int *ar , int len )
  {
    this.ar = ar;
    this.len = len;
  }

  int getNextElement()
  {
    if ( more() )
      return ar[ index++ ];
    return -1;
  }

  int more()
  {
    return ( index < ( len - 1 ) );
  }
}

Furthermore, without templates, you've got to duplicte it.
With templates, you have great potential for code bloat.

Here's the same sort of thing in lisp.

(defun make-array-iterator( arr )
  (let ((index -1)(al (1- (length arr)))
    #'(lambda()(if (< index al) (values nil nil)(values (aref arr (incf
index)) T))))

It's so easy, do you really need a "pattern?"  Furthermore, the code is
so
flexible and reusable that it almost serves as the pattern itself.  I do
agree with a previous poster that the patterns will be much higher level
in
lisp because these C++ patterns are so trivial we are not stuck fiddling
with them.

dave
From: Jochen Schneider
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <u4sa5apkt.fsf@yod.cs.uni-magdeburg.de>
Hi,

Peter Norvig wrote an article on Lisp and Design Patterns:
	http://www.norvig.com/design-patterns/

(I'm not really sure that method combination is the right way to
implement the observer pattern, though.)

Regards,

	Jochen
-- 
C++ : an octopus made by nailing extra legs onto a dog
From: Barry Margolin
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <J7tA4.71$Hp4.1863@burlma1-snr2>
In article <·············@yod.cs.uni-magdeburg.de>,
Jochen Schneider  <·····@isg.cs.uni-magdeburg.de> wrote:
>Hi,
>
>Peter Norvig wrote an article on Lisp and Design Patterns:
>	http://www.norvig.com/design-patterns/
>
>(I'm not really sure that method combination is the right way to
>implement the observer pattern, though.)

But he basically supports what I wrote.  He refers to the patterns that are
built into the language and that you often don't think about formally as
"invisible", and claims that 16 of the 23 patterns are invisible or very
simple in Lisp (presumably meaning Common Lisp) and Dylan.  Even if you
agree with Jochen that Observer isn't really built in, 15 out of 23 isn't
bad.  If most people used languages that made just the remaining 8 patterns
complex, I doubt that there would be a formal term for this notion or any
books on the subject.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Will Deakin
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <8at2pi$8ja$1@nnrp1.deja.com>
·······@my-deja.com wrote:
> I've heard that the kind of design you find in the Design
> Patterns book are C++isms, and that it's not a good idea to implement
> them in CL. Is this true?
This question has been hotly debated on this newsgroup in recent and
not so recent times. To find out about this I would suggest you try
searching c.l.l. archives. (deja.com is a good place to start).

>What do you people use?
To add to the muddle there is an argument about `what is a pattern.'
For arguments sake take a pattern to be `all of those things describe
in the GoF book, and nothing else'. Then my take on this (which is
probably wrong ;) is that there are two types of patterns: patterns
that are needed to fix problems in C++ which CL doesn't need as CL
isn't broken like this; And stuff which is an interesting way of
looking at the world and could be usefully applied to programs written
in CL.

Which pattern is which is clearly a moot point. And this (along with
whether CL could use patterns, what is a pattern, how can a man survive
such times and live, taxes on the farmer feed us all and other such
questions) causes hackles to rise and flame wars to ensue. Read the old
stuff and this will become more apparent,

Best Regards,

:) will


Sent via Deja.com http://www.deja.com/
Before you buy.
From: Gareth Rees
Subject: Re: Design Patterns and CL
Date: 
Message-ID: <usnxpzrw5.fsf@pobox.com>
·······@my-deja.com wrote:
> I've heard that the kind of design you find in the Design Patterns
> book are C++isms, and that it's not a good idea to implement them in
> CL.

Some of the patterns in the Design Patterns book [1] are good ways of
structuring an algorithm in any language.  But several are definitely
just ways to work around deficiencies in C and C++.

One of the worst examples is the Visitor pattern (p. 331).

The Visitor pattern describes what you do when you have collections
of objects that fall into a fixed set of classes but you want to be
able to define new operations on those collections.  You don't want
to have to add a method to each class for each new operation.

So you instead create a Visitor class which has a method for each
class in the collection.  And the individual objects know how to
call the appropriate method in any Visitor that's visiting them.

For example, you have a parse tree for integer expression, which has
two clases of Node: namely Operator and Value.  You want to have
several kinds of operation on the parse tree: evaluate, prettyprint,
code-generate, etc.  So you write something like

   class NodeVisitor {
     visit_operator(Operator *o);
     visit_value(Value *v);
   };

   class Operator : Node {
     Node *left, *right;
     visit (Visitor *v) {
       v->visit_operator(self);
     }
   };

   class Value : Node {
     int value;
     visit (Visitor *v) {
       v->visit_value(self);
     }
   };

and now you can define new operations on Nodes without having to
redefine Node or any of its subclasses.

The Common Lisp programmer is thinking at this point, "what a bizarre
thing to do!".  (In fact, I can hardly believe that the Patterns book
uses the example I outlined above, but that's exactly the example it
picks.)

In Common Lisp you add new methods to a class without having to rewrite
the old class definition or to recompile anything.  And moreover you can
use the multimethod dispatch mechanism of CLOS to allow you to add new
operations *and* new classes of node independently.  (And in CL I don't
think you'd ever want to represent a parse tree as a graph of objects
when you have trees built-in to the language, and S-expressions as a
very nice way of representing parse trees.)

Another example is the Flyweight pattern (p. 195), which tries to work
around the horrible consequences of C++ having to store a virtual table
pointer with each object (so that the smallest possible object is
probably at least as big as two pointers) by sharing and reusing
individual objects when objects are used to represent small but numerous
objects like characters in a document.  In Common Lisp, a vector of
(unsigned-byte 8) can be stored cheaply, but you can still write method
instances for the elements.

Even for the cases where the Patterns book recommends a good solution, I
often think, "why not package this technique up as a nice abstraction
rather than to have to copy out all the boilerplate code each time?"
But that's a different argument (Richard Gabriel has written a lot on
that subject [2]).

[1] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides
    Design patterns: elements of reusable object-oriented software
    Addison-Wesley, 1995

[2] Richard P. Gabriel
    Patterns of software
    Oxford University Press, 1996

-- 
Gareth Rees
From: Scott L. Burson
Subject: Re: Representing abstract syntax trees
Date: 
Message-ID: <38D6FDE9.30AA6048@my-dejanews.com>
Gareth Rees wrote:
> 
> (And in CL I don't
> think you'd ever want to represent a parse tree as a graph of objects
> when you have trees built-in to the language, and S-expressions as a
> very nice way of representing parse trees.)

Actually, S-expressions leave a lot to be desired as an Abstract Syntax Tree
(AST) representation, compared to other representations I have worked with.  A
graph of objects is much better because it gives one an easy way to attach
annotations to the nodes without mucking up the tree structure.  What kind of
annotations would one want to attach?  Some examples:

() Referencing instances of names can be linked to their defining instances. 
Once this linking is done, one no longer has to worry about names and scoping
rules at all; the defining instance, rather than the symbol which is its name,
is then the object that the compiler or code analyzer uses to represent the
variable (or whatever) in the subject language.  One can then analyze and
transform the code without worrying about name collisions (though of course if
one is doing source-to-source transformation, there has to be a final step that
assigns appropriate names to any new variables).

() Many inferrable properties of programs are very naturally and conveniently
expressed as properties of nodes in the parse tree: control and data flow,
inferred type and value constraints, etc. etc.

() Frequently these inferrable properties apply to entire subtrees.  By linking
each node back to its parent, one makes it easy to walk up the tree to find
ancestors with relevant annotations attached.

() It is frequently useful to be able to attach procedures to slots of nodes,
which can compute default values, or perform other work in a data-driven way
when the slots are updated (for instance, updating the aforementioned parent
links).

The Reasoning CBMS ("Code Base Management System"; see
<http://www.reasoning.com/>), which I have used for years, uses a representation
with these properties.  It is, in fact, implemented in Common Lisp.

The wonder of Lisp is not that S-expressions are the very best way of
representing ASTs, but rather that they are an adequate way, and that they are
standardized as part of the language.  Such standardization could certainly be
done for other languages, making it possible to write Lisp-style macros in those
languages as well.  I think the best way to do it would be to use a
representation like Reasoning's.

-- Scott
From: Barry Margolin
Subject: Re: Representing abstract syntax trees
Date: 
Message-ID: <gkNB4.11$vE.262@burlma1-snr2>
In article <·················@my-dejanews.com>,
Scott L. Burson <·······@my-dejanews.com> wrote:
>Gareth Rees wrote:
>> 
>> (And in CL I don't
>> think you'd ever want to represent a parse tree as a graph of objects
>> when you have trees built-in to the language, and S-expressions as a
>> very nice way of representing parse trees.)
>
>Actually, S-expressions leave a lot to be desired as an Abstract Syntax Tree
>(AST) representation, compared to other representations I have worked with.  A
>graph of objects is much better because it gives one an easy way to attach
>annotations to the nodes without mucking up the tree structure.  What kind of
>annotations would one want to attach?  Some examples:

Indeed.  I remember looking at the compiler technology that Symbolics
developed for their Pascal/Ada/C compilers.  It was heavily
object-oriented, and used CLOS objects to represent the AST, for pretty
much the reasons that Scott gave.  He mentioned attaching procedures to
nodes; this can be done by having different node classes and defining
appropriate generic functions and methods.

-- 
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.