From: verec
Subject: Re: defgeneric, defstruct and no CLOS
Date: 
Message-ID: <436852e8$0$38044$5a6aecb4@news.aaisp.net.uk>
On 2005-11-02 05:08:19 +0000, Jack Unrue <·······@example.tld> said:

>> (draw conclusion)
>> (draw bank-account)
>> (draw shape)
>> 
>> I kind of sense that in CL parlance this all what a "generic function"
>> is about. Where I start to get confused is when the CLHS starts
>> talking about ``objects'' according to which the appropriate method
>> of the generic function is selected.
> 
> One thing I gather from your example there is that you want to define
> a single 'function name' that is applicable across domains -- I am
> interpreting 'conclusion', 'bank-account', and 'shape' to be different
> problem domains.  But this function arguably has different semantics in
> each of those domains,

Yes. They would be used in different domains, and would need different
arguments both in kind and number in each of them. I'm just trying to
leverage the polysemy of verbs to mean different things, in situations
where the context (type and number of arguments) would disambiguate.

> and in fact I would guess that more granular
> design would reveal the need for more/different parameters.  E.g.,
> 
> (draw conclusion assumptions evidence)
> (draw bank-account amount)
> (draw shape position)

Exactly.

> As a practical matter, I'm saying that the different variations would
> not necessarily be congruent,

You are right, they wouldn't. Unless by accident, not by design.

> and that is going to prevent defining
> this method in the way that I think you are intending.

Are you saying that, for a given generic function, there
are "congruency" constraints regarding the kind of methods
you can define for it?

> Whereas,
> within problem a domain, you probably will find that there is a
> class hierarchy where such methods would naturally be congruent.

There is no commonality accross the domains. That's the whole point.
In the example I gave in my other reply to Wade (which is about
the practical problem I'm facing right now), I want "load" to
mean ``construct a dictionary from disk'' and ``construct a
grid from disk'', in the same way as I want "locate" to mean
``find the index of that word in the dictionary'' and `` find
the word limit associated with coordinates x and y in that grid''

>> Do I need to understand the whole of CLOS first, or is there a "shortcut"
>> that would allow me to experiment quicker?
> 
> I'm not sure how much of CLOS you mean, but I found the
> defclass/defgeneric/defmethod triumvirate to be pretty approachable.

I'm scared by the MOP ... :-(

>> Is it the same with CLOS/defgeneric/defmethod, or is there a simple(r)
>> way to basically perform function overloading?
> 
> I don't think function overloading is the correct way to think of it.

Please, could you elaborate on what would be a correct way? I'm genuinely
interested in exploring "OO-less" modes of thoughts.

> For one thing, all methods of a generic function have to be congruent
> (hence my comments above).  And function overloading seems to me to
> be a special-case of multiple dispatch.

If you're saying that multiple dispatch would handle my "overloading"
approach, then I'm glad to hear about that clue :-)

>> One possible answer is that I'm too "OO biased" and can't see the world
>> otherwise than "encapsulated state" on one hand, and "state modifying
>> functions" on the other hand... Yet, I'm not too convinced by Scheme-
>> like functional programming either. Is there a third way? I'd love to get
>> a glimpse at it :-)
> 
> Try doing some bottom-up experimentation, and I'll bet that answers to some
> of your questions will fall out in ways that cause you to re-evaluate what
> you can do with CLOS.

I've already done a lot of experimentation on this particular problem, in Java,
and failed. That's why I'm now turning to Lisp. Precisely because I want to
learn to "Think Different" (TM). But I find that I bring my old "OO" habits
to Lisp :-(

Over the past 20+ years, my approach to problem solving has always been to
start any project by concentrating first on what I don't know how to do.
I guess this qualifies as "bottom-up". Yet, I kind of sense that the expression
"bottom-up" has a different meaning in CL, meaning which I find elusive (for
me).

AFAIK, an OO approach is "bottom-up" (at least, mine ;-) What does it look
like, a bottom-up approach that is not OO ?

Many Thanks
-- 
JFB  (defun is more fun than define is fine)

From: Pisin Bootvong
Subject: Re: defgeneric, defstruct and no CLOS
Date: 
Message-ID: <1130913859.528105.90070@g47g2000cwa.googlegroups.com>
verec wrote:
> On 2005-11-02 05:08:19 +0000, Jack Unrue <·······@example.tld> said:
>
> >> (draw conclusion)
> >> (draw bank-account)
> >> (draw shape)
> >>
> >> I kind of sense that in CL parlance this all what a "generic function"
> >> is about. Where I start to get confused is when the CLHS starts
> >> talking about ``objects'' according to which the appropriate method
> >> of the generic function is selected.
> >
> > One thing I gather from your example there is that you want to define
> > a single 'function name' that is applicable across domains -- I am
> > interpreting 'conclusion', 'bank-account', and 'shape' to be different
> > problem domains.  But this function arguably has different semantics in
> > each of those domains,
>
> Yes. They would be used in different domains, and would need different
> arguments both in kind and number in each of them. I'm just trying to
> leverage the polysemy of verbs to mean different things, in situations
> where the context (type and number of arguments) would disambiguate.
>
> > and in fact I would guess that more granular
> > design would reveal the need for more/different parameters.  E.g.,
> >
> > (draw conclusion assumptions evidence)
> > (draw bank-account amount)
> > (draw shape position)
>
> Exactly.
>
> > As a practical matter, I'm saying that the different variations would
> > not necessarily be congruent,
>
> You are right, they wouldn't. Unless by accident, not by design.
>
> > and that is going to prevent defining
> > this method in the way that I think you are intending.
>
> Are you saying that, for a given generic function, there
> are "congruency" constraints regarding the kind of methods
> you can define for it?
>
> > Whereas,
> > within problem a domain, you probably will find that there is a
> > class hierarchy where such methods would naturally be congruent.
>
> There is no commonality accross the domains. That's the whole point.
> In the example I gave in my other reply to Wade (which is about
> the practical problem I'm facing right now), I want "load" to
> mean ``construct a dictionary from disk'' and ``construct a
> grid from disk'', in the same way as I want "locate" to mean
> ``find the index of that word in the dictionary'' and `` find
> the word limit associated with coordinates x and y in that grid''
>

Generic function is for function that has the same meaning. In other
word, a single document on the generic function should describe all its
specialized methods.
Can you think of a single meaning full description for your DRAW method
which takes any of (conclusion, bank-account and shape)?

Different domain need different package. That's why, even in java/C#,
you need package/namespace to distinguished thread.Worker from
factory.Worker. The local name could be the same, but their real name
is not.

If you only use one of either symbols (class names). Then you can use
the unqualified name (DRAW, Worker). But once you start using both
symbol in a section of code, You have to qualified it. (LOGIC:DRAW,
thread.Worker).

> >> Do I need to understand the whole of CLOS first, or is there a "shortcut"
> >> that would allow me to experiment quicker?
> >
> > I'm not sure how much of CLOS you mean, but I found the
> > defclass/defgeneric/defmethod triumvirate to be pretty approachable.
>
> I'm scared by the MOP ... :-(

You don't need MOP yet to do these simple stuffs. MOP is used to alter
the standard behavior of how CLOS works.

>
> >> Is it the same with CLOS/defgeneric/defmethod, or is there a simple(r)
> >> way to basically perform function overloading?
> >
> > I don't think function overloading is the correct way to think of it.
>
> Please, could you elaborate on what would be a correct way? I'm genuinely
> interested in exploring "OO-less" modes of thoughts.
>
> > For one thing, all methods of a generic function have to be congruent
> > (hence my comments above).  And function overloading seems to me to
> > be a special-case of multiple dispatch.
>
> If you're saying that multiple dispatch would handle my "overloading"
> approach, then I'm glad to hear about that clue :-)
>
> >> One possible answer is that I'm too "OO biased" and can't see the world
> >> otherwise than "encapsulated state" on one hand, and "state modifying
> >> functions" on the other hand... Yet, I'm not too convinced by Scheme-
> >> like functional programming either. Is there a third way? I'd love to get
> >> a glimpse at it :-)
> >
> > Try doing some bottom-up experimentation, and I'll bet that answers to some
> > of your questions will fall out in ways that cause you to re-evaluate what
> > you can do with CLOS.
>
> I've already done a lot of experimentation on this particular problem, in Java,
> and failed. That's why I'm now turning to Lisp. Precisely because I want to
> learn to "Think Different" (TM). But I find that I bring my old "OO" habits
> to Lisp :-(
>
> Over the past 20+ years, my approach to problem solving has always been to
> start any project by concentrating first on what I don't know how to do.
> I guess this qualifies as "bottom-up". Yet, I kind of sense that the expression
> "bottom-up" has a different meaning in CL, meaning which I find elusive (for
> me).
>
> AFAIK, an OO approach is "bottom-up" (at least, mine ;-) What does it look
> like, a bottom-up approach that is not OO ?
>

CLOS is neither OO-less nor stateless.

It may be good design to overload in C++

Person.draw(Gun)
Person.draw(Shape)
Person.draw(Conclusion)

However, CLOS emphasize more on the meaning of the operation. One
qualified symbol should have only one meaning.

> Many Thanks
> -- 
> JFB  (defun is more fun than define is fine)
From: Jack Unrue
Subject: Re: defgeneric, defstruct and no CLOS
Date: 
Message-ID: <b1lgm19fpukbmvcj1s4bmun05slgv5nhph@4ax.com>
On Wed, 2 Nov 2005 05:47:20 +0000, verec <·····@mac.com> wrote:
>
> On 2005-11-02 05:08:19 +0000, Jack Unrue <·······@example.tld> said:
>
> You are right, they wouldn't. Unless by accident, not by design.
>
> > and that is going to prevent defining
> > this method in the way that I think you are intending.
>
> Are you saying that, for a given generic function, there
> are "congruency" constraints regarding the kind of methods
> you can define for it?

Yep.  Basically, all methods of a GF have to agree in the
number of their arguments (but note that methods can take
&key and &rest arguments). This is needed to prevent ambiguity
in method selection.  Look up "congruence" and "lambda-list"
in the CLHS; and if you google for those terms, you'll find
references mentioning Guy Steele.

Seibel's book discusses all of this (note especially
footnote 7 on page 194).

> I'm scared by the MOP ... :-(

The MOP is your friend; it wants to help you! :-) Actually,
I have much to learn about the MOP myself.

>>> Is it the same with CLOS/defgeneric/defmethod, or is there a simple(r)
>>> way to basically perform function overloading?
>> 
>> I don't think function overloading is the correct way to think of it.
>
> Please, could you elaborate on what would be a correct way? I'm genuinely
> interested in exploring "OO-less" modes of thoughts.

This is only my opinion, but generally I think your options are either:

- slightly rename the methods based on the concept, as Pascal
  mentioned.  Now, this one is interesting because I had a conversation
  with Surendra Singhi about CLOS wrapper methods in wxCL where I
  suggested that encoding classnames in method names seemed to go against
  proper OOD, and I still feel that way.  This might be your best
  option, especially if you can come up with a naming scheme that doesn't
  tie the methods (or defun's if that's the way you go) too tightly
  with your class names;

or

- use the package system to isolate the different cases; this only works
  if you don't have occasion to use more than one of them in a given
  place in your code.

I hope the other, more experienced Lisp'ers will jump in here and provide
more insight.

> I've already done a lot of experimentation on this particular problem, in Java,
> and failed. That's why I'm now turning to Lisp. Precisely because I want to
> learn to "Think Different" (TM). But I find that I bring my old "OO" habits
> to Lisp :-(

I totally understand, I have come to Lisp from Java (and C++) myself. It does
take some effort to "un-learn" some of the specific concepts from Java.  I still
think more in terms of OOP in my Lisp programming right now than maybe I should.

There have been some past threads in c.l.l. discussing defmethod vs. plain
defuns.  Cf.

http://groups.google.com/group/comp.lang.lisp/browse_frm/thread/4a5fffe3da3a595b/f8ed97daf199ad2e?lnk=st&q=defmethod+%2Bdefun+group:comp.lang.lisp&rnum=1&hl=en#f8ed97daf199ad2e

and the earlier:

http://groups.google.com/group/comp.lang.lisp/browse_frm/thread/7cf3b45f63572f44/01eae96970f2242c?lnk=st&q=method+%2Bcongruence+group:comp.lang.lisp&rnum=2&hl=en#01eae96970f2242c

for a couple of discussions.

> Over the past 20+ years, my approach to problem solving has always been to
> start any project by concentrating first on what I don't know how to do.
> I guess this qualifies as "bottom-up". Yet, I kind of sense that the expression
> "bottom-up" has a different meaning in CL, meaning which I find elusive (for
> me).
>
> AFAIK, an OO approach is "bottom-up" (at least, mine ;-) What does it look
> like, a bottom-up approach that is not OO ?

To me, it's firing up the REPL and typing in code to try out ideas, leaving
so-called proper architecture for later refinement. It's a different mindset
from what you're used to in Java, and it's hard to explain how neat it is that
you can just experiment like that until you've tried it.

One of the key things to remember is a point that Kaz Kylheku made in that
first thread I linked above:

  "...the price for making the ``wrong'' decision too early
is not that great in Lisp compared to some other languages. You don't
have to plan that far ahead; just do what works now. "

-- 
Jack Unrue
From: Jack Unrue
Subject: Re: defgeneric, defstruct and no CLOS
Date: 
Message-ID: <0engm1hsogdp4avmbdih7q2tsv3sokk1vi@4ax.com>
On Wed, 02 Nov 2005 06:29:20 GMT, Jack Unrue <·······@example.tld> wrote:
>
> To me, it's firing up the REPL and typing in code to try out ideas, leaving
> so-called proper architecture for later refinement. It's a different mindset
> from what you're used to in Java, and it's hard to explain how neat it is that
> you can just experiment like that until you've tried it.

BTW, I know you have prior Lisp experience.  So take the above comment
as more of a friendly reminder than telling you something you already
know.

-- 
Jack Unrue
From: Kenny Tilton
Subject: Re: defgeneric, defstruct and no CLOS
Date: 
Message-ID: <nXZ9f.19757$3A4.10867@news-wrt-01.rdc-nyc.rr.com>
verec wrote:

> On 2005-11-02 05:08:19 +0000, Jack Unrue <·······@example.tld> said:
> 
>>> (draw conclusion)
>>> (draw bank-account)
>>> (draw shape)

(conclude result)
(withdraw-amount bank-account)
(render shape)

> ... I'm just trying to
> leverage the polysemy of verbs to mean different things, in situations
> where the context (type and number of arguments) would disambiguate.

That is not the same context as the context that differentiates natural 
language. That context is just computer language syntax. ie, Polysemy is 
not so hot. In fact, natural language sucks where precision is required. 
Folks like to make fun of legalese, but anything less than that leaves 
behind huge loopholes (which is precisely how legalese came to be). Any 
domain requiring precision comes up with a precise albeit constraining 
vocabulary where there is one word for everything and everything has one 
word. This suggests that CLOS, like the rest of CL, somehow Got It Right.

Mind you, I do get a kick out of other languages happening to allow 
different signatures on overloaded names. I just think, as per the 
above, that monosemy roolz.

-- 
Kenny

Why Lisp? http://wiki.alu.org/RtL_Highlight_Film

"I've wrestled with reality for 35 years, Doctor, and I'm happy to state 
I finally won out over it."
     Elwood P. Dowd, "Harvey", 1950
From: Robert Uhl
Subject: Re: defgeneric, defstruct and no CLOS
Date: 
Message-ID: <m364ra3odm.fsf@4dv.net>
verec <·····@mac.com> writes:

> On 2005-11-02 05:08:19 +0000, Jack Unrue <·······@example.tld> said:
>
>>> (draw conclusion)
>>> (draw bank-account)
>>> (draw shape)
>>> I kind of sense that in CL parlance this all what a "generic function"
>>> is about. Where I start to get confused is when the CLHS starts
>>> talking about ``objects'' according to which the appropriate method
>>> of the generic function is selected.
>> One thing I gather from your example there is that you want to define
>> a single 'function name' that is applicable across domains -- I am
>> interpreting 'conclusion', 'bank-account', and 'shape' to be different
>> problem domains.  But this function arguably has different semantics in
>> each of those domains,
>
> Yes. They would be used in different domains, and would need different
> arguments both in kind and number in each of them. I'm just trying to
> leverage the polysemy of verbs to mean different things, in situations
> where the context (type and number of arguments) would disambiguate.

For different domains, I think that packages would be the right way to
go.  That is, have a LOGIC package, a BANKING package and a GRAPHICS
package.  It's generally really, really rare that you'd need to
disambiguate those--that is, a package using LOGIC probably won't need
to use BANKING, and thus you wouldn't need to write logic:draw in stead
of just draw.

> Are you saying that, for a given generic function, there are
> "congruency" constraints regarding the kind of methods you can define
> for it?

Yup.  Although of course you could create your own generic function
system.  Lisp is programmable, after all...

-- 
Robert Uhl <http://public.xdi.org/=ruhl>
Contrary to popular opinion there often is a right answer.
            --Carter & Sanger, Thinking about Programming
From: Peter Seibel
Subject: Re: defgeneric, defstruct and no CLOS
Date: 
Message-ID: <m2k6fq93vx.fsf@gigamonkeys.com>
verec <·····@mac.com> writes:

> On 2005-11-02 05:08:19 +0000, Jack Unrue <·······@example.tld> said:
>
>>> (draw conclusion)
>>> (draw bank-account)
>>> (draw shape)
>>> I kind of sense that in CL parlance this all what a "generic
>>> function"
>>> is about. Where I start to get confused is when the CLHS starts
>>> talking about ``objects'' according to which the appropriate method
>>> of the generic function is selected.
>> One thing I gather from your example there is that you want to
>> define
>> a single 'function name' that is applicable across domains -- I am
>> interpreting 'conclusion', 'bank-account', and 'shape' to be different
>> problem domains.  But this function arguably has different semantics in
>> each of those domains,
>
> Yes. They would be used in different domains, and would need different
> arguments both in kind and number in each of them. I'm just trying to
> leverage the polysemy of verbs to mean different things, in situations
> where the context (type and number of arguments) would disambiguate.

Okay, in that case (which I missed in your earlier posts--probably
from not reading carefully enough) you shouldn't use generic
functions--a generic function defines a single conceptual operation
which can be applied (with some variation) to different types of
objects. If you just want a bunch of unrelated functions you need to
give them different names. However you can use the same "name" across
different domains be defining different packages:

  (defpackage :logic
    (:use :cl)
    (:export :draw))

  (defpackage :banking
    (:use :cl)
    (:export :draw))

  (defpackage :2d-graphics
    (:use :cl)
    (:export :draw))

Now you can define three different DRAW functions, LOGIC:DRAW which
takes a conclusion, BANKING:DRAW which takes a bank account (and
presumably an ammount), and 2D-GRAPHICS:DRAW which takes a shape. In
any given piece of code, you may or may not need to use the fully
qualified name--if you're writing code that deals with all three
domains at once, you will need to qualify at least two of them, but
usually you'll only be dealing with one of these domains at a time and
you can USE-PACKAGE the appropriate package so that DRAW will be read
as the appropriate symbol.

> Are you saying that, for a given generic function, there
> are "congruency" constraints regarding the kind of methods
> you can define for it?

Yes.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/