On Tue, 18 Mar 2008 12:36:47 +0100, Pascal Costanza pc@p-cos.net wrote:
...but that's ambiguous:
Only if you insist on having a short form without parentheses. That's not a hard-and-fast requirement.
(case (thing :test #'=) (42 'foo) (4711 'bar))
What's the result of that form?
Error: The variable THING is unbound.
On 18 Mar 2008, at 12:52, Edi Weitz wrote:
On Tue, 18 Mar 2008 12:36:47 +0100, Pascal Costanza pc@p-cos.net wrote:
...but that's ambiguous:
Only if you insist on having a short form without parentheses. That's not a hard-and-fast requirement.
What about backwards compatibility?
Or to put it differently: Are we talking about an extension of cl:case, or a new case that's different from cl:case?
(case (thing :test #'=) (42 'foo) (4711 'bar))
What's the result of that form?
Error: The variable THING is unbound.
There was a binding for a function and a variable thing in my example.
cl:case would interpret the second form as a call of the function thing, and that should remain so for backwards compatibility.
Pascal
On 18 Mar 2008, at 13:46, Pascal Costanza wrote:
On 18 Mar 2008, at 12:52, Edi Weitz wrote:
On Tue, 18 Mar 2008 12:36:47 +0100, Pascal Costanza pc@p-cos.net wrote:
...but that's ambiguous:
Only if you insist on having a short form without parentheses. That's not a hard-and-fast requirement.
What about backwards compatibility?
Or to put it differently: Are we talking about an extension of cl:case, or a new case that's different from cl:case?
(case (thing :test #'=) (42 'foo) (4711 'bar))
What's the result of that form?
Error: The variable THING is unbound.
There was a binding for a function and a variable thing in my example.
cl:case would interpret the second form as a call of the function thing, and that should remain so for backwards compatibility.
BTW, even if we are talking about a new my-case, it may be a good idea to remain backwards compatible to ease 'refactoring' between cl:case and my-case. It would be an unnecessary source of bugs if you had to add or remove parentheses in the first argument when you want to go from one operator to the other. These are things that are easily forgotten, especially if something looks otherwise innocuous.
Pascal
On Tue, 18 Mar 2008 13:50:28 +0100, Pascal Costanza pc@p-cos.net wrote:
BTW, even if we are talking about a new my-case, it may be a good idea to remain backwards compatible to ease 'refactoring' between cl:case and my-case. It would be an unnecessary source of bugs if you had to add or remove parentheses in the first argument when you want to go from one operator to the other. These are things that are easily forgotten, especially if something looks otherwise innocuous.
Hmm, yes, I tend to agree with this.
On Tue, 18 Mar 2008 13:46:14 +0100, Pascal Costanza pc@p-cos.net wrote:
Or to put it differently: Are we talking about an extension of cl:case, or a new case that's different from cl:case?
I thought the latter. The former doesn't seem like a reasonable CDR to me. But, hey, I'm just trying to give feedback... :)
There was a binding for a function and a variable thing in my example.
Ah, sorry, I missed the variable binding.
cl:case would interpret the second form as a call of the function thing, and that should remain so for backwards compatibility.
See above. I would think that the chances of vendors actually changing CL:CASE proper are pretty slim.
See above. I would think that the chances of vendors actually changing CL:CASE proper are pretty slim.
I'm all for extending CL:CASE in a backwards-compatible way. Why would that be a problem for CL implementors? Extending the macro in a backwards-compatible way doesn't look any different to me from adding a new function.
Leslie
On Tue, 18 Mar 2008 14:49:19 +0100 (CET), "Leslie P. Polzer" leslie.polzer@gmx.net wrote:
I'm all for extending CL:CASE in a backwards-compatible way. Why would that be a problem for CL implementors?
It wouldn't be ANSI-compliant anymore.
Am 18.03.2008 um 15:08 schrieb Edi Weitz:
On Tue, 18 Mar 2008 14:49:19 +0100 (CET), "Leslie P. Polzer" <leslie.polzer@gmx.net
wrote:
I'm all for extending CL:CASE in a backwards-compatible way. Why would that be a problem for CL implementors?
It wouldn't be ANSI-compliant anymore.
Also, changes in implementations have been known to contain bugs, hence by forcing the changes to be to cl:case, we are going to potentially affect existing code bases, for no discernible gain. Given the sizable code bases out there, the only circumstances where I find it acceptable to mess with the COMMON-LISP package (or other packages or behaviours mandated by ANSI) is when there is no reasonable way of achieving the intended goal without doing so. In this case I can see no downsides to placing the extended case (or select, or what have you) symbol in a different package. Indeed this will aid adoption, since it makes it easier to provide this CDR as a user-maintained library for starters, with implementations still having the ability to optimize the implementation if enough users see the benefit of this (and personally I'd think that most useful optimizations can actually be achieved through user code as well).
Which brings me to another question I've been meaning to bring up w.r.t. the latest CDRs: Would it be sensible to have a defined package for these kinds of smallish extensions (like e.g. the index types, as well), maybe cdr-cl or ext-cl, or whatever? Has this been discussed already?
Regs, Pierre.
Also, changes in implementations have been known to contain bugs, hence by forcing the changes to be to cl:case, we are going to potentially affect existing code bases, for no discernible gain.
That's why regression tests exist...
Which brings me to another question I've been meaning to bring up w.r.t. the latest CDRs: Would it be sensible to have a defined package for these kinds of smallish extensions (like e.g. the index types, as well), maybe cdr-cl or ext-cl, or whatever? Has this been discussed already?
Sounds sensible to me, yes.
Leslie
On 18 Mar 2008, at 15:39, Leslie P. Polzer wrote:
Also, changes in implementations have been known to contain bugs, hence by forcing the changes to be to cl:case, we are going to potentially affect existing code bases, for no discernible gain.
That's why regression tests exist...
The advantage of not requiring cl:case to change would be that you could add this CDR as a plain library, which if you define as a change of cl:case itself, you would have to wait for implementors to "catch up."
My suggestion would be to keep this open, or specify it in such a way that both options are possible. (It could be cl-ext:case, which you could then shadow-import, but where an implementor could easily support it directly as well.)
Pascal
"Pierre R. Mai" writes:
Which brings me to another question I've been meaning to bring up w.r.t. the latest CDRs: Would it be sensible to have a defined package for these kinds of smallish extensions (like e.g. the index types, as well), maybe cdr-cl or ext-cl, or whatever? Has this been discussed already?
I don't think this has been discussed, but I could be wrong.
Although it's undesirable to require a separate package for every tiny API, I think that in general there are drawbacks to specifying package names as part of interfaces (as opposed to implementations of interfaces). My main concern is that you can sometimes want two or more libraries that implement the same interface loaded into one Lisp image. You can do this pretty easily if interfaces don't specify the package namespace, but less easily or not at all if package names are part of interfaces: if all implementors of some interface are required to associate their code with the same symbols in the Lisp image, there'll be conflicts. Possibly the conflicts won't matter much, but if the different implementations have incompatible bugs or extensions, the conflicts can be fairly frustrating; in order to debug, you'll need to know which implementation you compiled against, which may be different than the debug-time definitions, and so forth. So my preference would be to keep package names out of CDR document interfaces per se, and to leave it to library authors and users to construct package namespaces as they see fit.
There are a number of ways that users can get footholds on things, even if CDR documents leave package names unspecified:
* A user who wants to depend on a particular library's implementation of some interface can just employ that library's package name(s), either by USE-PACKAGE, selective importing, package-qualified symbols in the client's source code, etc. This is probably the easiest thing to do, and it's basically how people already use libraries.
* A user who wants a layer of package namespace indirection between different libraries' implementations of an interface can programmatically construct a package containing the symbols in the interface. Something like this might suffice:
(defun make-api-package (new-package-name string-designator from-package) (let ((new-package (make-package new-package-name))) (dolist (string-designator string-designators new-package) (import (find-symbol string-designator from-package) new-package) (export (find-symbol string-designator new-package) new-package))))
* An author of library providing an interface might furnish an operator that "installs" the symbols in an interface into some package (this is analogous to what the SERIES system does). For example, a library that provides a couple of CDR documents' interfaces might have an INSTALL function defined like this:
(in-package "WHIZ-BANG-LIBRARY")
(defvar *cdr-apis* '((:cdr-42 . (frob munge)) (:cdr-100 . (mangle hose))))
(defun install (api &optional (package *package*)) (dolist (symbol (cdr (assoc api *cdr-apis* :test 'string= #| or STRING-EQUAL? |#))) (shadowing-import symbol package)))
While I admit that having to do some amount of namespace bookkeeping can be annoying, ISTM to be a tradeoff that buys the user flexibility in how he can employ the package namespace in his Lisp image.
-- Richard
Richard M Kreuter writes:
"Pierre R. Mai" writes:
Which brings me to another question I've been meaning to bring up w.r.t. the latest CDRs: Would it be sensible to have a defined package for these kinds of smallish extensions (like e.g. the index types, as well), maybe cdr-cl or ext-cl, or whatever? Has this been discussed already?
I don't think this has been discussed, but I could be wrong.
Although it's undesirable to require a separate package for every tiny API, I think that in general there are drawbacks to specifying package names as part of interfaces (as opposed to implementations of interfaces).
So if I understood you correctly, you're advocating that CDR documents specify interfaces, and---in the same spirit as the MOP---packaging is an implementation detail. To portably make use of such an interface, it's necessary to rely on a portability-library like SWANK-MOP or CLOSER-MOP (which you may have to do /anyway/ due to buggy/incomplete implementations from vendors.) Does this summarize your point fairly?
For the contrary opinion that a CDR should specify a package, notice that you can leave the question of having one package per CDR, or a single package for possibly several CDRs open by specifying that
"Symbols FOO, BAR, QUUX are exported from a package named CDR-N."
This makes it possible for implementations to collect symbols of several CDRs in one package as long as this package has nicknames CDR-X, CDR-N, CDR-Y (as long as symbols don't collide.)
Programs can rely on (:import-from "CDR-N" "FOO" "BAR" "QUUX") to work portably.
-T.
"Tobias C. Rittweiler" writes:
Richard M Kreuter writes:
Although it's undesirable to require a separate package for every tiny API, I think that in general there are drawbacks to specifying package names as part of interfaces (as opposed to implementations of interfaces).
So if I understood you correctly, you're advocating that CDR documents specify interfaces, and---in the same spirit as the MOP---packaging is an implementation detail.
I agree up to this point.
To portably make use of such an interface, it's necessary to rely on a portability-library like SWANK-MOP or CLOSER-MOP (which you may have to do /anyway/ due to buggy/incomplete implementations from vendors.) Does this summarize your point fairly?
I don't agree that leaving packages out of interface specifications is what leads people to write compatibility libraries: compatibility libraries sometimes smooth out differences among implementations of interfaces, sometimes fix or hide bugs among implementations, sometimes target lowest-common-denominators of functionality for the purpose of being a lower bound for portability. For the MOP, if the only differences among MOP implementations were the namespacing, all you'd need in a MOP compatibility library would be a trivial script to build a package that imported and exported the right symbols. In fact, the differences among the CL implementors' MOPs are not so trivial, and the compatibility libraries must therefore do more than merely setting up some packages. (The same is true of Gray Streams implementations, IIRC.)
For the contrary opinion that a CDR should specify a package, notice that you can leave the question of having one package per CDR, or a single package for possibly several CDRs open by specifying that
"Symbols FOO, BAR, QUUX are exported from a package named CDR-N."
This makes it possible for implementations to collect symbols of several CDRs in one package as long as this package has nicknames CDR-X, CDR-N, CDR-Y (as long as symbols don't collide.)
You could specify interfaces this way, but then the user can't straightforwardly load more than one library that implements such an API, because the two libraries will collide in the package namespace.
For the case-with-test operator that people have been discussing, some folks have brought up the idea of having a portable implementation of whatever spec they come up with, and maybe eventually asking CL implementors to provide an optimized version, where possible. If the interface specification for case-with-test says that the operator must be available in some package by name, then a library that purports to conform to that interface will conflict with an implementation that purports to conform to the same interface, since they'll both be trying to set the symbol-function on the same symbol. Of course this can be worked around, e.g., a library that normally provides the operator might not define it when loading on an implementation that already defines the operator, but then users who'd prefer to use that library's implementation of the operator (say, because the library extends it, or has some flaw the user relies on) won't be able to do so on that implementation.
-- Richard
Q.E.D.
The worms are squirming around. :)
Cheers -- Marco
On Mar 18, 2008, at 19:44 , Richard M Kreuter wrote:
"Tobias C. Rittweiler" writes:
Richard M Kreuter writes:
Although it's undesirable to require a separate package for every tiny API, I think that in general there are drawbacks to specifying package names as part of interfaces (as opposed to implementations of interfaces).
So if I understood you correctly, you're advocating that CDR documents specify interfaces, and---in the same spirit as the MOP--- packaging is an implementation detail.
I agree up to this point.
To portably make use of such an interface, it's necessary to rely on a portability-library like SWANK-MOP or CLOSER-MOP (which you may have to do /anyway/ due to buggy/incomplete implementations from vendors.) Does this summarize your point fairly?
I don't agree that leaving packages out of interface specifications is what leads people to write compatibility libraries: compatibility libraries sometimes smooth out differences among implementations of interfaces, sometimes fix or hide bugs among implementations, sometimes target lowest-common-denominators of functionality for the purpose of being a lower bound for portability. For the MOP, if the only differences among MOP implementations were the namespacing, all you'd need in a MOP compatibility library would be a trivial script to build a package that imported and exported the right symbols. In fact, the differences among the CL implementors' MOPs are not so trivial, and the compatibility libraries must therefore do more than merely setting up some packages. (The same is true of Gray Streams implementations, IIRC.)
For the contrary opinion that a CDR should specify a package, notice that you can leave the question of having one package per CDR, or a single package for possibly several CDRs open by specifying that
"Symbols FOO, BAR, QUUX are exported from a package named CDR-N."
This makes it possible for implementations to collect symbols of several CDRs in one package as long as this package has nicknames CDR-X, CDR-N, CDR-Y (as long as symbols don't collide.)
You could specify interfaces this way, but then the user can't straightforwardly load more than one library that implements such an API, because the two libraries will collide in the package namespace.
For the case-with-test operator that people have been discussing, some folks have brought up the idea of having a portable implementation of whatever spec they come up with, and maybe eventually asking CL implementors to provide an optimized version, where possible. If the interface specification for case-with-test says that the operator must be available in some package by name, then a library that purports to conform to that interface will conflict with an implementation that purports to conform to the same interface, since they'll both be trying to set the symbol-function on the same symbol. Of course this can be worked around, e.g., a library that normally provides the operator might not define it when loading on an implementation that already defines the operator, but then users who'd prefer to use that library's implementation of the operator (say, because the library extends it, or has some flaw the user relies on) won't be able to do so on that implementation.
-- Richard _______________________________________________ cdr-discuss mailing list cdr-discuss@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/cdr-discuss
-- Marco Antoniotti
My brain is starting to hurt!
-- Gary Warren King, metabang.com Cell: (413) 559 8738 Fax: (206) 338-4052 gwkkwg on Skype * garethsan on AIM
On Mar 18, 2008, at 15:24 , Pierre R. Mai wrote:
Am 18.03.2008 um 15:08 schrieb Edi Weitz:
On Tue, 18 Mar 2008 14:49:19 +0100 (CET), "Leslie P. Polzer" leslie.polzer@gmx.net wrote:
I'm all for extending CL:CASE in a backwards-compatible way. Why would that be a problem for CL implementors?
It wouldn't be ANSI-compliant anymore.
Also, changes in implementations have been known to contain bugs, hence by forcing the changes to be to cl:case, we are going to potentially affect existing code bases, for no discernible gain. Given the sizable code bases out there, the only circumstances where I find it acceptable to mess with the COMMON-LISP package (or other packages or behaviours mandated by ANSI) is when there is no reasonable way of achieving the intended goal without doing so. In this case I can see no downsides to placing the extended case (or select, or what have you) symbol in a different package. Indeed this will aid adoption, since it makes it easier to provide this CDR as a user-maintained library for starters, with implementations still having the ability to optimize the implementation if enough users see the benefit of this (and personally I'd think that most useful optimizations can actually be achieved through user code as well).
Which brings me to another question I've been meaning to bring up w.r.t. the latest CDRs: Would it be sensible to have a defined package for these kinds of smallish extensions (like e.g. the index types, as well), maybe cdr-cl or ext-cl, or whatever? Has this been discussed already?
You are opening a can of worms :) But yes. At a minimum (and I would advocate a non-minimum solution which I will not discuss here) every CDR should come in its own package.
Cheers -- Marco
On Tue, 18 Mar 2008 14:49:19 +0100 (CET), "Leslie P. Polzer" leslie.polzer@gmx.net wrote:
I'm all for extending CL:CASE in a backwards-compatible way. Why would that be a problem for CL implementors?
It wouldn't be ANSI-compliant anymore.
I don't know.
CLHS 1.5.1.3, “Documentation of Extensions” says: “A conforming implementation shall be accompanied by a document that separately describes any features accepted by the implementation that are not specified in this standard, but that do not cause any ambiguity or contradiction when added to the language standard. Such extensions shall be described as being ``extensions to Common Lisp as specified by ANSI <<standard number>>.''”
Is a conforming implementation required to signal an error when an argument not defined by the standard occurs in the lambda list of a function? More specifically, may a conforming program rely on syntax/grammar errors being thrown?
Leslie
On Tue, 18 Mar 2008 15:34:40 +0100 (CET), "Leslie P. Polzer" leslie.polzer@gmx.net wrote:
Is a conforming implementation required to signal an error when an argument not defined by the standard occurs in the lambda list of a function?
I'm not a language lawyer, but I'd be /very/ surprised if it where in the spirit of the ANSI spec that you could "extend" functions at your whim. As a data point, look at the dictionary entry for DIRECTORY which specifically allows implementations to add keyword parameters to the function. Why would that passage be in there?
I'm not a language lawyer, but I'd be /very/ surprised if it where in the spirit of the ANSI spec that you could "extend" functions at your whim. As a data point, look at the dictionary entry for DIRECTORY which specifically allows implementations to add keyword parameters to the function. Why would that passage be in there?
That's enlightening and proves your point, thanks.
Leslie
On Tue, 18 Mar 2008 14:49:19 +0100 (CET), "Leslie P. Polzer" leslie.polzer@gmx.net wrote:
I'm all for extending CL:CASE in a backwards-compatible way. Why would that be a problem for CL implementors?
It wouldn't be ANSI-compliant anymore.
While we already have come to the conclusion that the spec usually mentions implementation-defined arguments explicitly, I came across Lispworks' MAKE-HASH-TABLE[1] today.
They seem to be quite liberal about it (as I am -- an additional keyword arg shouldn't hurt anyone). I wonder what the policies of other implementors are...
Leslie
[1] http://www.lispworks.com/documentation/lw445/LWRM/html/lwref-86.htm
On 6 Apr 2008, at 12:58, Leslie P. Polzer wrote:
On Tue, 18 Mar 2008 14:49:19 +0100 (CET), "Leslie P. Polzer" <leslie.polzer@gmx.net
wrote:
I'm all for extending CL:CASE in a backwards-compatible way. Why would that be a problem for CL implementors?
It wouldn't be ANSI-compliant anymore.
While we already have come to the conclusion that the spec usually mentions implementation-defined arguments explicitly, I came across Lispworks' MAKE-HASH-TABLE[1] today.
They seem to be quite liberal about it (as I am -- an additional keyword arg shouldn't hurt anyone). I wonder what the policies of other implementors are...
My impression is that most implementations have a liberal approach towards adding new keyword arguments to functions defined by ANSI Common Lisp. However, strictly speaking, that makes them non- conforming implementations. (But I would agree that ANSI Common Lisp is too strict in this regard.)
Pascal