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.
DanL wrote: > 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.
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.
In article <c3ffc29a-f7f8-44bc-9f2e-bd53846b9...@d77g2000hsb.googlegroups.com>,
DanL <leidis...@gmail.com> wrote: > 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.
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
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.
> > 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.
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:
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.
> 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.
>> 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.
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.
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.
>> 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.
> DanL wrote: > > I have just been watchinghttp://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.
> 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.
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.)
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:
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-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.
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.
> 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.)
On 2008-07-22, John Thingstad <jpth...@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?
> On 2008-07-22, John Thingstad <jpth...@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.)
>> On 2008-07-22, John Thingstad <jpth...@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.
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.
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.
>>> On 2008-07-22, John Thingstad <jpth...@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.
> 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.
Thanks for the correction. That is kinda what I expected. Note that on my compiler
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
Kaz Kylheku <kkylh...@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."
Kent M Pitman wrote: > Kaz Kylheku <kkylh...@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."
John Thingstad wrote: > Pć Wed, 23 Jul 2008 00:56:23 +0200, skrev Kaz Kylheku <kkylh...@gmail.com>:
>> On 2008-07-22, John Thingstad <jpth...@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.)
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: _______________________
> 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.
>> 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.
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 :)
Kenny <kentil...@gmail.com> writes: > John Thingstad wrote: >> Pć Wed, 23 Jul 2008 00:56:23 +0200, skrev Kaz Kylheku <kkylh...@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!