Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

defgeneric, defstruct and no CLOS

222 views
Skip to first unread message

verec

unread,
Nov 1, 2005, 11:15:35 PM11/1/05
to
I'm again a bit confused. Basically, what I want to do, is to be
able to define a single "function" name, reused (ie: "redefined")
for various combinations of arguments such that I can:

(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.

I guess my problem is also a terminlogy problem. As I understand
it, most everything in CL is an object (in the sense: can be garbage
collected) whether it is a "cons cell" or an instance of a CLOS class.
Does that mean that I can specialize a method on a cons cell type?

My real goal, at this stage, is to start defining my data structures using
defstruct, and be able to define "context free" names for functions, which,
when "specialized" for a given "type" (as far as defstruct defines types)
will resolve to the correct body of code.

Do I need to understand the whole of CLOS first, or is there a "shortcut"
that would allow me to experiment quicker?

20 years or so ago, when "Inside Mac" in 3 volumes first appeared,
the joke was that: "In order to understand Inside Mac, you have first
to ... understand Inside Mac!" -- and I must admit that I had to read
slowly the three volumes, from cover to cover, at least three times,
before I got to the "Aha!".

Is it the same with CLOS/defgeneric/defmethod, or is there a simple(r)
way to basically perform function overloading?

I get even more confused when I start to consider that in CL, values
are typed, but identifiers (ie symbols) are not, unless ``(declare
(sometype x))''
and I don't see (yet?) how ``overloading'' would work nor how I would
go about to
(defun draw (conclusion) ...)
(defun draw (shape) ...)
and have the right code be called when a form simply contains
(draw x)

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 :-)

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

Wade Humeniuk

unread,
Nov 1, 2005, 11:21:51 PM11/1/05
to
verec wrote:

>
> 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 :-)
>

The Rolling in the Mud Way. Which means, write what you want in the
most expressive way (rigorously in s-exps) you can and then implement it.

Wade

Jack Unrue

unread,
Nov 2, 2005, 12:08:19 AM11/2/05
to
On Wed, 2 Nov 2005 04:15:35 +0000, verec <ve...@mac.com> wrote:
>
> I'm again a bit confused. Basically, what I want to do, is to be
> able to define a single "function" name, reused (ie: "redefined")
> for various combinations of arguments such that I can:
>
> (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, 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)

As a practical matter, I'm saying that the different variations would
not necessarily be congruent, and that is going to prevent defining
this method in the way that I think you are intending. Whereas,
within problem a domain, you probably will find that there is a
class hierarchy where such methods would naturally be congruent.

> I guess my problem is also a terminlogy problem. As I understand
> it, most everything in CL is an object (in the sense: can be garbage
> collected) whether it is a "cons cell" or an instance of a CLOS class.
> Does that mean that I can specialize a method on a cons cell type?
>
> My real goal, at this stage, is to start defining my data structures using
> defstruct, and be able to define "context free" names for functions, which,
> when "specialized" for a given "type" (as far as defstruct defines types)
> will resolve to the correct body of code.
>
> 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.

> 20 years or so ago, when "Inside Mac" in 3 volumes first appeared,
> the joke was that: "In order to understand Inside Mac, you have first
> to ... understand Inside Mac!" -- and I must admit that I had to read
> slowly the three volumes, from cover to cover, at least three times,
> before I got to the "Aha!".
>
> 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.
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. I'm sure I don't yet understand
all of the implications.

> I get even more confused when I start to consider that in CL, values
> are typed, but identifiers (ie symbols) are not, unless ``(declare
> (sometype x))''
> and I don't see (yet?) how ``overloading'' would work nor how I would
> go about to
> (defun draw (conclusion) ...)
> (defun draw (shape) ...)
> and have the right code be called when a form simply contains
> (draw x)
>
> 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.

--
Jack Unrue

verec

unread,
Nov 2, 2005, 12:12:38 AM11/2/05
to
On 2005-11-02 04:21:51 +0000, Wade Humeniuk
<whumeniu+...@telus.net> said:

I guess what you're saying is: "Just do it!". But I'm still a bit
encumbered by some noise in my head :-(

Let's consider this current project I'm working on at the moment
(http://lisp.jfb-city.co.uk)

o I've got a file that contains 100,000 sorted english words.
I want to read that file from disk into a "someting". Let's
call that something: dict

o I've got another file that contains a 15x15 grid that I also
want to read from disk into another something. Let's call
that: grid

Obviously, I can define:
(defun load-dict (dict-name) ...)
and
(defun load-grid (grid-name) ...)

But that "noise in my head" I was referring to above is nagging
me, and claims loudly to my hears: "This is crap! What you want
is: (defun load (grid) ... ) and (defun load (dict) ...)"

So, my question realy is, assuming both:
(defstruct grid ...) and
(defstruct dict ...)

how would I go about

(defun load (grid) ... ) and

(defun load (dict) ... ) and while I'm there, not shadow the

standard cl::load ?

This suggests using packages as a means of encapsulation
but that little voice is not too happy with that idea either.

If this kind of "overloading" is not "the Lisp way" then that's
fine with me too, but what would be "the Lisp way" in that case?

The thing is, I've got quite a few "generic" verbs that I'd like
to apply to any ``object''. In that example, and assuming that
overloading can be made to work (and is "idiomatic"), I'd
add to the party:

(defun locate (grid x y)
"Returns the word limit associated with coordinates
x and y of the grid"
... )

and

(defun locate (dict word)
"Returns the index of the word if found, or the one's complement
of the index this word would need to be inserted at if not
found"
...)

In short: how can I make this overloading work, or, what would be a
better (more idiomatic) alternative?

Pascal Bourguignon

unread,
Nov 2, 2005, 12:16:12 AM11/2/05
to
verec <ve...@mac.com> writes:

> I'm again a bit confused. Basically, what I want to do, is to be
> able to define a single "function" name, reused (ie: "redefined")
> for various combinations of arguments such that I can:
>
> (draw conclusion)
> (draw bank-account)
> (draw shape)

A misconception.

All the methods of the same generic function must implement the same
generic function, only for different type of arguments.


Drawing a conclusion, drawing a bank account and drawing a shape are
three totally different concepts, three different functions and should
be named differently. At least, they cannot be methods to the same
generic function.

You could write:

(defun logic:draw (conclusion premises) ...)
(defun bank:draw (account amount) ...)
(defun graphic:draw (shape color line-thickness) ...)

If you really had to handle conclusions, bank accounts and shapes in
the same pacakage, then write:

(defun draw-conclusion (conclusion premises) ...)
(defun draw-account (account amount) ...)
(defun draw-shape (shape color line-thickness) ...)

And if you have different kind of conclusions, different kind of
accounts, or different kinds of shapes:

(defgeneric draw-conclusion (conclusion premises))
(defgeneric draw-account (account amount))
(defgeneric draw-shape (shape color line-thickness))

(defmethod draw-conclusion ((conclusion binary-logic-predicate) premises) ...)
(defmethod draw-conclusion ((conclusion ternary-logic-predicate) premises) ...)

(defmethod draw-account ((account devise-account) amount) ...)
(defmethod draw-account ((account shares-account) amount) ...)

(defmethod draw-shape ((shape triangle) (color rgb-color) line-thickness) ...)
(defmethod draw-shape ((shape triangle) (color cymk-color) line-thickness) ...)
(defmethod draw-shape ((shape square) (color color) line-thickness) ...)

Otherwise, you could just write one big generic function named PERFORM
and be done with names.


> I guess my problem is also a terminlogy problem.

CLHS contains a big glossary. Read it!


> Does that mean that I can specialize a method on a cons cell type?

Irrelevant, but yes. There's only one type of cons cell, but:


(defmethod perform ((object cons))
(print `(this is a cons cell \: object)))

;; vs.:

(defmethod perform ((object integer))
(print `(this is an integer \: object)))


(perform (cons 'a 'b))
(perform 5550960)

> Do I need to understand the whole of CLOS first, or is there a "shortcut"
> that would allow me to experiment quicker?

There are two short-cuts.

One is the touristic short-cut, for sportive people (named: REPL).
Perhaps not so short, but you can get nice cuts.

The other looks longer at first sight, but is good for chamber
programmers (named: CLHS).


> 20 years or so ago, when "Inside Mac" in 3 volumes first appeared,
> the joke was that: "In order to understand Inside Mac, you have first
> to ... understand Inside Mac!" -- and I must admit that I had to read
> slowly the three volumes, from cover to cover, at least three times,
> before I got to the "Aha!".

Yes, things didn't change yet, we still have no way to download
Kung-Fu directly to your brains. Note that in Matrix it was possible
after all only because they were actually in a bigger computer.


> Is it the same with CLOS/defgeneric/defmethod, or is there a simple(r)
> way to basically perform function overloading?

Overloading is not a CLOS notion. C++ is this way --->


> I get even more confused when I start to consider that in CL, values
> are typed, but identifiers (ie symbols) are not, unless ``(declare
> (sometype x))''

Not even, these type declaration only tell the compiler that you
guarantee that you'll never bind a _value_ of another type to this
variable. The variable is still untyped.

> and I don't see (yet?) how ``overloading'' would work nor how I would
> go about to
> (defun draw (conclusion) ...)
> (defun draw (shape) ...)
> and have the right code be called when a form simply contains
> (draw x)

Don't be afraid, draw your own conclusion! Indeed, how could you
overload if there's not typed variables?


> 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?

Are you French, by happenstance?


> I'd love to get a glimpse at it :-)

--
__Pascal Bourguignon__ http://www.informatimago.com/

There is no worse tyranny than to force a man to pay for what he does not
want merely because you think it would be good for him. -- Robert Heinlein

Pascal Bourguignon

unread,
Nov 2, 2005, 12:26:12 AM11/2/05
to
verec <ve...@mac.com> writes:
> So, my question realy is, assuming both:
> (defstruct grid ...) and
> (defstruct dict ...)
>
> how would I go about
>
> (defun load (grid) ... ) and
>
> (defun load (dict) ... ) and while I'm there, not shadow the
>
> standard cl::load ?

standard cl::load or standard cl::read are perfectly good:

(defstruct grid rows cols)
(defstruct dict words)

(let ((grid (make-grid :rows 15 :cols 10))
(dict (make-dict :words '("suggests""using""packages""as"
"a""means""of""encapsulation"))))
(with-open-file (out "dict.data" :direction :output
:if-does-not-exist :create :if-exists :supersede)
(print dict out))
(with-open-file (out "grid.data" :direction :output
:if-does-not-exist :create :if-exists :supersede)
(print grid out)))

;; Now:

(defparameter my-grid (with-open-file (in "grid.data") (read in)))
(defparameter my-dict (with-open-file (in "dict.data") (read in)))

But what cood would it be to call (load grid) if the file contains a dict?
That's why you call load or read, and you get what value there is in the file.
You've not taken the red pill yet. ;-)


--
"You cannot really appreciate Dilbert unless you read it in the
original Klingon"

Kenny Tilton

unread,
Nov 2, 2005, 12:27:41 AM11/2/05
to

Pascal Bourguignon wrote:

> verec <ve...@mac.com> writes:
>
>
>>I'm again a bit confused. Basically, what I want to do, is to be
>>able to define a single "function" name, reused (ie: "redefined")
>>for various combinations of arguments such that I can:
>>
>>(draw conclusion)
>>(draw bank-account)
>>(draw shape)
>
>
> A misconception.
>
> All the methods of the same generic function must implement the same
> generic function, only for different type of arguments.
>
>
> Drawing a conclusion, drawing a bank account and drawing a shape are
> three totally different concepts, three different functions and should
> be named differently. At least, they cannot be methods to the same
> generic function.

For a newby, let's make clear that the language itself does not prevent
this. Rather, the functionality itself will soon enough force the GF
signatures to deviate, so yes, this probably idly chosen trio /should
not/ be given the same names.

--
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

verec

unread,
Nov 2, 2005, 12:47:20 AM11/2/05
to
On 2005-11-02 05:08:19 +0000, Jack Unrue <no....@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

Jack Unrue

unread,
Nov 2, 2005, 1:29:20 AM11/2/05
to
On Wed, 2 Nov 2005 05:47:20 +0000, verec <ve...@mac.com> wrote:
>
> On 2005-11-02 05:08:19 +0000, Jack Unrue <no....@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

verec

unread,
Nov 2, 2005, 1:33:33 AM11/2/05
to
On 2005-11-02 05:26:12 +0000, Pascal Bourguignon <sp...@mouse-potato.com> said:

>> So, my question realy is, assuming both:
>> (defstruct grid ...) and
>> (defstruct dict ...)
>>
>> how would I go about
>> (defun load (grid) ... ) and
>> (defun load (dict) ... ) and while I'm there, not shadow the
>> standard cl::load ?
>
> standard cl::load or standard cl::read are perfectly good:

[snip]

> ;; Now:
>
> (defparameter my-grid (with-open-file (in "grid.data") (read in)))
> (defparameter my-dict (with-open-file (in "dict.data") (read in)))

In the first part you didn't quote, I had written:


> Obviously, I can define:
> (defun load-dict (dict-name) ...)
> and
> (defun load-grid (grid-name) ...)

You are just proposing an alternate way to *not* define "load" or "load-dict"

In a second part you didn't quote, I had written:

> (defun locate (grid x y) ...
> ...
> (defun locate (dict word) ...

Which was meant to emphasize that my intention was to take advantage
of natural language verbs polysmey to mean different things at different
times (in different contexts).

This may not be the Lisp way. And that's why I asked a double question:
1. is it possible to do "overloading" in Lisp and
2. whether it is possible or not, is it compatible with the Lisp way
and if it is not, what would be the Lisp way.

So far, I construe your answers as:
1. I could use packages, but that's ugly (and I would concur)
2. "overloading" is not the Lisp way

That's fine with me. But while most answers are of the form
"don't do this", few, if any, are of the form "do that, instead"
(your transforming my initial (defun load-dict ()) into
(defparameter my-dict ...) doesn't really count as another
way of _thinking_, does it?)

> But what cood would it be to call (load grid) if the file contains a dict?

That's very true, but not exactly relevant to the question ...

> That's why you call load or read, and you get what value there is in the file.

Don't focus on "load" as such. Tell me the same story, but using "locate"
this time, as an example. That way it won't clash with any preconceived
notion.

> You've not taken the red pill yet. ;-)

I'd rather have belgian chocolate :-)

Jack Unrue

unread,
Nov 2, 2005, 1:35:02 AM11/2/05
to
On Wed, 02 Nov 2005 06:29:20 GMT, Jack Unrue <no....@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

Pisin Bootvong

unread,
Nov 2, 2005, 1:44:19 AM11/2/05
to

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.

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.

Kenny Tilton

unread,
Nov 2, 2005, 2:31:31 AM11/2/05
to

verec wrote:

> On 2005-11-02 05:08:19 +0000, Jack Unrue <no....@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.

Kalle Olavi Niemitalo

unread,
Nov 2, 2005, 2:59:59 AM11/2/05
to
Pascal Bourguignon <sp...@mouse-potato.com> writes:

> Otherwise, you could just write one big generic function named PERFORM
> and be done with names.

Or you could just use Perl.
http://aspn.activestate.com/ASPN/CodeDoc/Acme-Bleach/Acme/DWIM.html

Mario Tanev

unread,
Nov 2, 2005, 9:20:00 AM11/2/05
to
That is not necessarily a problem, since a generic is allowed to take a
variable number of parameters. Here's how to go around that:

;; super-class
(defclass parent () ())

;; sub-class
(defclass child (parent) ())

;; mystery defined on parent (1 parameter version
(defmethod mystery ((object parent) &rest args)
(apply #'(lambda (x) (not x)) args))

;; mystery defined on child
(defmethod mystery ((object child) &rest args)
(apply #'(lambda (x y) (+ x y)) args))

;; inherited? _only_ defined on parent
(defmethod inherited? ((object parent) &rest args)
(apply #'(lambda () (format t "Answer: It was defined on class parent
~%" )) args))

(defparameter pobj (make-instance 'parent))
(defparameter cobj (make-instance 'child))

;; Here we call mystery with 1 parameter
(format t "(mystery pobj nil) -> ~A~%" (mystery pobj nil))

;; Here we call mystery with 2 parameters
(format t "(mystery cobj 2 3) -> ~A~%" (mystery cobj 2 3))

(format t "Question: Where was inherited defined for pobj? ")
(inherited? pobj)
(format t "Question: Where was inherited defined for cobj? ")
(inherited? cobj)

;; So what is this clunkyness with apply/lambda
;; Well, we can avoid it with macros
;; Unfortunately it only specializes on the first parameter
(defmacro defvirtual (name ((object class) &rest formals) &rest body)
`(defmethod ,name ((,object ,class) &rest args)
(apply #'(lambda ,formals ,@body) args)))

;; Now let's try it again
(defvirtual myth ((object parent) x)
(not x))

(defvirtual myth ((object child) x y)
(+ x y))

;; Here we call myth with 1 parameter
(format t "(myth pobj nil) -> ~A~%" (myth pobj nil))

;; Here we call myth with 2 parameters
(format t "(myth cobj 2 3) -> ~A~%" (myth cobj 2 3))

Homework:
Is there a way to call myth with 1 parameter on cobj and have it invoke the
pobj version? Modify defvirtual to achieve that. Even better, make
defvirtual optionally specialize on more than one parameter.

And just a note, you don't need defmethod or defgeneric at all, you can
create your own macros that operate on hash tables of "methods" and achieve
the functionality *you* need.

Joe Marshall

unread,
Nov 2, 2005, 10:53:55 AM11/2/05
to
verec <ve...@mac.com> writes:

> I'm again a bit confused. Basically, what I want to do, is to be
> able to define a single "function" name, reused (ie: "redefined")
> for various combinations of arguments such that I can:
>
> (draw conclusion)
> (draw bank-account)
> (draw shape)
>
> I kind of sense that in CL parlance this all what a "generic function"
> is about.

Yes and no. The word `draw' in the above examples has very different
meanings (that is, if you don't want (draw bank-account) to make a
little box with some money in it on the screen). CLOS is specifically
*not* designed with this in mind.

On the other hand, if your example was this:

(draw shape x y)
(draw text x y)
(draw cursor x y)

Then CLOS *is* what you want.

> 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.
>
> I guess my problem is also a terminlogy problem. As I understand
> it, most everything in CL is an object (in the sense: can be garbage
> collected) whether it is a "cons cell" or an instance of a CLOS class.
> Does that mean that I can specialize a method on a cons cell type?

Yes. CLOS integrates with the rest of the common lisp type system.

> My real goal, at this stage, is to start defining my data structures using
> defstruct, and be able to define "context free" names for functions, which,
> when "specialized" for a given "type" (as far as defstruct defines types)
> will resolve to the correct body of code.

While you *can* use defstructs, classes are supposed to be a
replacement. It is perfectly reasonable to use a class as sort of a
verbose version of defstruct and make no use of inheritance or other
fancy object features. In fact, I'd recommend it.

> Do I need to understand the whole of CLOS first, or is there a "shortcut"
> that would allow me to experiment quicker?

Dive in. CLOS is big, and 90% of it is magic that is not necessary to
know (but *really* nice to have in the background). You can start
with the simplest aspects of CLOS and gain a great amount of benefit.

> 20 years or so ago, when "Inside Mac" in 3 volumes first appeared,
> the joke was that: "In order to understand Inside Mac, you have first
> to ... understand Inside Mac!" -- and I must admit that I had to read
> slowly the three volumes, from cover to cover, at least three times,
> before I got to the "Aha!".

Nah, I tried that with CLOS and decided it was `too hairy'. Then I
started working with CLOS on a project and saw the light.

> Is it the same with CLOS/defgeneric/defmethod, or is there a simple(r)
> way to basically perform function overloading?

A terminology point. Overloading is bad. Overloading means taking a
name and using it for completely different purposes and expecting to
disambiguate by context. A generic function is a function that
applies to a wide range of argument types and does `the same sort of
thing' to each object.

> I get even more confused when I start to consider that in CL, values
> are typed, but identifiers (ie symbols) are not, unless ``(declare
> (sometype x))''
> and I don't see (yet?) how ``overloading'' would work nor how I would
> go about to
> (defun draw (conclusion) ...)
> (defun draw (shape) ...)
> and have the right code be called when a form simply contains
> (draw x)

Right. That's why overloading doesn't work.

> 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 :-)

Yes. Forget `encapsulation'. CLOS gives you functions on steroids.

Joe Marshall

unread,
Nov 2, 2005, 10:57:30 AM11/2/05
to
verec <ve...@mac.com> writes:

> Let's consider this current project I'm working on at the moment
> (http://lisp.jfb-city.co.uk)
>
> o I've got a file that contains 100,000 sorted english words.
> I want to read that file from disk into a "someting". Let's
> call that something: dict
>
> o I've got another file that contains a 15x15 grid that I also
> want to read from disk into another something. Let's call
> that: grid
>
> Obviously, I can define:
> (defun load-dict (dict-name) ...)
> and
> (defun load-grid (grid-name) ...)
>
> But that "noise in my head" I was referring to above is nagging
> me, and claims loudly to my hears: "This is crap! What you want
> is: (defun load (grid) ... ) and (defun load (dict) ...)"

Exactly where a generic function would be great.

> So, my question realy is, assuming both:
> (defstruct grid ...) and
> (defstruct dict ...)
>
> how would I go about
>
> (defun load (grid) ... ) and
>
> (defun load (dict) ... ) and while I'm there, not shadow the
>
> standard cl::load ?
>
> This suggests using packages as a means of encapsulation
> but that little voice is not too happy with that idea either.
>
> If this kind of "overloading" is not "the Lisp way" then that's
> fine with me too, but what would be "the Lisp way" in that case?

Separating the LOAD that you define from CL:LOAD is what you would do
with packages. Frankly, that's more of a pain than I'd want to deal
with, so I'd define a new generic function like `LOAD-OBJECT'.

> The thing is, I've got quite a few "generic" verbs that I'd like
> to apply to any ``object''. In that example, and assuming that
> overloading can be made to work (and is "idiomatic"), I'd
> add to the party:
>
> (defun locate (grid x y)
> "Returns the word limit associated with coordinates
> x and y of the grid"
> ... )
>
> and
>
> (defun locate (dict word)
> "Returns the index of the word if found, or the one's complement
> of the index this word would need to be inserted at if not
> found"
> ...)
>
> In short: how can I make this overloading work, or, what would be a
> better (more idiomatic) alternative?

This kind of overloading you *wouldn't* use CLOS for. A position in a
dictionary is a very different thing from a grid co-ordinate.

Pascal Bourguignon

unread,
Nov 2, 2005, 11:08:04 AM11/2/05
to
verec <ve...@mac.com> writes:

> On 2005-11-02 05:26:12 +0000, Pascal Bourguignon <sp...@mouse-potato.com> said:
>
>>> So, my question realy is, assuming both:
>>> (defstruct grid ...) and
>>> (defstruct dict ...)
>>> how would I go about
>>> (defun load (grid) ... ) and
>>> (defun load (dict) ... ) and while I'm there, not shadow the
>>> standard cl::load ?
>> standard cl::load or standard cl::read are perfectly good:
>
> [snip]
>
>> ;; Now:
>> (defparameter my-grid (with-open-file (in "grid.data") (read in)))
>> (defparameter my-dict (with-open-file (in "dict.data") (read in)))
>
> In the first part you didn't quote, I had written:
>> Obviously, I can define:
>> (defun load-dict (dict-name) ...)
>> and
>> (defun load-grid (grid-name) ...)
>
> You are just proposing an alternate way to *not* define "load" or "load-dict"

Yes.


> In a second part you didn't quote, I had written:
>
>> (defun locate (grid x y) ...
>> ...
>> (defun locate (dict word) ...
>
> Which was meant to emphasize that my intention was to take advantage
> of natural language verbs polysmey to mean different things at different
> times (in different contexts).

You could have a look at Pascal Costanza's ContextL.
But Lisp is not a natural language.

If you want ambiguity, and resolving ambiguity with context and
semantics, you'll have to design a new language.


> This may not be the Lisp way. And that's why I asked a double question:
> 1. is it possible to do "overloading" in Lisp and

Everything's possible. It's possible. We've done it in c.l.l. a few
months ago when we designed some macros to be able to write overloaded
methods like in C++ with even different number of arguments.


> 2. whether it is possible or not, is it compatible with the Lisp way
> and if it is not, what would be the Lisp way.

Lisp accepts all kind of torture. If it needed by your problem at
hand, go ahead.


> So far, I construe your answers as:
> 1. I could use packages, but that's ugly (and I would concur)

Not really. You only change one character in the names:

grid-load vs. grid:load
dict-load vs. dict:load


> 2. "overloading" is not the Lisp way

As I said, overloading is not in CLHS glossary. This is not a CLOS
notion. You can have dispatch based on the type of the arguments, and
you can have it automatically with generic functions, but the notion
of overloading is not native.


> [...]

--
__Pascal Bourguignon__ http://www.informatimago.com/

In a World without Walls and Fences,
who needs Windows and Gates?

John Thingstad

unread,
Nov 2, 2005, 12:24:56 PM11/2/05
to
On Wed, 02 Nov 2005 05:15:35 +0100, verec <ve...@mac.com> wrote:

> I'm again a bit confused. Basically, what I want to do, is to be
> able to define a single "function" name, reused (ie: "redefined")
> for various combinations of arguments such that I can:
>

I'm a bit confused myself. Either use methods and eq specializers or use
defun and make it part of the name (make point x y) vs
(make-point x y). You are not programming Java now!
And if you want a object oriented perspective why not use CLOS?
Paul Graham might not like CLOS but he is a minority among CL Lisp users.
How about reading another book (one I like) Practical Common Lisp
at www.gigamonkeys/book/ and reassess.

--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/

John Thingstad

unread,
Nov 2, 2005, 12:28:48 PM11/2/05
to
On Wed, 02 Nov 2005 18:24:56 +0100, John Thingstad
<john.th...@chello.no> wrote:

> On Wed, 02 Nov 2005 05:15:35 +0100, verec <ve...@mac.com> wrote:
>
>> I'm again a bit confused. Basically, what I want to do, is to be
>> able to define a single "function" name, reused (ie: "redefined")
>> for various combinations of arguments such that I can:
>>
>

> defun and make it part of the name (make point x y)

before they start.. (make 'point x y)

Kenny Tilton

unread,
Nov 2, 2005, 1:04:44 PM11/2/05
to

Joe Marshall wrote:


> verec <ve...@mac.com> writes:
>>20 years or so ago, when "Inside Mac" in 3 volumes first appeared,
>>the joke was that: "In order to understand Inside Mac, you have first
>>to ... understand Inside Mac!" -- and I must admit that I had to read
>>slowly the three volumes, from cover to cover, at least three times,
>>before I got to the "Aha!".
>
>
> Nah, I tried that with CLOS and decided it was `too hairy'.

You mean Keene? The menu at TGIF's is bigger! defclass, defmethod,
:before, :after, :around -- where is the hard part?!

You must have started with AMOP by mistake.

Robert Uhl

unread,
Nov 2, 2005, 1:10:08 PM11/2/05
to
verec <ve...@mac.com> writes:
>
> I'm again a bit confused. Basically, what I want to do, is to be
> able to define a single "function" name, reused (ie: "redefined")
> for various combinations of arguments such that I can:
>
> (draw conclusion)
> (draw bank-account)
> (draw shape)
>
> I kind of sense that in CL parlance this all what a "generic function"
> is about.

Yup. You can define a generic function which will choose the right
method to run based on the type of the arguments. One thing which may
be surprising is that every method must have congruent arguments.

> I get even more confused when I start to consider that in CL, values
> are typed, but identifiers (ie symbols) are not, unless ``(declare
> (sometype x))''
> and I don't see (yet?) how ``overloading'' would work nor how I would
> go about to
> (defun draw (conclusion) ...)
> (defun draw (shape) ...)
> and have the right code be called when a form simply contains
> (draw x)

You create the generic function with DEFGENERIC; you then create each
method with DEFMETHOD (actually, the generic function can be implicitly
created by DEFMETHOD, but it's good practise not to do it that way).
E.g., assuming that you've previously defined classes CONCLUSION,
BANK-ACCOUNT and SHAPE:

(defgeneric draw (x)
(:documentation "This is a generic draw function which can do lots of
stuff.))

(defmethod draw ((conc conclusion))
"Draw a conclusion"
(print "I'm drawing a conclusion!))

(defmethod draw ((acct bank-account))
"Draw a bank account"
(print "Ain't banks fun?"))

Or something along those lines.

--
Robert Uhl <http://public.xdi.org/=ruhl>
If you stand on your head, you will get footprints in your hair.

Robert Uhl

unread,
Nov 2, 2005, 1:17:57 PM11/2/05
to
verec <ve...@mac.com> writes:

> On 2005-11-02 05:08:19 +0000, Jack Unrue <no....@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...

Contrary to popular opinion there often is a right answer.
--Carter & Sanger, Thinking about Programming

Pascal Bourguignon

unread,
Nov 2, 2005, 3:00:26 PM11/2/05
to
verec <ve...@mac.com> writes:
> [...]

> (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.
> [...]

> My real goal, at this stage, is to start defining my data structures using
> defstruct, and be able to define "context free" names for functions, which,
> when "specialized" for a given "type" (as far as defstruct defines types)
> will resolve to the correct body of code.
> [...]

Ok, by now it should be clear that the generic function model is not
meant to do that. You've got the choice between using the generic
function model for what it is designed, or to go on with inventing a
new language.

Why should you limit your syntax to one word prefix?

You could want to write ambiguous sentences such as:

(get a dictionary dict from the file "dict.data")
(get the interface eth0 up)
(get the element x out of list)
(get the table get the association (:name "Pascal") by heart)

You'd just need to write some nlp layer over CL to compile these
statements to unambiguous low-level lisp code.

No kidding.
Just have a look at the LOOP macro which does quite the same thing.


--
"Debugging? Klingons do not debug! Our software does not coddle the
weak."

Peter Seibel

unread,
Nov 2, 2005, 3:36:32 PM11/2/05
to
verec <ve...@mac.com> writes:

> Obviously, I can define:
> (defun load-dict (dict-name) ...)
> and
> (defun load-grid (grid-name) ...)
>
> But that "noise in my head" I was referring to above is nagging
> me, and claims loudly to my hears: "This is crap! What you want
> is: (defun load (grid) ... ) and (defun load (dict) ...)"
>
> So, my question realy is, assuming both:
> (defstruct grid ...) and
> (defstruct dict ...)
>
> how would I go about
>
> (defun load (grid) ... ) and
>
> (defun load (dict) ... ) and while I'm there, not shadow the
>
> standard cl::load ?

I think you're life will get better if you separate the two problems
you're wrestling with. One is how to define generic functions so that
you can use the same name for different (but related) operations,
depending on the type of the objects to which you apply the
operation. The other is what to do when you want to use a name that is
the same as a symbol exported from the COMMON-LISP package.

To solve the first problem you indeed define a generic function:

(defgeneric load-from-disk (thing source)
(:documentation "Populate THING with data from SOURCE."))

(defmethod load-from-disk ((thing grid) (source stream)) ...)

(defmethod load-from-disk ((thing dict) (source stream)) ...)

To solve the second problem you either bite the bullet and define your
own package in which you shadow the name you want to use (e.g. LOAD)
or decide that you can live with a different name. In general it's
probably a bad idea to shadow a symbol from the COMMON-LISP package
just to use a name--sometimes it's appropriate if you actually want to
replace the functionality of the function (or whatever) named by the
symbol in the COMMON-LISP pacakge. For instance, if you were working
on a system where you wanted every function definition to squirrel
away some extra info, you might shadow DEFUN and define your own macro
that expanded into a CL:DEFUN form plus some other bits.

> This suggests using packages as a means of encapsulation
> but that little voice is not too happy with that idea either.

Packages aren't for encapsulation--they're for managing namespaces.

> If this kind of "overloading" is not "the Lisp way" then that's
> fine with me too, but what would be "the Lisp way" in that case?

Use a different name. This is sometimes annoying but there it is.

> The thing is, I've got quite a few "generic" verbs that I'd like to
> apply to any ``object''. In that example, and assuming that
> overloading can be made to work (and is "idiomatic"), I'd add to the
> party:
>
> (defun locate (grid x y)
> "Returns the word limit associated with coordinates
> x and y of the grid"
> ... )
>
> and
>
> (defun locate (dict word)
> "Returns the index of the word if found, or the one's complement
> of the index this word would need to be inserted at if not
> found"
> ...)
>
> In short: how can I make this overloading work, or, what would be a
> better (more idiomatic) alternative?

For this, since there's no LOCATE in the COMMON-LISP package you just
need to use DEFGENERIC and DEFMETHOD.

-Peter

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

Peter Seibel

unread,
Nov 2, 2005, 3:44:03 PM11/2/05
to
verec <ve...@mac.com> writes:

> On 2005-11-02 05:08:19 +0000, Jack Unrue <no....@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.

verec

unread,
Nov 2, 2005, 6:40:59 PM11/2/05
to
Many thanks to all.

I will ponder all your remarks for a few days.

Joe Marshall

unread,
Nov 2, 2005, 9:05:35 PM11/2/05
to
Kenny Tilton <kti...@nyc.rr.com> writes:

> Joe Marshall wrote:
>> verec <ve...@mac.com> writes:
>>>20 years or so ago, when "Inside Mac" in 3 volumes first appeared,
>>>the joke was that: "In order to understand Inside Mac, you have first
>>>to ... understand Inside Mac!" -- and I must admit that I had to read
>>>slowly the three volumes, from cover to cover, at least three times,
>>>before I got to the "Aha!".
>> Nah, I tried that with CLOS and decided it was `too hairy'.
>
> You mean Keene? The menu at TGIF's is bigger! defclass, defmethod,
> :before, :after, :around -- where is the hard part?!
>
> You must have started with AMOP by mistake.

What can I say? I'm easily confused. But Sonya hadn't written her
book when I first encountered Common LOOPS --- er, I mean CLOS --- and
LMI was pushing Object Lisp at the time.

Alexander Kjeldaas

unread,
Nov 3, 2005, 12:01:10 PM11/3/05
to
verec wrote:
> I'm again a bit confused. Basically, what I want to do, is to be
> able to define a single "function" name, reused (ie: "redefined")
> for various combinations of arguments such that I can:
>
> (draw conclusion)
> (draw bank-account)
> (draw shape)
>


Adding to what others have said, overloading in the C++ sense is
something that is always decidable at compile-time. In CL, this means
that DRAW would typically be a MACRO, not a generic function.

SETF is a macro that does various things based on what kind of PLACE it
is given. It is also extensible. If is possible to create a framework
for overloading ala SETF for DRAW by using some macrology, but you would
typically have to give a bit more information than what you give above
so that the correct draw is statically decidable.

For example: (draw (conclusion c)) where DRAW is a macro could "resolve"
to (DRAW-CONCLUSION C) while (draw (on table) (with pencil) (a picture))
could expand to (DRAW-GRAPHIC :TABLE TABLE :PENCIL PENCIL :A PICTURE).

You just have to provide a decent amount of macrology.

astor

John Thingstad

unread,
Nov 3, 2005, 12:54:15 PM11/3/05
to

CLOS defmehods are as definetive as C++. They are run at runtime.
SETF is a bit more complicated than what you are used too from c++.
Using defmaco requires a level of knowlege you don't have.
Putting it all into a email is futile and pointless..
I feel Peter Seiblel in his book http:/www.gigamonkeys.com/book/
describes the basic Lisp process fine. I would start there.
I am aware that you are a estabished programmer and that you
are working on a xword puzzle now. I have said before (and
will say again) learn your language. I say this from personal
experience. This is not a easy language to learn, but it is worth it.

Good luck!

John

verec

unread,
Nov 3, 2005, 8:40:28 PM11/3/05
to
On 2005-11-03 17:54:15 +0000, "John Thingstad" <john.th...@chello.no> said:

> On Thu, 03 Nov 2005 18:01:10 +0100, Alexander Kjeldaas
> <astor...@fast.no> wrote:
>
>> verec wrote:
>>> I'm again a bit confused. Basically, what I want to do, is to be
>>> able to define a single "function" name, reused (ie: "redefined")
>>> for various combinations of arguments such that I can:
>>> (draw conclusion)
>>> (draw bank-account)
>>> (draw shape)
>>>
>>
>>
>> Adding to what others have said, overloading in the C++ sense is
>> something that is always decidable at compile-time. In CL, this means
>> that DRAW would typically be a MACRO, not a generic function.

Yep. I had come to the same conclusion.

I have been starting along these lines (low level plumbing):
;;; poly is a simple struct whose only purpose is to serve as
;;; a seed for the defpoly (semic) macro to refer to the map that
;;; maps a symbol to lamda in a context free way. Such a context,
;;; precisely, is to be provided by further structs that :include
;;; poly.

(defstruct poly
(map (make-hash-table)))

(defun poly-locate (symbol poly)
"returns the lambda associated with symbol in poly, or nil"
(let ((map (poly-map poly)))
(gethash symbol map)))

(defun poly-bind (fn symbol poly)
"binds fn to symbol in the context of poly"
(let ((map (poly-map poly)))
(setf (gethash symbol map) fn)))

With the idea of a
(defmacro defpoly ...) coming to crown the whole thing.

But I must explore this a lot more. At the moment the path I'm
thinking of would involve macro-expansion twice, once when creating
the poly, and once when the resulting poly is itself used at call time, ie:

(defpoly locate (grid x y) ... ) ;; for the first macro use, and

(defun some-code ()
...
(locate grid 3 5)) ;; ``locate'' would be a macro here too

in other words, defpoly would be a macro generating a deferred macro...

>> SETF is a macro that does various things based on what kind of PLACE it
>> is given. It is also extensible. If is possible to create a
>> framework for overloading ala SETF for DRAW by using some macrology,
>> but you would typically have to give a bit more information than what
>> you give above so that the correct draw is statically decidable.
>>
>> For example: (draw (conclusion c)) where DRAW is a macro could
>> "resolve" to (DRAW-CONCLUSION C) while (draw (on table) (with pencil)
>> (a picture)) could expand to (DRAW-GRAPHIC :TABLE TABLE :PENCIL PENCIL
>> :A PICTURE).
>>
>> You just have to provide a decent amount of macrology.

This, I am afraid, you are right about! Where I equate "decent" with
non trivial and more than half a page of code :-(

> CLOS defmehods are as definetive as C++. They are run at runtime.
> SETF is a bit more complicated than what you are used too from c++.
> Using defmaco requires a level of knowlege you don't have.
> Putting it all into a email is futile and pointless..
> I feel Peter Seiblel in his book http:/www.gigamonkeys.com/book/
> describes the basic Lisp process fine. I would start there.

I've been on his site quite a few times already, and I wished there
was ... a volume two! :-)

> I am aware that you are a estabished programmer and that you
> are working on a xword puzzle now. I have said before (and
> will say again) learn your language. I say this from personal
> experience. This is not a easy language to learn, but it is worth it.

If I didn't beleive it was worth it, I wouldn't have started along
this path.

Regarding this "polysemic overloading" stuff, the more I think about
it, the more I'm convinced that this is doable ... and that I shouldn't
bother and go the full CLOS route instead.

I may carry on on this for a few days as a "learning exercise" in
"double prong macro hackery", but I don't intend to pursue it more
than that.

That said, between the CLOS OO way, on one hand, and the Schemish
functional way, on the other hand, what I've read about Lisp here
or there seemed to hint at yet another "thinking approach" which,
so far, still eludes me.

Many Thanks to all.

Thomas A. Russ

unread,
Nov 7, 2005, 3:34:04 PM11/7/05
to
Pascal Bourguignon <sp...@mouse-potato.com> writes:

>
> verec <ve...@mac.com> writes:
>
> > I'm again a bit confused. Basically, what I want to do, is to be
> > able to define a single "function" name, reused (ie: "redefined")
> > for various combinations of arguments such that I can:
> >
> > (draw conclusion)
> > (draw bank-account)
> > (draw shape)
>

> A misconception.
>
> All the methods of the same generic function must implement the same
> generic function, only for different type of arguments.
>
>
> Drawing a conclusion, drawing a bank account and drawing a shape are
> three totally different concepts, three different functions and should
> be named differently. At least, they cannot be methods to the same
> generic function.

I agree. The fact that these various different activities happen to use
the same English verb could be considered a "bug" in the English
language. A simple argument that these really are different concepts is
to note that if you choose your verb from languages other than English,
you would not end up using the same word for each of these verb senses.

So, it would be a good idea to not introduce the confusion present in
the use of multiple senses in natural language into your own interface
design. You should give each different sort of generic function its own
name.

Depending on other considerations, you could do this in Common Lisp by
using packages or by using different names inside a single package.

--
Thomas A. Russ, USC/Information Sciences Institute

verec

unread,
Nov 7, 2005, 5:46:05 PM11/7/05
to


"'When I use a word,' Humpty Dumpty said in rather a scornful tone, 'it
means just what I choose it to mean -- neither more nor less.'"
-- Lewis Carroll in Alice in Wonderland.

As a French-English bilingual, I'm quite aware of the differences in evocation
power of a given word depending on its surroundings, context, cultural
differences.

That's precisely why mathematicians have no problem assigning different
meanings
to the same word (or think of it: the same single letter!) depending on
the context.

For example, if you use the word "Liberty", which is extremely close in
meaning to its French counterpart "Liberté", I know that you are probably
willing to convey something a bit different to mere "freedom", for which
a Fench speaker would probably steer more towards "independance"

Next time you get a word "on the tip of your tongue" experience, you will
probably have to recognize that while you know full well the _idea_ that
you want to express, the word just escapes you. Which I take as a proof
that that ideas are "word-less", which in turn allows me to wholeheartedly
agree with Humpty Dumpty :-)

--
JFB ()

0 new messages