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

Turn an ordinary function into a generic function

35 views
Skip to first unread message

DanL

unread,
Jul 20, 2008, 12:39:31 PM7/20/08
to
I have just been watching http://www.archive.org/details/DanielGB1987,
where at around 24:00 it is mentioned, that one can turn an ordinary
function into a generic one. ("... those ordinary functions become the
default method for the generic function.")

Well, I have tried that, and all I got was errors. The video is from
1987, so I suppose the mentioned functionality did not make it into
ANSI/X3.226-1994.

I am just curious if this works in ansi-cl.

Pascal Costanza

unread,
Jul 20, 2008, 12:51:46 PM7/20/08
to

No, it doesn't.

It is sometimes a good idea to be able to "protect" a function from
having methods defined on it. In Common Lisp, when you define a plain
function, users cannot add methods. That feature would have "destroyed"
that possibility (or would have caused hairy problems wrt defining when
it does and doesn't work).

Dylan doesn't make the distinction between "plain" functions and generic
functions, but instead provides "sealing", which allows you to protect a
generic function from user-defined methods. That is conceptually
cleaner, because it's more orthogonal than in Common Lisp.

Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/

Rainer Joswig

unread,
Jul 20, 2008, 12:53:50 PM7/20/08
to
In article
<c3ffc29a-f7f8-44bc...@d77g2000hsb.googlegroups.com>,
DanL <leid...@gmail.com> wrote:

LispWorks:

P100 30 > (defun foo (bar)
(baz bar))
FOO

P100 31 > (defmethod foo (bar)
(baz bar))

Error: FOO is defined as an ordinary function #<interpreted function FOO 40600051DC>
1 (continue) Discard existing definition and create generic function
2 (abort) Return to level 0.
3 Return to top loop level 0.

Type :b for backtrace, :c <option number> to proceed, or :? for other options

P100 32 : 1 > :c 1
#<STANDARD-METHOD FOO NIL (T) 40202D7333>

--
http://lispm.dyndns.org/

DanL

unread,
Jul 20, 2008, 1:00:48 PM7/20/08
to
On Jul 20, 6:51 pm, Pascal Costanza <p...@p-cos.net> wrote:

> > I am just curious if this works in ansi-cl.
>
> No, it doesn't.

> [...]

Ok, thanks for the clarification.

Cheers,

dhl


DanL

unread,
Jul 20, 2008, 1:13:57 PM7/20/08
to
On Jul 20, 6:53 pm, Rainer Joswig <jos...@lisp.de> wrote:

>   1 (continue) Discard existing definition and create generic function

That worked for me, too (OpenMCL, SBCL, Allegro), but the original
ordinary function is lost, instead of becoming the "fall-through", if
none of the generic functions methods matches.

Regards,

dhl

Kent M Pitman

unread,
Jul 20, 2008, 1:37:26 PM7/20/08
to
DanL <leid...@gmail.com> writes:

Yes, the reason for that is that it is that there isn't really a uniquely
determined, philosophically correct thing to do there.

Consider that DEFUN might mean "define a function that is total" or it might
mean "define a function that is the default". Suppose you think it means
"define a function that is the default". Then what does:

(defmethod foo ((x integer)) (1+ x))
(defun foo (x) x)
(foo 0)

return. If it returns 0, then DEFUN has overridden the definition given
in the DEFMETHOD. (In effect, in this model, DEFUN is more primitive than
DEFMETHOD and exists for the purpose of installing things in a cell, whereas
DEFMETHOD and DEFGENERIC are service operations on something installed in
the cell.) If it returns 1, then DEFUN has been a synonym for DEFMETHOD
with all T specializers. (In effect here, DEFUN is a macro capability layered
on lower level definitions presumably done by DEFGENERIC and/or DEFMETHOD
or things even more primitive.)

CL takes the positino that DEFUN can exist absent any CLOS stuff. This
position is, in part, historical and compatible with older code. But it
also makes sense to have a definer that can override a prior definition,
not just add to it. If DEFUN had the "softer" function you seem to want,
one could do the thing DEFUN does now with FMAKUNBOUND just before
a DEFMETHOD, but that would be a very low-level end-run around things
and I think would make more people unhappy.

It's easy enough to make a new package, shadow these symbols, and make them
do what you like given the existing primitives as underlying capability.

DanL

unread,
Jul 20, 2008, 3:21:57 PM7/20/08
to
On Jul 20, 7:37 pm, Kent M Pitman <pit...@nhplace.com> wrote:

> Suppose you think it means
> "define a function that is the default".  Then what does:
>
>  (defmethod foo ((x integer)) (1+ x))
>  (defun foo (x) x)
>  (foo 0)
>
> return.  If it returns 0, then DEFUN has overridden the definition given
> in the DEFMETHOD. (In effect, in this model, DEFUN is more primitive than
> DEFMETHOD and exists for the purpose of installing things in a cell, whereas
> DEFMETHOD and DEFGENERIC are service operations on something installed in
> the cell.)  If it returns 1, then DEFUN has been a synonym for DEFMETHOD
> with all T specializers. (In effect here, DEFUN is a macro capability layered
> on lower level definitions presumably done by DEFGENERIC and/or DEFMETHOD
> or things even more primitive.)

As I understood it, the latter should happen -- (defun x (y)) being
equivalent to (defmethod x (y)), if x is turned into a generic
function by defining a method on it. I am not sure, if the order in
which defun and defmethod take place matters, but I guess it does.
(e.g. If the defun in your example would have overwritten the generic
function. In the video, only defmethods on an existing function are
shown, not vice versa.)

~25:20

"Now what we've done is we've specialized it; we've made it a generic
function, so now we can incrementally extend [an ordinary function] by
adding new methods, and anything else will go through and go to this
default function."

> CL takes the positino that DEFUN can exist absent any CLOS stuff.  This
> position is, in part, historical and compatible with older code.  But it
> also makes sense to have a definer that can override a prior definition,
> not just add to it.  If DEFUN had the "softer" function you seem to want,
> one could do the thing DEFUN does now with FMAKUNBOUND just before
> a DEFMETHOD, but that would be a very low-level end-run around things
> and I think would make more people unhappy.

I do not know, if it would make more people unhappy, but I get your
point. What I saw in the video just made me curious, as I have not
heard about that "turning into a default" thing before.

> It's easy enough to make a new package, shadow these symbols, and make them
> do what you like given the existing primitives as underlying capability.

I agree.


Thank you very much for the elaborate explanation.


Cheers,

dhl

Pascal Costanza

unread,
Jul 20, 2008, 3:49:31 PM7/20/08
to
DanL wrote:
> On Jul 20, 7:37 pm, Kent M Pitman <pit...@nhplace.com> wrote:
>
>> Suppose you think it means
>> "define a function that is the default". Then what does:
>>
>> (defmethod foo ((x integer)) (1+ x))
>> (defun foo (x) x)
>> (foo 0)
>>
>> return. If it returns 0, then DEFUN has overridden the definition given
>> in the DEFMETHOD. (In effect, in this model, DEFUN is more primitive than
>> DEFMETHOD and exists for the purpose of installing things in a cell, whereas
>> DEFMETHOD and DEFGENERIC are service operations on something installed in
>> the cell.) If it returns 1, then DEFUN has been a synonym for DEFMETHOD
>> with all T specializers. (In effect here, DEFUN is a macro capability layered
>> on lower level definitions presumably done by DEFGENERIC and/or DEFMETHOD
>> or things even more primitive.)
>
> As I understood it, the latter should happen -- (defun x (y)) being
> equivalent to (defmethod x (y)), if x is turned into a generic
> function by defining a method on it. I am not sure, if the order in
> which defun and defmethod take place matters, but I guess it does.
> (e.g. If the defun in your example would have overwritten the generic
> function. In the video, only defmethods on an existing function are
> shown, not vice versa.)

There are the technical issues.

But there are also "semantic" issues: The view that you can get
extensibility of your code by simply turning plain functions into
generic functions is quite naive. It is rather the case that
extensibility must be designed well - you have to provide well-defined
hooks and protocols, especially when several functions have to cooperate
to achieve their goal.

Since you have to think about how you design extensibility into your
libraries anyway, you might as well make it explicit which functions are
generic and which aren't.

If you need more ad-hoc changes to functions for more pragmatic
purposes, so that you can fix things in the absence of a better designed
API, many Common Lisp implementations come with their own advice
functionality which you can use for this purpose and which typically
works for plain functions as well.

DanL

unread,
Jul 20, 2008, 4:07:29 PM7/20/08
to
On Jul 20, 9:49 pm, Pascal Costanza <p...@p-cos.net> wrote:

> If you need more ad-hoc changes to functions for more pragmatic
> purposes, so that you can fix things in the absence of a better designed
> API, many Common Lisp implementations come with their own advice
> functionality which you can use for this purpose and which typically
> works for plain functions as well.

Do you mean something akin to Emacs-Lisps defadvice? I have used this
in Emacs sometimes, but have not seen it in Common-Lisp code.

DanL

unread,
Jul 20, 2008, 5:24:59 PM7/20/08
to
On Jul 20, 10:07 pm, DanL <leidis...@gmail.com> wrote:

> Do you mean something akin to Emacs-Lisps defadvice? I have used this
> in Emacs sometimes, but have not seen it in Common-Lisp code.

Ok, Allegro provides this via DEFADVICE (deprecated) and DEF-FWRAPPER,
neither OpenMCL nor SBCL seem to support such a thing. (At least, I
have not found anything.) I will stick with standard CL and eschew
such highly implementation-dependent features.

Anyway, my question about defun/defmethod arouse out of curiousity,
after looking the video, not because I am actually missing something.

Thanks for the tip and sorry for double posting.

dhl

Pascal Costanza

unread,
Jul 21, 2008, 6:50:52 AM7/21/08
to
DanL wrote:
> On Jul 20, 10:07 pm, DanL <leidis...@gmail.com> wrote:
>
>> Do you mean something akin to Emacs-Lisps defadvice? I have used this
>> in Emacs sometimes, but have not seen it in Common-Lisp code.
>
> Ok, Allegro provides this via DEFADVICE (deprecated) and DEF-FWRAPPER,
> neither OpenMCL nor SBCL seem to support such a thing. (At least, I
> have not found anything.) I will stick with standard CL and eschew
> such highly implementation-dependent features.

There is also an advice facility in LispWorks.

Dan Weinreb

unread,
Jul 21, 2008, 9:32:02 AM7/21/08
to
On Jul 20, 12:51 pm, Pascal Costanza <p...@p-cos.net> wrote:
> DanL wrote:
> > I have just been watchinghttp://www.archive.org/details/DanielGB1987,

I was just recently thinking about this. I've been asked: "why do we
have single-quote when we could just use backquote?" and "why do we
have setq when we could just use setf?". In both cases, I don't think
there's any good answer other than back-compatibility and tradition.

Somewhat similarly, what if we made defun be a macro that turns into a
defmethod, with all the arguments given type "t"?

As you point out, without a "seal" provision, someone else could add
methods, thus changing the behavior of the function, unless you were
careful to give the function a "generic" contract in the first place.

My first thought was that it should be possible to solve this with
packages. Suppose I write a generic function in a package P, and
export it from P so that other packages can use it. Unfortunately
(for these purposes!), the method name is the same as the generic
function name, so it gets exported too.

On the other hand, your own methods might all be specialized on
classes whose name and implementation are internal to the module. (I
just wrote a module like this. It's a fifo queue. The exports are
the generic operations on a fifo queue, plus one factory function, and
the class names for the two (as it happens) implementations are
internal symbols.

Somebody could define new methods on the fifo operations, for a new
class. This would mean that they had defined a new implementation of
fifo. That's OK; it would not break anything.

You don't need "seal" since code outside the package cannot see the
class names. (Of course I am assuming no use of "::" or any other
snide things like that.)

Pascal Costanza

unread,
Jul 21, 2008, 10:00:03 AM7/21/08
to
Dan Weinreb wrote:

> I was just recently thinking about this. I've been asked: "why do we
> have single-quote when we could just use backquote?" and "why do we
> have setq when we could just use setf?". In both cases, I don't think
> there's any good answer other than back-compatibility and tradition.

For backquote, there is a very good answer: How would you get something
like `', to work otherwise?

setq and setf is a style preference. Yes, there is no good reason there.

> Somewhat similarly, what if we made defun be a macro that turns into a
> defmethod, with all the arguments given type "t"?
>
> As you point out, without a "seal" provision, someone else could add
> methods, thus changing the behavior of the function, unless you were
> careful to give the function a "generic" contract in the first place.
>
> My first thought was that it should be possible to solve this with
> packages. Suppose I write a generic function in a package P, and
> export it from P so that other packages can use it. Unfortunately
> (for these purposes!), the method name is the same as the generic
> function name, so it gets exported too.
>
> On the other hand, your own methods might all be specialized on
> classes whose name and implementation are internal to the module. (I
> just wrote a module like this. It's a fifo queue. The exports are
> the generic operations on a fifo queue, plus one factory function, and
> the class names for the two (as it happens) implementations are
> internal symbols.
>
> Somebody could define new methods on the fifo operations, for a new
> class. This would mean that they had defined a new implementation of
> fifo. That's OK; it would not break anything.
>
> You don't need "seal" since code outside the package cannot see the
> class names. (Of course I am assuming no use of "::" or any other
> snide things like that.)

Here is an example:

(defmethod read-one-byte (stream)
... do something low-level ...)

(defmethod read-n-bytes (stream n)
(loop repeat n collect (read-one-byte stream)))

Assume both are exported, so both are generic functions. Somebody
specializes read-one-byte, like this:

(defmethod read-one-byte :after ((stream my-stream))
(incf (read-counter stream)))

All is well and nice.

Next, the original implementor sees that there is an efficiency problem.
It's better to read bytes from buffers rather than read single bytes
from low level streams. So the following changes are made:

(defmethod read-one-byte (stream)
(car (read-n-bytes stream 1)))

(defmethod read-n-bytes (stream n)
... do something low level ...)

Now the extension for my-stream is broken. You don't get an early error
message, you just get weird read counters. This is the kind of bug which
is nasty to track down and which you want to avoid upfront as far as
possible.

Having the distinction between sealed and unsealed functions / "plain"
functions and generic functions gives me a handle to signal to a user
that specialization of a particular function is not a good idea.

Kaz Kylheku

unread,
Jul 21, 2008, 10:37:45 PM7/21/08
to
On 2008-07-21, Dan Weinreb <d...@alum.mit.edu> wrote:
> I was just recently thinking about this. I've been asked: "why do we
> have single-quote when we could just use backquote?"

Suppose we just had backquote and, moreover, suppose that we had
Scheme-like quasiquote syntax supporting backquote.

What if you wanted the following list to appear as a literal in your code:

((unquote x))

?

If you put (quasiquote ...) around the above, the unquote becomes live.

It is a property of that you can put QUOTE around any
expression and you know that everything inside it is then just data.

> and "why do we
> have setq when we could just use setf?"

That's different. SETQ, as a construct, is a special case of SETF.
You can replace SETQ with SETF in any correct expression without changing
its meaning.

But quote is not a special case of backquote as a construct. Only specific
instances of quote are special cases of backquote (i.e. such that the
quote could be replaced by backquote without changing meaning).

> In both cases, I don't think
> there's any good answer other than back-compatibility and tradition.
>
> Somewhat similarly, what if we made defun be a macro that turns into a
> defmethod, with all the arguments given type "t"?

Sometimes Lisp programmers work with functions specifically because
they want to be in that programming space.

> As you point out, without a "seal" provision, someone else could add
> methods, thus changing the behavior of the function, unless you were
> careful to give the function a "generic" contract in the first place.
> My first thought was that it should be possible to solve this with
> packages. Suppose I write a generic function in a package P, and
> export it from P so that other packages can use it. Unfortunately
> (for these purposes!), the method name is the same as the generic
> function name, so it gets exported too.

Methods don't have names. Only the generic function. Methods are
part of the satellite data of the generic function.

If you create a generic function, and define only one method
which specializes all specializable parameters to T, then it is effectively
a regular function, since there is no dispatch decision to make among
any methods.

It could well be implemented as such; that is to say, calling that function
should be just as cheap as calling a regular DEFUN.

So the answer is that if you want everything to be a method, then just
write methods.

John Thingstad

unread,
Jul 22, 2008, 4:17:00 AM7/22/08
to
>
> I was just recently thinking about this. I've been asked: "why do we
> have single-quote when we could just use backquote?" and "why do we
> have setq when we could just use setf?". In both cases, I don't think
> there's any good answer other than back-compatibility and tradition.
>

Well if you look at how Lisp is implemented setf just calls setq, rplaca,
rplacd etc. behind the scenes.
I guess the trick is to know they are there but use (setf (cdr list) val)
instead of (rplacd list val) for readabillity.
Remember setf was originally added to the language to support CLOS class
assignement but soon was found to be so powerfull it took over.
So see it this way. Lisp exposes it's innards. They have to be there but
you don't usually have to use them directly.
When was the last time you used tagbody and go for instance? Yet they form
the foundation of every loop structure.

>
> You don't need "seal" since code outside the package cannot see the
> class names. (Of course I am assuming no use of "::" or any other
> snide things like that.)

Always a dangerous assumption :)

--------------
John Thingstad

Kaz Kylheku

unread,
Jul 22, 2008, 6:56:23 PM7/22/08
to
On 2008-07-22, John Thingstad <jpt...@online.no> wrote:
>>
>> I was just recently thinking about this. I've been asked: "why do we
>> have single-quote when we could just use backquote?" and "why do we
>> have setq when we could just use setf?". In both cases, I don't think
>> there's any good answer other than back-compatibility and tradition.
>>
>
> Well if you look at how Lisp is implemented setf just calls setq, rplaca,
> rplacd etc. behind the scenes.

Neither SETQ or nor SETF is primitive with respect to the other. It's
not the case that SETF detects assignment to a symbol, which it delegates to
SETQ.

Both SETQ and SETF have to work across symbol macros. They both have expand
the symbol macro and then recursively deal with assignment to the resulting
expression.

> When was the last time you used tagbody and go for instance?

Last week.

John Thingstad

unread,
Jul 22, 2008, 7:21:37 PM7/22/08
to
På Wed, 23 Jul 2008 00:56:23 +0200, skrev Kaz Kylheku <kkyl...@gmail.com>:

> On 2008-07-22, John Thingstad <jpt...@online.no> wrote:
>>>
>>> I was just recently thinking about this. I've been asked: "why do we
>>> have single-quote when we could just use backquote?" and "why do we
>>> have setq when we could just use setf?". In both cases, I don't think
>>> there's any good answer other than back-compatibility and tradition.
>>>
>>
>> Well if you look at how Lisp is implemented setf just calls setq,
>> rplaca,
>> rplacd etc. behind the scenes.
>
> Neither SETQ or nor SETF is primitive with respect to the other. It's
> not the case that SETF detects assignment to a symbol, which it
> delegates to
> SETQ.

oh no! Lets see.

(defvar *a* 5)

(setf *a* 6)

=> (LET* ((#:G685 6)) (SETQ *A* #:G685))

Of cource you are right that setq is no longer primitive. So this is
implementation dependent.
(This is what LispWorks does.)

--------------
John Thingstad

Pascal J. Bourguignon

unread,
Jul 22, 2008, 7:33:42 PM7/22/08
to
"John Thingstad" <jpt...@online.no> writes:

SETQ is a Special Operator.
SETF is a Macro.

Minimal compilation shall expand all macros and symbol-macros: it will
remain only SETQ (with no symbol-macro). So that
post-minimal-compilation SETQ is primitive.

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

COMPONENT EQUIVALENCY NOTICE: The subatomic particles (electrons,
protons, etc.) comprising this product are exactly the same in every
measurable respect as those used in the products of other
manufacturers, and no claim to the contrary may legitimately be
expressed or implied.

John Thingstad

unread,
Jul 22, 2008, 8:22:00 PM7/22/08
to
På Wed, 23 Jul 2008 01:33:42 +0200, skrev Pascal J. Bourguignon
<p...@informatimago.com>:

Thanks for the correction. That is kinda what I expected.
Note that on my compiler

(setf (cdr *a*) (list 'c))
=> (LET* ((#:G1143 *A*) (#:G1142 (LIST 'C))) (SYSTEM::%RPLACD #:G1143
#:G1142))

Which I expect is a version of RPLACD without checks. Thus even though
replacing it with RPLACD would work the compiler is not required to do
this.

Simulularly
(setf (elt *a* 1) (list 'c))
=> (LET* ((#:G1146 *A*) (#:G1145 1) (#:G1144 (LIST 'C))) (SYSTEM::SET-ELT
#:G1146 #:G1145 #:G1144))

So clearly in the interest of increasing performance compiler writers have
taken some liberties and added some functions of their own.
Still the initial analysis seems essentially correct in that the original
implementation of setf followed along the line I suggested.
--------------
John Thingstad

Kent M Pitman

unread,
Jul 22, 2008, 9:37:04 PM7/22/08
to
Kaz Kylheku <kkyl...@gmail.com> writes:

> > When was the last time you used tagbody and go for instance?
>
> Last week.

And for those who think they didn't just use it last week, or even
today, think again: Just because something is used only inside a macro
doesn't mean it doesn't get used. It gets used a LOT, it's just that
it's mostly useful in implementing other more structured abstractions.

To quote "Madge" from an old Palmolive commercial, "you're soaking in it."

Kenny

unread,
Jul 22, 2008, 10:48:06 PM7/22/08
to

Just when I was losing hope for this ng.

kt

Kenny

unread,
Jul 22, 2008, 11:05:21 PM7/22/08
to

That is what AllegroCL does, too, altho inexplicably it offers #:G919
instead of #:G685.

Reminds me of a funny debate I had with another engineer over whether
let* or let was correct when only one binding was in play. let* always
struck me as the special case, where I cared what other bindings came
first. statistically true, I am sure. But this macroexpansion pattern
suggests (and now that I think on it, yeah) that let is implemented via
let*, which could be construed for that as the one to use when multiples
do not enter into it.

But still... how would you vote?

1. (let ((x 42)) ...) or (let* ((x 42))..)?
2. Which do you actually code?
3. If 1 and 2 differ: _______________________

kxo

John Thingstad

unread,
Jul 22, 2008, 11:17:45 PM7/22/08
to
På Wed, 23 Jul 2008 05:05:21 +0200, skrev Kenny <kent...@gmail.com>:

>
> Reminds me of a funny debate I had with another engineer over whether
> let* or let was correct when only one binding was in play. let* always
> struck me as the special case, where I cared what other bindings came
> first. statistically true, I am sure. But this macroexpansion pattern
> suggests (and now that I think on it, yeah) that let is implemented via
> let*, which could be construed for that as the one to use when multiples
> do not enter into it.
>
> But still... how would you vote?
>
> 1. (let ((x 42)) ...) or (let* ((x 42))..)?
> 2. Which do you actually code?
> 3. If 1 and 2 differ: _______________________
>
> kxo

Indeed. Lisp is unusual in that paralell bining is the rule rather than
the exception.
Since the computer will do things in order it makes sense to implement let
as let*.
That said 'let' is a special form not a macro so I don't think you could
argue one is more 'primitive' than the other.

--------------
John Thingstad

Leandro Rios

unread,
Jul 22, 2008, 11:57:52 PM7/22/08
to
John Thingstad escribió:

It is easy to implement let* in terms of let:

(let ((var1 1))
(let ((var2 (+ var1 2)))
(values var1 var2)))

But I don't see how to implement let except by means of lambda. If it is
so, I would say that let is more "primitive" than let*.
I always use let, except when I need sequential binding (saves one
keystroke :)

Leandro

Pascal J. Bourguignon

unread,
Jul 23, 2008, 2:18:04 AM7/23/08
to
Kenny <kent...@gmail.com> writes:

> John Thingstad wrote:
>> På Wed, 23 Jul 2008 00:56:23 +0200, skrev Kaz Kylheku <kkyl...@gmail.com>:
>> => (LET* ((#:G685 6)) (SETQ *A* #:G685))
>> Of cource you are right that setq is no longer primitive. So this is
>> implementation dependent.
>> (This is what LispWorks does.)
>
> That is what AllegroCL does, too, altho inexplicably it offers #:G919
> instead of #:G685.

Yes, that must be yet annoter under-specified,
implementation-dependant area of Common Lisp. One wonder how we can
even think of writing portable programs with such divergences.

> Reminds me of a funny debate I had with another engineer over whether
> let* or let was correct when only one binding was in play. let* always
> struck me as the special case, where I cared what other bindings came
> first. statistically true, I am sure. But this macroexpansion pattern
> suggests (and now that I think on it, yeah) that let is implemented
> via let*, which could be construed for that as the one to use when
> multiples do not enter into it.

CL is multi-core ready. Just use a compiler that compute the bindings
of LET effectively in parallel.

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

I need a new toy.
Tail of black dog keeps good time.
Pounce! Good dog! Good dog!

Kent M Pitman

unread,
Jul 25, 2008, 7:33:18 PM7/25/08
to
p...@informatimago.com (Pascal J. Bourguignon) writes:

> Kenny <kent...@gmail.com> writes:
> ...


> > Reminds me of a funny debate I had with another engineer over whether
> > let* or let was correct when only one binding was in play. let* always
> > struck me as the special case, where I cared what other bindings came
> > first. statistically true, I am sure. But this macroexpansion pattern
> > suggests (and now that I think on it, yeah) that let is implemented
> > via let*, which could be construed for that as the one to use when
> > multiples do not enter into it.
>
> CL is multi-core ready. Just use a compiler that compute the bindings
> of LET effectively in parallel.

Hopefully you're just kidding.

(let ((x (read)) (y (read)))
(f x y))

happens in a very well-defined order and cannot be parallelized.

Doing a parallel Lisp is really a different endeavor entirely and
cannot be snuck in without telling people.

The only part that is "parallel" is not the evaluation of the
variable initializations, it is putting the bindings in place.
The meaning is the same as:

(let ((#1=#:exp1 (read)))
(let ((#2=#:exp2 (read)))
((lambda (x y) (f x y)) #1# #2#)))

So I guess if you want to write that as a LET* you could. Giving
some serious credence to Kenny's query about which is more primitive.

(let* ((#1=#:exp1 (read))
(#2=#:exp2 (read))
(x #1#)
(y #2#))
(f x y))

Then again, you don't really need the call to LET* at all, since
(f (read) (read))
is equally well-defined, and one could argue still even more primitive.

Dan Weinreb

unread,
Jul 26, 2008, 3:28:34 AM7/26/08
to

This is an excellent example, but I think it's an example of a
different thing: an unclear contract between the base class and
extenders of the class. The original read-one-byte :after method only
works if the original guy is promising that every read of a byte will
call that method. You can't go around adding to an existing class by
peering into its implementation and just assuming that you can depend
on everything you see therein.

Developing a good methodology for writing contracts between class
writers and class extenders is a problem that needs work.

-- Dan

Dan Weinreb

unread,
Jul 26, 2008, 3:33:23 AM7/26/08
to
On Jul 22, 4:17 am, "John Thingstad" <jpth...@online.no> wrote:

> Remember setf was originally added to the language to support CLOS class  

> assignment

Actually, setf came before CLOS, and before Flavors. Its original
purpose was to avoid the need to come up with separate names for
getters and setters of defstruct's. Since defstruct had the ability
to make structures that were implemented various ways, such as lists
or arrays, the solution had to work on both of those. Then, it became
apparent that setf could be generalized and used for lots of things.
Its big advantage is that you don't have to learn a whole second set
of names of "setter" functions like rplacd, aset, or whatever.

The question of why we retain "setq" as a visible Lisp function now
that we have "setf" can be considered without reference to the
question of how either of them is implemented.

Anyway, I just brought that up as an analogy to lead into the question
I really wanted to ask about defun and defmethod...

Dan Weinreb

unread,
Jul 26, 2008, 3:39:58 AM7/26/08
to
On Jul 21, 10:37 pm, Kaz Kylheku <kkylh...@gmail.com> wrote:

> > My first thought was that it should be possible to solve this with
> > packages.  Suppose I write a generic function in a package P, and
> > export it from P so that other packages can use it.  Unfortunately
> > (for these purposes!), the method name is the same as the generic
> > function name, so it gets exported too.
>
> Methods don't have names. Only the generic function. Methods are
> part of the satellite data of the generic function.

Oh, do I have to spell it out formally? The problem is that if I
write a generic function named G in package P, and I export it from P
so that functions in other packages can call it without resorting to
":use" or "::", then someone not authorized to change things in my
package can nevertheless write a defmethod for function G, because the
defmethod special form uses that same symbol, G, and therefore the
unauthorized person isn't kept from writing the defmethod simply by
virtue of the use of packages in this way. OK?


>
> If you create a generic function, and define only one method
> which specializes all specializable parameters to T, then it is effectively
> a regular function, since there is no dispatch decision to make among
> any methods.

Yes, that's what I was saying.

>
> It could well be implemented as such; that is to say, calling that function
> should be just as cheap as calling a regular DEFUN.

Yes, ideally a CLOS implementation should have that property.

>
> So the answer is that if you want everything to be a method, then just
> write methods.

But the question is, while we're at it, could we just get rid of defun
entirely, or make it a macro that turns (defun foo (a b) ...) into
(defmethod foo ((a t) (b t)) ...)? If we could, then we'd be removing
one major underlying concept from the core language, without actually
losing any functionality. That means it would make Common Lisp
conceptually simpler. If we ever managed to define Common Lisp as a
"core" plus macros, there would be less in the "core". That's the
hope.

(By the way, here's a little flaw I thought of: the defmethod
implicitly declares all of its required arguments "ignorable" on the
ground that they are never "unused" because they were used to look up
the method. At work, we recently had to fix up some complex macrology
in order to get the proper "argument X was unused" warnings from the
compiler when they are appropriate.)


Dan Weinreb

unread,
Jul 26, 2008, 3:45:03 AM7/26/08
to
On Jul 22, 7:33 pm, p...@informatimago.com (Pascal J. Bourguignon)
wrote:

>
> SETQ is a Special Operator.
> SETF is a Macro.

In my opinion, it would be nice to have, in a sense, two definitions
of Common Lisp.

For people who are "just programming", there's no reason to know the
distinction between symbols that are special operators and symbols
that are macros. The only thing they care about is what it is defined
to do. If dolist is implemented by expanding into loop, who cares? It
does what it does, and that's all that matters, not HOW it works
internally.

The second definition would express Common Lisp as a "core", kept as
small as possible, plus a bunch of code written in the core. In this
definition, it would be very clear what was implemented in terms of
what. This could serve as a "reference implementation", and as a way
of reasoning about properties of Common Lisp.

(Or any Lisp dialect.)

Dan Weinreb

unread,
Jul 26, 2008, 3:47:06 AM7/26/08
to
On Jul 22, 11:05 pm, Kenny <kentil...@gmail.com> wrote:
> John Thingstad wrote:

> But still... how would you vote?
>
> 1. (let ((x 42)) ...) or (let* ((x 42))..)?
> 2. Which do you actually code?
> 3. If 1 and 2 differ: _______________________

I use "let" in such situations. NOT because of how let is
implemented; that makes no difference to me.

I guess I do it because "let" has a shorter name, and possibly also
because I am old enough to have learned Lisp during a period when we
had "let" but did not yet have "let*".

Dan Weinreb

unread,
Jul 26, 2008, 4:00:48 AM7/26/08
to
On Jul 20, 3:49 pm, Pascal Costanza <p...@p-cos.net> wrote:

>
> Since you have to think about how you design extensibility into your
> libraries anyway, you might as well make it explicit which functions are
> generic and which aren't.

> Pascal

This goes to the heart of what I asked in my first post on this
thread, about whether it might make sense to try to declare "defun" to
be an obsolete special case and just replace it with defgeneric/
defmethod.

Suppose I am writing a library. It lives in a package and exports
symbols, most of which are functions that I am offering to the caller.

First, let's assume that the only way that clients of my package use
it is to call these entrypoint functions. In that case, why should I
externally advertise whether one of these entrypoints is a generic
function or a non-generic function? That's just an implementation
detail: did I write a defun with a typecase on the first argument, or
did I use CLOS to do that dispatching? It's no business of the
caller. I think I'm on pretty firm ground here, but I'd like to hear
your opinion.

Such a contract might not even reveal the names of any class at all.
I just wrote one of these. It exports a type called 'fifo:fifo', a
function called "fifo:make-fifo', and a bunch of functions called
things like 'fifo:insert' and 'fifo:length'. Based on the arguments
that make-fifo gets, where you say things like how large you think the
fifo might get, make-fifo makes a decision about which of two classes
to use. The two classes (which both don't inherit from anything) have
two different implementations of a fifo. The caller knows nothing
about which class he is given. The type 'fifo' works, but if you
looked under the covers at the internal implementation details, you'd
find that it was a deftype with an "or" on the actual implementation
classes.

Second, suppose the more general case, where I am advertising to my
clients that they can not only call the functions, but define their
own specializations of the functions on their own classes, or define
their own :after methods on my own classes. That's very different.
As was pointed out earlier in the thread, with the read-a-character
example, defining a clean, modular contract that allows this kind of
thing is hard. I think it's hard, and I'm quite sure that hardly
anybody even tries, even though they really ought to.

Thomas F. Burdick

unread,
Jul 26, 2008, 4:22:15 AM7/26/08
to
On Jul 26, 9:39 am, Dan Weinreb <d...@alum.mit.edu> wrote:

> (By the way, here's a little flaw I thought of: the defmethod
> implicitly declares all of its required arguments "ignorable" on the
> ground that they are never "unused" because they were used to look up
> the method.  At work, we recently had to fix up some complex macrology
> in order to get the proper "argument X was unused" warnings from the
> compiler when they are appropriate.)

Is this a shortcomming in CLOS or in PCL? I don't have the heart to
try to muddle through the spec to figure out if CLOS actually requires
that specialized parameters be considered as used, but I would hope
not. I'm completely in agreement with you though, that in practice
this is really annoying and misses some of the useful static checks
that lisp compilers can give you.

Chris Russell

unread,
Jul 26, 2008, 9:55:36 AM7/26/08
to
On 23 Jul, 04:57, Leandro Rios <leandroprograma...@gmail.com> wrote:
> It is easy to implement let* in terms of let:
>
> (let ((var1 1))
>    (let ((var2 (+ var1 2)))
>      (values var1 var2)))      
>
> But I don't see how to implement let except by means of lambda. If it is
> so, I would say that let is more "primitive" than let*.
> I always use let, except when I need sequential binding (saves one
> keystroke :)
>
> Leandro

(let ((a expa)(b expb)..)..) is equivalent to

(let* ((gensyma expa) (gensymb expb)..)
(let*((a gensyma) (b gensymb)..)..)

where gensym_ is an appropriate unique name.

DanL

unread,
Jul 27, 2008, 8:24:38 PM7/27/08
to
On Jul 21, 12:50 pm, Pascal Costanza <p...@p-cos.net> wrote:

> DanL wrote:

> > neither OpenMCL nor SBCL seem to support such a thing. (At least, I
> > have not found anything.) I will stick with standard CL and eschew
> > such highly implementation-dependent features.
>
> There is also an advice facility in LispWorks.

I have to correct myself: OpenMCL actually provides ADVISE and
UNADVISE macros. (Which I find quite useful for debugging puroposes,
btw.)


dhl

Robert Uhl

unread,
Jul 30, 2008, 2:40:29 PM7/30/08
to
DanL <leid...@gmail.com> writes:
>
> Ok, Allegro provides this via DEFADVICE (deprecated) and DEF-FWRAPPER,
> neither OpenMCL nor SBCL seem to support such a thing. (At least, I
> have not found anything.) I will stick with standard CL and eschew
> such highly implementation-dependent features.

You could implement your own DEFADVICE pretty easily:

(defmacro defadvice ((function type) &body body)
(let ((func-name (gensym)))
`(let ((,func-name (symbol-function ',function)))
(setf (symbol-function ',function)
(lambda (&rest args)
,(cond
((eq type :before)
`(progn
,@body
(apply ,func-name args)))
((eq type :after)
`(progn
(apply ,func-name args)
,@body))))))))

There's no error checking, and I didn't bother implementing :around, and
there's no REMOVE-ADVICE or anything like that, but that's a basic
skeleton. A better DEFADVICE would set a symbol property on the
function to indicate that it had been advised and to store the original
function, but this is good enough for government work.

--
Robert Uhl <http://public.xdi.org/=ruhl>
Architects cannot learn to design grand cathedrals if they are taught all their
drawing courses using only an Etch-a-Sketch because the company struck a deal
with the university... --Gene Spafford

Pascal Costanza

unread,
Jul 30, 2008, 3:40:41 PM7/30/08
to

A major problem of such an approach is that it doesn't work well with
inlined functions.

Robert Uhl

unread,
Jul 31, 2008, 10:32:53 AM7/31/08
to
Pascal Costanza <p...@p-cos.net> writes:
>
> > [snip hand-rolled DEFADVICE]

>
> A major problem of such an approach is that it doesn't work well with
> inlined functions.

Very true. Maybe a wrapper on DEFUN which does a quick check for advice
at the beginning of running a function would work? But then DEFADVICE
would only work on newly-defined functions.

I guess one could combine DEFADVICE and a DEFUN wrapper; with sufficient
smarts it might be workable.

If not that, I don't think it's doable without internals knowledge.

This is why one carries the regulation Leatherman tool, Gerber tool, or Swiss
Army knife at _all_ times. You never know when you will have an emergency
that requires you to drink a beer immediately. --Matt Roberds

0 new messages