Received: from SAIL by SCORE with Pup; Sun 8 May 83 09:07:08-PDT Received: from USC-ECL by SU-AI with TCP/SMTP; 8 May 83 08:31:49 PDT Received: from MIT-MC by USC-ECL; Fri 6 May 83 20:13:21-PDT Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Fri 6-May-83 22:59:56-EDT Date: Friday, 6 May 1983, 23:12-EDT From: David A. Moon Subject: Package Proposal (moby message) To: common-lisp@SU-AI In-reply-to: The message of 6 May 83 20:40-EDT from Scott E. Fahlman Since the mailing list seems to be working again, here's the response to Fahlman's package proposal from people at Symbolics. I think we are very close to converging, in spite of the voluminous nature of these comments. A summary of points made is at the end. ------- List the standard consistency (sanity) rules for package systems: If the value of *package* is not changed: - read-read consistency Reading the same print name always gets you the same (EQ) symbol. - print-read consistency An interned symbol always prints as a sequence of characters which, when read back in, yields the same (EQ) symbol. - print-print consistency If two interned symbols are not EQ, then their printed representations will not be the same sequence of characters. These consistency rules remain true in spite of any amount of implicit interning caused by typing in Lisp forms, loading files, etc. This has the important implication that results are reproducible regardless of the order of loading files or the exact history of what symbols were typed in when. The rules can only be violated by explicit action, such as changing the value of *PACKAGE*, calling one of the functions UNINTERN, IMPORT, SHADOW, INHERIT-PACKAGE, UNINHERIT-PACKAGE, or continuing from an error signalled by IMPORT or by reading an illegal qualified name. The purposes of the package system are two: to prevent naming conflicts, and to make the modular structure of programs more explicit. The tree-structured directory of names, allowing two packages to have the same name, has been invaluable for certain things (including bootstrapping our present Common Lisp implementation), but does not work completely. The fact that this has subtle problems suggests that it is better to leave it out of Common Lisp for now. The incompatibilities required to add it as an extension later can be made very small. [I agree with the proposal as it stands. We have had a lot of problems with the current hierarchical package namespace stuff as it stands. Most of our problems were because the very same hierarchy controlled both package inheritance and controlled the namespace of package names themselves. Thus, if you wanted to inherit from SYS, which is under GLOBAL, then your name isn't globally accessible. So you had to invoke a special mechanism to make your name globally accessible, which in practice most things did. The Common Lisp bootstrapping is about the only case I can think of where we have actually used the hierarchical naming, and boy is it a zoo keeping track of what's going on. --DLW] [In fact we have used it for other things. Some of the zoo is not inherent but is due to brain-damage in programs that weren't written with the hierarchical naming in mind. But I think we should leave it out of Common Lisp, at least for now.--Moon] Synonyms are very valuable, since people want to type short package prefixes but things should have long descriptive names. If the package system doesn't remember the full name, then people will have to consult documentation to find out what a package name abbreviation means. However this can be added later. [Our present package system uses synonyms heavily. On the one hand, it's desirable to use long, descriptive names, so that packages can print out as, e.g., #. On the other hand, it's nice to have short abbreviations, because you type them a lot when using the "qualified name" syntax, e.g., dbg:frame-active-p, dbg:with-erring-frame, etc. This is because you usually get at symbols in other packages by using qualified names, rather than by inheritance. --DLW] [BSG's only additional comment was that the balance of arguments is on the side of synonyms.] [Specifying synonyms in the recipient can replace hierarchical naming. (In common lisp, SI means what is CL-SI globally).--MMcM] Document that the package cell of an uninterned symbol contains NIL. It would be very useful to have two kinds of qualified name, one for externals and a second for internals. This way externals need not be put directly into one's main "name space," where the possibility of name conflicts can arise. Externals can be referenced by a qualified name, but the important externals/internals distinction that tells you which symbols in a module are interfaces you are allowed to use is retained. A different kind of qualified name is used for sticking your fingers where they don't belong. Reading an external qualified name should signal an error if you try to use an external that doesn't exist yet; continuing from the error should fake an EXPORT to create the desired external in the desired package. However the keyword package is a special case; you can always create new keywords. I suggest #: for the internal qualifier (keyword has no internals so this doesn't conflict with uninterned syntax). Double colon can remain reserved for future extensions (we have some in mind). There should be a function that does what the external-qualified-name syntax does. INTERN is the function corresponding to the internal-qualified-name syntax. This suggests an obvious name for the function, which will be confusing to MACRO-10 programmers. [Here we get to what is probably the most tricky issue in any package system that distinguishes between internal and external symbols. This issue has been the major thing that has held up major changes in the Zetalisp package system for so long. I don't have any breakthroughs but I think this issue deserves a good explanation and I threw in a few comments. Suppose I load into my Lisp environment a utility program containing subroutines that deal with magtape I/O stuff. This program is written using the package system. It lives in its own package, named TAPE, and all of its internal functions are internal symbols of the TAPE package so that they're hidden from the rest of the Lisp world. It has several entrypoints, which are external symbols of the TAPE package. Now, I am writing my own program (a backup dumper/loader) and I want to invoke the magtape utilities. There are two alternative schemes. In scheme 1, I inherit all of the external symbols of TAPE, and then I can just refer directly to those symbols. In scheme 2, I use a qualified name, saying tape:do-this-or-that to get at the tape. The proposal only appears to have scheme 1 in mind. The qualified names are referred to as being "desirable when typing an expression to be read by the Lisp reader", with the implication that programs aren't really supposed to use qualified names, that they're really more like a debugging tool. The qualified names search the internal symbols as well as the external symbols. Moon's comment is asking for some new mechanism to help allow scheme 2 work as well; that is, I think Moon is trying to design the package system in such a way that either scheme can be used. The advantage of scheme 2 shows up when you write a program that needs to call functions that reside in two different packages. Suppose we need to call a function named FOO from the A package, but we also need to call a function named FOO in the B package. In scheme 1 we can't do it at all (or need to resort to the colon, which is considered bad in scheme 1). A more subtle but more important problem is if we need a function FOO from the A package and a function BAR from the B package, but don't realize that B also has an external symbol named FOO, and so we don't worry enough about the order of the inheritance list; then we end up calling the wrong function at run-time. Probably this is pretty easy to find at run-time, as long as you understand about the problem. You fix it by rearranging the order of packages and trying again, hopin that there isn't any symbol on A with the name of a symbol that you need on B. If there is, again you're in trouble. Knowing which scheme a package system uses has an effect on how you choose your function names. In the Lisp Machine right now, there are two functions names chaos:make-stream and tape:make-stream. The fact that they have the same name doesn't cause any trouble, because the present Zetalisp package system only uses scheme 2. But if we belived in scheme 1, we'd have chosen the names differently, probably using make-chaos-stream and make-tape-stream. (If you decide you want both schemes, you have to use the latter set of names, and put up with the redundancy of tape:make-tape-stream.) In fact, in scheme 1, probably just about all of the external functions of the TAPE package would have "tape" in their names, whereas with scheme 2 none of them would. Of course, the presence of the IMPORT function is another way to solve the problems that scheme 2 addresses, since you can always explicitly IMPORT only exactly those symbols that you want to use. My present opinion isn't strong. I lean towards feeling that having both schemes is too hairy; we should go with one or the other and live with the minor problems, rather than having a facility that is capable of giving you a tradeoff between one set of problems and a different set of problems but which is harder to figure out how to use. But I don't feel convinced either way. And it will be a pain if we have to change all the names of the external functions in our existing TAPE package. --DLW] [Everyone who writes a program isn't going to put it in its own package, we have to face that. So, we still need to distinguish what symbols are entry points from those programs. This is the problem DCP keeps having with LMFS. #: could be only in SCL only, but then you couldn't write a CL program not in its own package that used some yellow pages program.--MMcM] [I think what this means is that scheme 2 is preferable, because it doesn't interfere with the operation of other programs in the same package, as scheme 1 does. It seems to me that the only viable position is to support both schemes, since some people will want one, some will want the other, and some will want both depending on circumstances. I don't think having both schemes available makes anything much worse. --Moon] SCL will of course continue to support package prefixes in front of structured object p.r.'s, such as lists, as well as in front of symbols. Just an abbreviation to avoid repeating a prefix many times. [Yes. This is an upward-compatible extension and shouldn't cause any problems. --DLW] If IMPORT finds a distinct symbol already present in the ancestors of the current package, it is presumably safe to assume that the user knows what he's doing and wants to shadow that symbol. If IMPORT finds a distinct symbol already present in the current package itself (either internal or external), we have a violation of the read-read consistency rule, because for that symbol to have gotten there someone must have read it. There may be programs or data already loaded containing references to that symbol, so IMPORT can't safely just replace it. A correctable error must be signalled. Upon continuing, IMPORT should do the hacks that Zetalisp GLOBALIZE does (it should do some checking before signalling the error, and list possible conflicts in the error message). This consists of checking for multiple distinct values, function definitions, and properties (check separately for each indicator) and complaining if any are found. If the symbol that is going to be thrown away has a value, function definition, or property that the symbol that is being imported does not have, it is copied onto that symbol, and vice versa. On the Lisp machine one can also forward the value, function, and property cells so that future changes to either symbol will propagate to the other one. This makes some screw cases non-fatal, e.g. where you were only using the symbol as the name of a function, and you got an undefined-function error because you forgot to import the symbol. Of course nothing can save you when you were depending on the EQ identity of symbols, other than fixing your package setup and loading the program (i.e. re-interning every name) over again. [The hacks that Moon describes (that GLOBALIZE does) are very ad hoc and obviously should not be part of the language. Having them in an error-proceeding handler is probably OK, although I greatly doubt that we want to make this part of the language definition. As far as Common Lisp goes, I think that to IMPORT a symbol when there is already a symbol of that name present should just be defined to signal an error. --DLW] EXPORT of a new symbol that wasn't exported before, into an externals that is somebody's ancestor, should check for name conflicts in a similar way. This is difficult because it doesn't know whether the descendant package shadowed the exported symbol accidentally or on purpose; maybe SHADOW should remember what it did. EXPORTing into an externals that hasn't been used as an ancestor yet, the usual case, is no problem. [Before we get into this level of hair, I'm still not sure what the definition of EXPORT is. My impression of the proposal was that every symbol is either uninterned or interned, and every interned symbol has exactly one home package, and every interned symbol is either an internal symbol of its home package or an external symbol of its home package. My impression was that EXPORT never changes the home package of a symbol; it merely "sets a bit" saying that this symbol is an external symbol of its own home package. But the @Defun says that the symbol becomes an external symbol in the current package. Is this just a mistake, or does EXPORT go around changing the home packages of its arguments? --DLW] [I can't tell from reading Fahlman's manuscript whether EXPORT requires that the symbols it is given already be in the current package, either internal or external, and just "sets their bit", or whether it is as if every package has attached to it a list of symbols, and EXPORT merely does a PUSHNEW onto that list. Of course it's really stored in some more efficient way than a list. If it's the former, what happens when try to export a symbol that you inherited from an ancestor? Is this a bug in the former scheme, or a useful detection of an error? --Moon] IMPORT does not do an UNEXPORT if somehow given an external of the current package. (Its @defun would suggest this.) [Probably the definition should be changed explicitly to say that IMPORT of a symbol that is already in the current package is a no-op. --DLW] I'm not sure about changing the ancestors list dynamically. This is a dangerous operation, but presumably it's only done "consciously." [I think our new collective opinion is that it's OK to have dangerous operations, and you take the consequences. What Moon means by "dangerous" is that it can have side-effects that are awfully hard to figure out. --DLW] Re: SI package. What you actually want is the SYS package, whose externals are the low-level and system-dependent interfaces that don't belong in the LISP package's externals. Normal packages, in particular USER, take LISP as an ancestor but don't take SYS as an ancestor. The old SI disappears into the internals of SYS. [Is there really any point in mentioning an SI package or a SYS package in the Common Lisp definition, if the definition doesn't ever define any symbols that live in those packages? Probably neither should be mentioned at all. --DLW] [I think it's a win for the name of this to be standardized. Admittedly that is somewhat bogus, since some implementations will decide they need more than one package of this kind and there is only one standard name. The CL manual shouldn't really say more about this than "SYS is the standard name for system-dependent things that don't go in LISP".--Moon] I think there are many cases in real life where a single package, with one internal set of symbols, wants to have several external sets of symbols that are distinct interfaces for different users. The external sets of symbols are not necessarily disjoint of course. To the outside world this looks like multiple packages, but the important difference is that there is only set of internals exporting to all of those packages. LISP and SYS are an example of this. It would save some juggling around if EXPORT took an optional second argument which was the package to export into. More about this below ("search lists"). [This is one of the things we've talked about for a long time, but I think it would be a big change to the proposal. I can't see how to incrementally modify the proposal to support this feature. --DLW] [See below--Moon] MAKE-PACKAGE must take keyword arguments, because it will certainly be extended in the future. The existing optional argument should be a keyword argument. There is a problem with your scheme with calling package setup functions such as IN-PACKAGE, IMPORT, and SHADOW at the front of a file that contains code to load into that package. At least in our system compiled binary files work by interning each symbol used in the file only once and then referencing it via a symbol table associated with the file. Any system that did this by first interning all the symbols used in the file, before evaluating any of the top-level-forms, would lose, because the symbols would get interned in the wrong package when the file was loaded. Our system interns symbols on first reference, so as long as they aren't accidentally used before the package setup forms you are all right. But note that the compiler can put symbols in the "header" at the front of the binary file that don't appear explicitly in the source file, e.g. because it records the place and date of compilation. I haven't figured out yet whether this is actually a problem in practice. Possibly the compiler needs to detect use of these package setup functions at top level and do something special with them. We have always preferred to put package setup things in a separate file from the main code. Of course, putting these package setup functions someplace in the middle of a file, rather than at the front, is virtually guaranteed to shaft you. [I'm not sure I understand all that you are saying here. I think that the issue is just like having (setq ibase ...) in a file, or like defining a reader-macro in a file and then using it. I presume that Common Lisp intends to allow the latter to work, and so LOAD is required to evaluate each form before it reads the next form. The compiler, likewise, has to process each for before it reads the next one, and the default eval-when-itude of in-package probably has to explicitly be compile-load-eval. I don't see any problem with the compiler's putting symbols in the header of a binary file; presumably the binary file format remembers what package these symbols were interned in. --DLW] [No, the issue isn't what happens at compile time (read time). Indeed at compile time setting the package is just like setting the base. The issue is what happens at load time; the package is different from the ibase and the readtable, because it has an effect at load time. The goal is to get the same symbols at load time as were gotten at compile time, without prohibiting the loader from encaching the results of INTERN in order to make loading faster. This is, I believe, only a real problem if the package-modifying functions are used in what I would consider an "unreasonable" way.--Moon] SHADOW is the only function that takes strings as proxies for symbols (assuming I have disambiguated the typos in its description in the way you intended). Note that the strings must be in upper-case. It is actually perfectly all right for SHADOW to take symbols as arguments, since any "accidental" interning this causes will be the interning that SHADOW would do anyway. Except there is the above-mentioned compiled-files issue, where the "accidental interning" in the loader's symbol table would not be all right. Again this might best be handled by saying that these functions should be used in files to be compiled only at top-level and only at the front of the file, where the compiler can detect them and handle them appropriately. ANCESTORS-LIST => PACKAGE-ANCESTORS, this is the standard naming convention. Is this first level only or is it the transitive closure of ancestor? There is a general issue here. I'm not at all sure that I believe in this depth-first search of the ancestors of the ancestors. Suppose I write a package called CHAOSNET, whose external symbols are the entry points I want people to call (CONNECT, DISCONNECT, and network things like that). Now to implement my chaosnet routines I need to call some hardware driver primitives, and I don't feel like writing package prefixes so I make the HARDWARE package an ancestor. When people use the CHAOSNET package as an ancestor, they shouldn't get those hardware things, which they are not supposed to use, thrown into their namespace. [Yes! This is the thing that most bothered me when I read the proposal. --DLW] On the other hand, we want to write yellow pages packages that add new general-use features. The way you had in mind to do this seems to have been to put some symbols in the externals of the YELLOW package, then add YELLOW to the ancestors of LISP, so that everyone who inherits from LISP will inherit from YELLOW also. This is surely better than YELLOW randomly going and interning its symbols into LISP so that people will get them. (let ((*package* (find-package "LISP"))) (import '(yellow:dog yellow:rain)) (export '(yellow:dog yellow:rain))) This is a translation into Common Lisp terms of the way we do it now in the Lisp machine, which everyone agrees is a crock of soil. [Oh, is THAT why there's the transitive inheritance of ancestors? This has the same name-conflict problems. If I want to use program A, and it loads a subroutine package P that adds its external symbols to the ancestor list of LISP, and then I want to use program B, and program B has an external or internal symbol with the same name as any external symbol of P, I'm in trouble. --DLW] [This paragraph is rephrased immediately below. But the original is of some interest, too.] Maybe what this shows is that the LISP package is really qualitatively different from other packages. Or in other words, perhaps there are two kinds of object in the world: packages and search-lists. They both have names and you can inherit from either. Inheriting from a package gets its own externals only; the ancestors list of a package is purely intended to affect that package's internals, not its externals. Inheriting from a search list gets the externals of all the packages listed in the search list, and if the search list is altered, what you inherit is altered. LISP is a search list of all the packages that go to make up the complete Lisp system. You can blithely inherit them all, or you can go ask what they are and pick and choose which ones you want to inherit, listing them all by name. Adding a new package to a search list should probably warn you if that would introduce two symbols with the same name in that search list. I.e. it's a bad idea for the order to matter, within one search list. In our discussion of packages two years ago, what I'm calling search lists here were called "conglomerates." [I would like to see packages and search lists distinguished. In addition to INHERIT-PACKAGE, EXPORT could take a search list, providing for more than one set of external symbols from the name package.--MMcM] Proposal to modify the proposal: The "package system" defines two kinds of named objects, called "packages" and "search lists". The names are strings, they are globally unique, and multiple names (nicknames) are allowed on an object. Each package has two search lists associated with it; a package's "external search list" has the same name as the package. A package's "internal search list" has no name. There are other search lists in the world as well. A package is an object that controls how READ and PRINT translate between printed representations of symbols and the actual symbol objects. A search list is a set of symbols that somehow belong together; the set is given a name so that it can be referred to. In the qualified name FOO:BAR, FOO is the name of a search list and BAR must be the name of some symbol in that search list. In the qualified name FOO#:BAR, FOO is the name of a package and BAR is translated into a symbol according to that package. Part of the difference between packages and search lists is that the contents of a search list are established very carefully and consciously. Often every symbol in a search list will be part of the interface to some module, and therefore will be mentioned in a piece of documentation. Conversely, the contents of a package are established haphazardly, according to whatever symbols happened to be contained in a program source file or typed in at top level, including spelling mistakes, typographical errors, etc. In addition to its internal and external search lists, a package has an internal symbol table and a shadow list. No two symbols in an internal symbol table have the same name. All symbols in a package's external search list (directly, not via ancestors) and in its shadow list also appear in its internal symbol table. Here is how a print-name is translated into a symbol, with respect to a certain package: 1. If a symbol with that print-name is in the internal symbol table, use it. 2. If a symbol with that print-name is in the internal search list, use it. 3. Create a new symbol with that print-name, put it in the internal symbol table, and use it. Every interned symbol is in at least one internal symbol table. One of those internal symbol tables, usually the only one, is considered its "home internal symbol table" and the corresponding package is its "home package". The SYMBOL-PACKAGE function returns the home package of an interned symbol, or NIL for an uninterned symbol. A symbol does not directly remember what search lists it is in. To print a symbol with respect to a package: If the value of *PRINPACKAGE* is non-NIL, go directly to step 3. 1. If the symbol is in the package's internal symbol table, just print it. 2. If the symbol is in the package's internal search list, and does not have the same name as a symbol in the package's shadow list, just print it. 3. Find the symbol's home package and print its name. If the symbol is in that package's external search list, print a colon, otherwise print a sharpsign and a colon. For uninterned and keyword symbols, print the appropriate prefix instead. Now print the symbol's print name. Note: An "obarray", a table which the system uses internally to map from character strings to symbols, is not a package and not a search list, and in fact is not visible to the user at all and not discussed in the Common Lisp manual. Every implementation will organize its obarrays in a different fashion, according to its own needs and hardware tradeoffs. A search list is defined by a list of symbols and a list of search lists, called its ancestors. The symbols in a search list are the listed symbols, plus all the symbols in the ancestors. This includes symbols in the ancestors of the ancestors, recursively to all levels. It is a rule that a given search list never contains two distinct symbols with the same print name; it is permissible for the same symbol to be in a search list for two different reasons (e.g. because it is in two ancestors, or because an ancestor is seen twice). Note that a search list does -not- contain a -copy- of its ancestors. If a symbol is added to or removed from an ancestor, the contents of the search list changes accordingly. This "late binding" is desirable so that the contents of a search list are not dependent on the order of operations in a non-obvious way. This "late binding" is viable because symbols are only added to search lists consciously, not accidentally as a side-effect of reading in an expression. Note that search lists are dual-purpose objects. A module uses a search list, e.g. its package's external search list, as a way to advertise its entry points for other modules to use. A module also uses search lists, e.g. its package's internal search list, as a way to locate the advertised entry points of other modules. This dual nature of search lists is a feature, not a bug, although the reasons may not be immediately apparent. MAKE-SEARCH-LIST name &key nicknames symbols ancestors if-exists Make a search list. nicknames, symbols, and ancestors default to NIL. if-exists controls what happens if a search list with this name already exists, and must be one of the following: :ERROR (the default) - signal an error. NIL - don't make a new search list, return the old one. :SUPERSEDE - make a new search list which replaces all uses of the old one as an ancestor. :RENAME - make a new search list. Rename the old one to a generated name. Uses of the old one as an ancestor continue to use it. MAKE-PACKAGE name &key nicknames ancestors if-exists Make a package and its two associated search lists. The external search list has the same name and nicknames as the package, no symbols, and no ancestors. The internal search list has no name, no symbols, and the specified ancestors, which defaults to (LISP), i.e. a single ancestor which is the search list containing all the symbols that define the Lisp language. if-exists is as for MAKE-SEARCH-LIST; :SUPERSEDE and :RENAME refer to the package's external search list. INTERN name &optional (package *package*) Do what READ does. UNINTERN symbol &optional (package *package*) Remove a symbol from the internal symbol table, and also from the external search list and from the shadow list, if present in them. EXPORT symbol(s) &optional (search-list (package-name *package*)) Insert symbols into a search list. Error if this would cause a name conflict, i.e. there would be two distinct symbols with the same name in the specified search list, in some search list of which it is an ancestor, or in a package's internal symbol table and internal search list, provided that the symbol in the package's internal symbol table is not also in its shadow list. Some programs have more than one external search list, because they present more than one interface to the outside world. MAKE-SEARCH-LIST is used to create the additional search lists, and EXPORT with two arguments is used to place symbols into them. UNEXPORT symbol(s) &optional (search-list (find-search-list (package-name *package*))) Remove symbols from a search list, without otherwise affecting them. IMPORT symbol(s) &optional (package *package*) Add symbols to the package's internal symbol table. Error if this would cause a name conflict (see EXPORT). SHADOW symbol(s) &optional (package *package*) Ensure that symbols with the specified names are in the package's internal symbol table, and on its shadow list. UNINTERN serves to undo SHADOW. IMPORT-AND-SHADOW symbol(s) &optional (package *package*) Same as import, but only gets a name conflict error if there is already a different symbol with the same name in the internal symbol table, not if there is one in the internal search list. Adds the imported symbols to the shadow list so that we don't later think there is a name conflict with the internal search list. IMPORT-AND-SHADOW cannot be done by combining separate IMPORT and SHADOW operations in the case where there is already a different symbol with the same name in the internal search list, e.g. importing a symbol that shadows a basic Lisp function in order to install an incompatible or improved version. FIND-PACKAGE name Get the package with the specified name, or NIL. FIND-SEARCH-LIST name Get the search list with the specified name, or NIL. PACKAGE-INTERNAL-SEARCH-LIST package Get the internal search list object, which has no name, for the package. SEARCH-LIST-ANCESTORS search-list A list of the (immediate) ancestors. SEARCH-LIST-ALL-ANCESTORS search-list A list of all the (recursive) ancestors. ADD-SEARCH-LIST-ANCESTORS search-list &rest ancestors Add ancestors to a search list, checking for name conflicts (see EXPORT). The order of ancestors to a search list never matters, since there are no duplicate symbols. REMOVE-SEARCH-LIST-ANCESTORS search-list &rest ancestors Remove ancestors from a search list. [Should the above two functions be deleted in favor of SETF of SEARCH-LIST-ANCESTORS? It is still necessary to check for name conflicts when adding ancestors. But this would allow the use of sequence tools, e.g. PUSHNEW, on the ancestors list.] *PRINPACKAGE* variable, default NIL If T, always print package prefixes on symbols regardless of the value of *package*. This is typically used by package-related tools that want to be very explicit about what package a symbol is in. DO-SEARCH-LIST-SYMBOLS (var search-list-or-name result-form) body... Iterate over all the symbols in a search list. DO-PACKAGE-SYMBOLS (var package-or-name result-form) body... Iterate over all the symbols in a package's internal symbol table and internal search list. DO-PACKAGE-INTERNAL-SYMBOLS (var package-or-name result-form) body... Iterate over all the symbols in a package's internal symbol table. DO-ALL-SYMBOLS (var result-form) body... Iterate over all the symbols in all packages' internal symbol tables. [Most of the above functions accept names of packages and search lists in place of the objects themselves. This needs to be made explicit in the manual, I left it out for brevity.] Note: the use of the word "list" in the above discussion is not to be taken to imply that the implementation uses lists in preference to some other table organization. End of proposal to modify the proposal. Why is LIST-PACKAGES a function rather than a (read-only) variable? Is it intentional that INTERN only accepts a string, not a symbol? In the laser edition it accepts either, as in Maclisp and Zetalisp. [Note that the existing SHADOW is what Zetalisp calls INTERN-LOCAL, and it accepts strings (but not symbols!). --DLW] This chapter of the manual -must- include a complete example of how to set up a toy yellow-pages package. Include a discussion of the issues with mutually-recursive (in the externals) packages, such as in the example on page 292 of the laser edition. Note the dependency on package setup (including declaration of all externals) happening first, before any code is loaded, and before any files that create other packages that use this one as an external are loaded. Include WHERE-IS. See the Lisp Machine manual, or try it on one of your machine(s!). This is handy for debugging package problems. For each symbol it finds with that name, it tells you where it found it, its home package if that is different, and all the packages that inherit it from that place. In this new package scheme it would tell you also whether it was internal or external in the place that it found it. The same symbol can be listed more than once if it's been imported. In addition to WHERE-IS, a user command that prints out and so forth, there should be a primitive, FIND-ALL-SYMBOLS, which takes a print name string and returns a list of all the symbols, interned in any package, with that print name. The system can probably do this much more efficiently than the user could with the primitives available in your proposal. In EXPORT and related functions, is NIL as an argument NIL or ()? It doesn't really matter which, but you must specify. Note that there are ways to do the "searching" without multiple hash-table lookups by INTERN. These aren't necessarily desirable, depending on the particular system's space and time tradeoffs. But it's probably worth noting in the manual that the implementation need not correspond directly to the way it's described; otherwise people might imagine that it's very inefficient. [In the file, where it says "@Defvar[Var {package}]", I think you really mean "@Defvar[Var {*package*}]". Also, at this point in the file, it says that it's OK for the value to be the name of a package, whereas earlier it says explicitly that it must be a package object. I think that it should be required to be a package object, and assume that's what you meant. --DLW] ------- Summary of points made: 1. Include the consistency rules in the documentation. 2. Clarify all ambiguities and loosenesses in the documentation; this stuff is difficult enough without the documentation adding to the problems. I'd be happy to help with this. Include a complete example of the use of packages. 3. Give MAKE-PACKAGE keyword arguments. Actually you can't go wrong with a general rule that anything that is named MAKE-xxx should take keyword arguments, along with some number of required arguments. 4. Put in synonyms (:NICKNAMES keyword in MAKE-PACKAGE). 5. Have four kinds of qualified name (two new kinds): :foo keyword #:foo uninterned symbol foo:bar external-symbol reference (error if not exported) foo#:bar internal-symbol reference (just like setting *package*) 6. Provide a function (or arguments to an existing function) to allow a program to do what each piece of syntax does. 7. Signal an error when there is a possibility of name conflict in IMPORT, EXPORT, or INHERIT-PACKAGE (and the proposed new functions). Continuing from the error can attempt to fix things up. Provide a WHERE-IS function to allow users to figure out what's going on, and a FIND-ALL-SYMBOLS function which is the underlying primitive on which WHERE-IS is built. 8. Separate the notions of package and search-list in order to clarify the issues of internal vs. external symbols.  Received: from SAIL by SCORE with Pup; Sat 7 May 83 21:09:46-PDT Received: from CMU-CS-C by SU-AI with TCP/SMTP; 7 May 83 21:05:35 PDT Received: ID ; 8 May 83 00:05:29 EDT Date: Sun, 8 May 1983 00:05 EDT From: Jim Large To: David A. Moon Cc: Common-Lisp@su-ai Subject: error proposal Phoon: LQ+3D.15H.37M.18S. Sorry, my babyl backfired. -- Jim  Received: from SAIL by SCORE with Pup; Sat 7 May 83 21:00:59-PDT Received: from CMU-CS-C by SU-AI with TCP/SMTP; 7 May 83 20:56:50 PDT Received: ID ; 7 May 83 23:56:42 EDT Date: Sat, 7 May 1983 23:56 EDT From: Jim Large To: David A. Moon Cc: Common-Lisp@su-ai Subject: error proposal Phoon: LQ+3D.15H.37M.18S. In-reply-to: Msg of 7 May 1983 21:04-EDT from Scott E. Fahlman  Received: from SAIL by SCORE with Pup; Sat 7 May 83 20:31:27-PDT Received: from USC-ECL by SU-AI with TCP/SMTP; 7 May 83 20:13:17 PDT Received: from MIT-MC by USC-ECL; Fri 6 May 83 20:22:12-PDT Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Fri 6-May-83 23:06:33-EDT Date: Friday, 6 May 1983, 23:19-EDT From: David A. Moon Subject: Errors To: Common-Lisp@su-ai Now that the mailing list appears to be working again, I'm re-sending my proposal to replace chapter 23 of the laser manual (on errors). My apologies to anyone who has seen this before (but I would advise you to wade through it again, because the previous proposal was sent out as an initial letter and a couple of appendices, so you might not have really seen all of it.) Our experience is that error-handling of adequate flexibility and power requires a complex error classification system, using flavors or the equivalent. Not everyone in the Common Lisp community agrees, and our implementation of these ideas has only been in existence for half a year, not long enough to consider it mature and stable. Chapter 23 of the laser manual is mainly a rehash of the old Lisp machine condition system (documented in The Lisp Machine Manual), which was generally found to be totally inadequate. Therefore we propose that for the present the language only standardize on ways to SIGNAL errors, not on ways to HANDLE errors. Of course a complete language requires error-handling mechanisms, but many useful portable programs do not require them. Thus it makes sense to defer standardizing this until we understand it better. The rest of this proposal replaces everything in chapter 23 of the laser manual. Most uppercase text should be read as boldface. Italics are not indicated. - Handling errors When an error is signalled, either by calling one of the functions documented in this section or directly by the Lisp system, it is handled in an implementation-dependent way. The general assumption is that each implementation will provide an interactive debugger that prints the error message, along with suitable contextual information such as what function detected the error. The user may interact with the debugger to examine or modify the state of the program in various ways, including abandoning the current computation ("aborting to top level") and continuing from the error. What "continuing" means depends on how the error is signalled; details are given with each error signalling function. [The Lisp machine calls continuing "proceeding".] - General error signalling functions ERROR format-string &rest args Signal an error, with the message constructed by applying FORMAT to the arguments. It is impossible to continue from this kind of error; thus the ERROR function will never return (barring someone meddling with it by redefining it or by using an interactive debugger to force it to return). The error message should not contain a carriage return at the beginning or end, and should not contain any sort of herald indicating that it is an error. The system will take care of these according to whatever its preferred style may be. Conventionally error messages are complete English sentences, ending with a period. Carriage returns in the middle of long messages are okay. The debugger printout in the following example is not to be taken as a Common Lisp requirement; it is only an example of what an implementation might print when ERROR is called. Example: (ERROR "The command ~S is unrecognized." CMD) Error: The command EMERGECNY-SHUTDOWN is unrecognized. Error signalled by function OPERATOR-COMMAND-EXECUTE. > [The Lisp machine calls this FERROR]. CERROR format-string &rest args Signal an error, with the message constructed by applying FORMAT to the arguments. Continuing from such an error will cause CERROR to return NIL. Use CERROR rather than ERROR to signal errors for which you have written recovery code. The name stands for "continuable error," which is too verbose to use for such a common function. Examples: (UNLESS (= (LIST-LENGTH FORM) 3) (CERROR "Wrong number of arguments in ~S; continuing will ~ :~[ignore extra args~;assume 0 for missing args~]." FORM (< (LIST-LENGTH FORM) 3)) (SETQ FORM (APPEND FORM '(0 0)))) (DO () ((KNOWN-WORDP X) X) (CERROR "~S is unknown, probably misspelled. Continue if you ~ want to replace it and try again." X) (FORMAT T "~&New word: ") (SETQ X (READ))) ;This example could be done more briefly with ASSERT or ;even with CHECK-TYPE (and SATISFIES). [The Lisp machine calls this FSIGNAL, except that it returns :NO-ACTION rather than NIL.] WARN format-string &rest args Print an error message constructed by applying FORMAT to the arguments, but don't go into the debugger. This would just be FORMAT with output directed to *ERROR-OUTPUT*, except that WARN takes care of advancing to a fresh line before and after the error message and may do other implementation-dependent things (in Symbolics Common Lisp, WARN messages printed during a compilation are associated with the function being compiled and saved for later perusal by editor tools. Furthermore WARN automatically prints the name of the function associated with the warning.) If it is desired to make WARN behave like CERROR (pause in the debugger after each warning), use TRACE on the WARN function. [The manual should state explicitly that this is supposed to work; calls to WARN mustn't be compiled in a special way that would make TRACE not find them. I realize that currently the portable subset of TRACE does not define a way to make a function pause into the debugger.] [The Lisp machine calls this COMPILER:WARN, approximately.] BREAK format-string &rest args Print the message and go directly into the debugger, without allowing any possibility of interception by error-handling facilities. There aren't any error-handling facilities in Common Lisp, but there might be in particular implementations, and there will be in Common Lisp in the future. The lack of interception is the only program-visible difference between BREAK and CERROR. The interactive debugger may choose to display them differently, for instance a CERROR's message might be prefixed with "Error:" and a BREAK's message prefixed with "Break:". This depends on the user-interface style of the particular implementation. When continued, BREAK returns NIL. It is permissible to call BREAK with no arguments; it will supply some default message. Compatibility note: Maclisp's BREAK takes two optional arguments. The first would be a string if Maclisp had strings. The second is a boolean value specifying whether BREAK should break or return immediately. In Common Lisp one makes a BREAK conditional by putting it inside a conditional form such as WHEN or UNLESS. - Specialized error-signalling special forms (or macros) CHECK-TYPE place typespec [string] Special Form Signal an error if the contents of place is not of the desired type. Continuing from this error will ask for a new value, store it into place, and start over, checking the type of the new value and signalling another error if it is still not of the desired type. Subforms of place may be evaluated multiple times, because of the implicit loop generated. CHECK-TYPE returns NIL. place must be a generalized variable reference acceptable to SETF. typespec must be a type expression; it is not evaluated. string must be an English description of the type, starting with an indefinite article (a or an); it is not evaluated. If string is not supplied, it is computed automatically from typespec. The error message will mention place, its contents, and the desired type. Some implementations may generate a somewhat differently worded error message if they recognize that place is one of the arguments to the function that called CHECK-TYPE. Example: (SETQ X 'FOO) (CHECK-TYPE X (INTEGER 0 *) "a positive integer") Error: The value of X, FOO, is not a positive integer. [The Lisp machine calls this CHECK-ARG-TYPE.] ASSERT test-form [reference]* [string [arg]*] Special Form Signal an error if the value of test-form is false. Continuing from this error will allow the user to alter the values of some variables and will then start over, evaluating the test-form again. ASSERT returns NIL. test-form is any form. Each reference (there may be any number of them, or none) is a generalized-variable reference acceptable to SETF. These are variables that test-form depends on and that it makes sense to allow the user to change when continuing from the error. Subforms of the references are only evaluated if an error is signalled, and may be re-evaluated if the error is signalled again (after continuing without actually fixing the problem). string is an error message string, not evaluated. args are forms evaluated only if an error is signalled, and re-evaluated if the error is signalled again. FORMAT is applied to string and args to get the error message. If string is omitted, a default error message such as "assertion failed" is used; in this case the args must be omitted, since the string serves to delimit the references from the args. The test-form and references are not directly included in the error message, but might be made available for the user's perusal by the debugger. If the user gives the continue command, he should be presented with the opportunity to alter the values of any or all of the references; the details of this depend on each particular implementation's user-interface style, of course. I'm willing to change the syntax of ASSERT to include some parentheses, e.g. around the references, if the use of the error message string as a delimiter is felt to be too untasteful. Note however that that would make it non-upward-compatible with the definition in the laser edition. I don't know whether that matters. Examples: (ASSERT (VALVE-CLOSED-P V1)) (ASSERT (VALVE-CLOSED-P V1) "Live steam is escaping!") (ASSERT (VALVE-CLOSED-P V1) (VALVE-MANUAL-CONTROL V1) "Live steam is escaping!") (ASSERT (<= MINBASE BASE MAXBASE) BASE "Base ~D is out of the range ~D-~D" BASE MINBASE MAXBASE) ;Note that the user is invited to change BASE, but not the bounds. (ASSERT (= (ARRAY-DIMENSION A 1) (ARRAY-DIMENSION B 0)) A B "The matrix multiplication ~S x ~S cannot be performed" A B) - Exhaustive case analysis special forms (or macros) [Better names for these special forms are solicited!] ETYPECASE value [clauses]* Special Form The syntax is the same as TYPECASE, except that no OTHERWISE clause is permitted. If no clause is satisfied, ETYPECASE signals an error with a message constructed from the clauses. It is not permissible to continue from this error. To supply your own error message, use TYPECASE with an OTHERWISE clause containing a call to ERROR. The name of this function stands for either "exhaustive type case" or "error-checking type case". Example: (SETQ X 1/3) (ETYPECASE X (INTEGER (- X)) (SYMBOL (INVERSE X))) Error: The value of X, 1/3, was neither an integer nor a symbol. CTYPECASE reference [clauses]* Special Form The syntax is the same as TYPECASE, except that no OTHERWISE clause is permitted. The reference must be a generalized variable reference acceptable to SETF. If no clause is satisfied, CTYPECASE signals an error with a message constructed from the clauses. Continuing from this error accepts a new value from the user, stores it into reference, and starts over, making the type tests again. Subforms of reference may be evaluated multiple times. The name of this function stands for "continuable exhaustive type case". ECASE value [clauses]* Special Form The syntax is the same as CASE, except that no OTHERWISE clause is permitted. If no clause is satisfied, ECASE signals an error with a message constructed from the clauses. It is not permissible to continue from this error. To supply your own error message, use CASE with an OTHERWISE clause containing a call to ERROR. The name of this function stands for either "exhaustive case" or "error-checking case". Example: (SETQ X 1/3) (ECASE X (ALPHA (FOO)) (OMEGA (BAR))) Error: The value of X, 1/3, is neither ALPHA nor OMEGA. CCASE reference [clauses]* Special Form The syntax is the same as CASE, except that no OTHERWISE clause is permitted. The reference must be a generalized variable reference acceptable to SETF. If no clause is satisfied, CCASE signals an error with a message constructed from the clauses. Continuing from this error accepts a new value from the user, stores it into reference, and starts over, making the clause tests again. Subforms of reference may be evaluated multiple times. The name of this function stands for "continuable exhaustive case". - Issues Should the following function exist? It's not clear how to define what it means in an implementation-independent way. ABORT-PROGRAM This function never returns. It throws out of the user's program and restores control to the Lisp system. (In the future, when Common Lisp includes error-handling mechanisms, it will also include a way to define to where this function, and the equivalent debugger command, transfers control.) [The Lisp machine calls this (SIGNAL 'SYS:ABORT), but very few programs do this explicitly. Probably no "user" programs do it.] In CHECK-TYPE, ASSERT, CTYPECASE, and CCASE, I have specified that subforms of the references may be evaluated multiple times. Would it be better to specify that they are always evaluated exactly once? This would be "more consistent" with SETF, but might present implementation difficulties. In ASSERT there is an efficiency issue, since you would like not to deal with anything but the test-form in the usual, no-error case; thus ASSERT shouldn't be required to evaluate the references and args if it doesn't signal an error. Furthermore, "the same" references presumably appear somewhere inside the test-form, or somewhere inside something it calls, so in fact the references would really be evaluated twice anyway. In CHECK-TYPE, CTYPECASE, and CCASE the naive user might plausibly expect subforms of the reference to be evaluated only once. It might not be a good idea to make ASSERT be inconsistent with the other three, though. I'm unsure what to do here. - Possible future extensions We anticipate that some or all of the following will be added to Common Lisp in the future, when they are better understood. A "condition system" providing names for unusual conditions (including but not limited to errors) and a taxonomic system for classifying those names. Extension of FERROR, CERROR, and WARN so that if the first argument is a symbol, it is taken to be a condition name. In this case the format-string is the second argument. If no condition name is specified, a default condition name with no interesting properties is assumed. Ways to define the behavior and relationships of conditions. Ways to use conditions as inter-module interfaces. Ways to use conditions to customize the behavior of the interactive debugger. Ways to establish condition handlers, so that programs may respond to conditions, by throwing out, by continuing, or by correcting the reason for the condition and retrying. A way to trap errors without going into the debugger, within a certain dynamic scope. Portable debugger details, e.g. TRACE and BREAKON commands. Facilities making it possible for a user to write a portable debugger. Portable floating-point exception, overflow, and rounding control.  Received: from SAIL by SCORE with Pup; Sat 7 May 83 18:08:44-PDT Received: from CMU-CS-C by SU-AI with TCP/SMTP; 7 May 83 18:04:23 PDT Received: ID ; 7 May 83 21:04:05 EDT Date: Sat, 7 May 1983 21:04 EDT From: Scott E. Fahlman To: David A. Moon Cc: Common-Lisp@su-ai Subject: error proposal In-reply-to: Msg of 7 May 1983 18:02-EDT from David A. Moon Now that Moon's error proposal has made it out to the mailing list, I can say that I am strongly in favor of it. The old proposal, as it evolved through various versions, ended up tying down all the wrong things. It is essential that the white pages include a good set of portable mechanisms for signalling errors, but I believe that the style of user interaction will vary so much from one implementation to another that it is a major mistake to say too much about error handling and user dialogues. Of course, the Lisp we are doing will have a condition handler that looks very much like the one specified in Laser. What this proposal does is to give us some room to evolve to something better in the future, as well as correcting some things that are already bothering us. On the issues: Should the manual include some way to make WARN behave like CERROR (pause in the debugger after each warning)? I advocate a *BREAK-ON-WARNINGS* switch. We'll probably add such a switch to our implementations in any event (a compatible extension) since I think it would be useful between now and when the "future condition-handling system" appears. I'm willing to change the syntax of ASSERT... The ASSERT Moon proposes above in the body of the proposal looks OK to me. Should the following function (ABORT-PROGRAM) exist? I agree with Moon: let's leave it out for now. There are funny issues about how this would interact with various top-levels (editor-based, etc.) and with breaks and embedded command loops. In CHECK-TYPE, ASSERT, CTYPECASE, and CCASE, I have specified that subforms of the references may be evaluated multiple times. Would it be better to specify that they are always evaluated exactly once? I think it's a mistake to specify that subforms here are evaluated only once. The reading of these forms (to present the current values to the user) and the setting of new values could be very far apart, with perhaps a breakpoint and some arbitrary environment-prowling by the user in between. We should allow implementors to have some flexibility here. DEFTYPE should provide a way to specify the default description string, used when that type is the second subform of CHECK-TYPE and there is no third subform. Is this what the documentation string in DEFTYPE is for, or is that something else? I think it would be confusing to snarf DEFTYPE's documentation string for this purpose. The "type name in English" and the documentation string might have similar contents, but the former must obey funny format rules that do not apply to any other kind of documentation. I think that these ought to be separate arguments to DEFTYPE. -- Scott  Received: from SAIL by SCORE with Pup; Sat 7 May 83 15:10:59-PDT Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 7 May 83 15:06:19 PDT Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Sat 7-May-83 18:03:38-EDT Date: Saturday, 7 May 1983, 18:02-EDT From: David A. Moon Subject: error proposal To: Common-Lisp@su-ai Here is my proposal to replace chapter 23 of the laser edition. I've mailed versions of this out several times already, but as far as I know they were lost in the network. If you've seen this already, I apologize for the redundancy. However, you should read it again since it has been amended as a result of discussion with various people. This message corresponds to version 6 of the file, made 5/7/83. Please respond this week. It would be very nice to have an error chapter we can all agree on in the next edition of the manual. I'd also like to see some suggestions or votes on the "issues" section, which includes questions I didn't feel confident enough to decide. Our experience is that error-handling of adequate flexibility and power requires a complex error classification system, using flavors or the equivalent. Not everyone in the Common Lisp community agrees, and our implementation of these ideas has only been in existence for half a year, not long enough to consider it mature and stable. Chapter 23 of the laser manual is mainly a rehash of the old Lisp machine condition system (documented in The Lisp Machine Manual), which was generally found to be totally inadequate. Therefore we propose that for the present the language only standardize on ways to SIGNAL errors, not on ways to HANDLE errors. Of course a complete language requires error-handling mechanisms, but many useful portable programs do not require them. Thus it makes sense to defer standardizing this until we understand it better. The rest of this proposal replaces everything in chapter 23 of the laser manual. Most uppercase text should be read as boldface. Italics are not indicated. - Handling errors When an error is signalled, either by calling one of the functions documented in this section or directly by the Lisp system, it is handled in an implementation-dependent way. The general assumption is that each implementation will provide an interactive debugger that prints the error message, along with suitable contextual information such as what function detected the error. The user may interact with the debugger to examine or modify the state of the program in various ways, including abandoning the current computation ("aborting to top level") and continuing from the error. What "continuing" means depends on how the error is signalled; details are given with each error signalling function. [The Lisp machine calls continuing "proceeding".] - General error signalling functions ERROR format-string &rest args Signal an error, with the message constructed by applying FORMAT to the arguments. It is impossible to continue from this kind of error; thus the ERROR function will never return (barring someone meddling with it by redefining it or by using an interactive debugger to force it to return). The error message should not contain a carriage return at the beginning or end, and should not contain any sort of herald indicating that it is an error. The system will take care of these according to whatever its preferred style may be. Conventionally error messages are complete English sentences, ending with a period. Carriage returns in the middle of long messages are okay. The debugger printout in the following example is not to be taken as a Common Lisp requirement; it is only an example of what an implementation might print when ERROR is called. Example: (ERROR "The command ~S is unrecognized." CMD) Error: The command EMERGECNY-SHUTDOWN is unrecognized. Error signalled by function OPERATOR-COMMAND-EXECUTE. > [The Lisp machine calls this FERROR]. CERROR format-string &rest args Signal an error, with the message constructed by applying FORMAT to the arguments. Continuing from such an error will cause CERROR to return NIL. Use CERROR rather than ERROR to signal errors for which you have written recovery code. The name stands for "continuable error," which is too verbose to use for such a common function. Examples: (UNLESS (= (LIST-LENGTH FORM) 3) (CERROR "Wrong number of arguments in ~S; continuing will ~ :~[ignore extra args~;assume 0 for missing args~]." FORM (< (LIST-LENGTH FORM) 3)) (SETQ FORM (APPEND FORM '(0 0)))) (DO () ((KNOWN-WORDP X) X) (CERROR "~S is unknown, probably misspelled. Continue if you ~ want to replace it and try again." X) (FORMAT T "~&New word: ") (SETQ X (READ))) ;This example could be done more briefly with ASSERT or ;even with CHECK-TYPE (and SATISFIES). [The Lisp machine calls this FSIGNAL, except that it returns :NO-ACTION rather than NIL.] WARN format-string &rest args Print an error message constructed by applying FORMAT to the arguments, but don't go into the debugger. This would just be FORMAT with output directed to *ERROR-OUTPUT*, except that WARN takes care of advancing to a fresh line before and after the error message and may do other implementation-dependent things (for example, in Symbolics Common Lisp, WARN messages printed during a compilation are associated with the function being compiled and saved for later perusal by editor tools. Furthermore WARN automatically prints the name of the function associated with the warning.) [The Lisp machine calls this COMPILER:WARN, approximately.] BREAK format-string &rest args Print the message and go directly into the debugger, without allowing any possibility of interception by error-handling facilities. There aren't any error-handling facilities in Common Lisp, but there might be in particular implementations, and there will be in Common Lisp in the future. The lack of interception is the only program-visible difference between BREAK and CERROR. The interactive debugger may choose to display them differently, for instance a CERROR's message might be prefixed with "Error:" and a BREAK's message prefixed with "Break:". This depends on the user-interface style of the particular implementation. When continued, BREAK returns NIL. It is permissible to call BREAK with no arguments; it will supply some default message. Compatibility note: Maclisp's BREAK takes two optional arguments. The first would be a string if Maclisp had strings. The second is a boolean value specifying whether BREAK should break or return immediately. In Common Lisp one makes a BREAK conditional by putting it inside a conditional form such as WHEN or UNLESS. - Specialized error-signalling special forms (or macros) CHECK-TYPE place typespec [string] Special Form Signal an error if the contents of place is not of the desired type. Continuing from this error will ask for a new value, store it into place, and start over, checking the type of the new value and signalling another error if it is still not of the desired type. Subforms of place may be evaluated multiple times, because of the implicit loop generated. CHECK-TYPE returns NIL. place must be a generalized variable reference acceptable to SETF. typespec must be a type expression; it is not evaluated. string must be an English description of the type, starting with an indefinite article (a or an); it is not evaluated. If string is not supplied, it is computed automatically from typespec. The reason that the optional string is allowed is that some usages of CHECK-TYPE may prefer a more specific or more explanatory description of what is wanted than can be generated automatically by the type system. The error message will mention place, its contents, and the desired type. Some implementations may generate a somewhat differently worded error message if they recognize that place is one of the arguments to the function that called CHECK-TYPE. Example: (SETQ X 'FOO) (CHECK-TYPE X (INTEGER 0 *) "a positive integer") Error: The value of X, FOO, is not a positive integer. [The Lisp machine calls this CHECK-ARG-TYPE.] ASSERT test-form [reference]* [string [arg]*] Special Form Signal an error if the value of test-form is false. Continuing from this error will allow the user to alter the values of some variables and will then start over, evaluating the test-form again. ASSERT returns NIL. test-form is any form. Each reference (there may be any number of them, or none) is a generalized-variable reference acceptable to SETF. These are variables that test-form depends on and that it makes sense to allow the user to change when continuing from the error. Subforms of the references are only evaluated if an error is signalled, and may be re-evaluated if the error is signalled again (after continuing without actually fixing the problem). string is an error message string, not evaluated. args are forms evaluated only if an error is signalled, and re-evaluated if the error is signalled again. FORMAT is applied to string and args to get the error message. If string is omitted, a default error message such as "assertion failed" is used; in this case the args must be omitted, since the string serves to delimit the references from the args. The test-form and references are not directly included in the error message, but might be made available for the user's perusal by the debugger. If the user gives the continue command, he should be presented with the opportunity to alter the values of any or all of the references; the details of this depend on each particular implementation's user-interface style, of course. Examples: (ASSERT (VALVE-CLOSED-P V1)) (ASSERT (VALVE-CLOSED-P V1) "Live steam is escaping!") (ASSERT (VALVE-CLOSED-P V1) (VALVE-MANUAL-CONTROL V1) "Live steam is escaping!") (ASSERT (<= MINBASE BASE MAXBASE) BASE "Base ~D is out of the range ~D-~D" BASE MINBASE MAXBASE) ;Note that the user is invited to change BASE, but not the bounds. (ASSERT (= (ARRAY-DIMENSION A 1) (ARRAY-DIMENSION B 0)) A B "The matrix multiplication ~S x ~S cannot be performed" A B) - Exhaustive case analysis special forms (or macros) [Better names for these special forms are solicited!] These macros are included in the standard language, even though a user could write them himself using the other standard facilities provided, for several reasons. It is likely that many people will want these, and so a standard consistent set should be provided rather than allowing a variety of incompatible dialects to develop. The E- versions are just automatically-generated OTHERWISE clauses, but the C- versions require some thought in order to implement correctly, so they should be provided by the system so users don't have to puzzle them out on their own. Individual implementations may be able to do a better job on these, using their own idiosyncratic facilities, than can be done using the standard facilities. Related to this is the fact that if the implementation provides these, they will fit better into its particular user-interface style. There is also the argument from morality: most people are too lazy to put in an otherwise clause to check for cases they didn't anticipate, even if they would agree that they will probably get shafted later. By making this very easy to do (one character) we make it more likely that people will take the trouble to do it. ETYPECASE value [clauses]* Special Form The syntax is the same as TYPECASE, except that no OTHERWISE clause is permitted. If no clause is satisfied, ETYPECASE signals an error with a message constructed from the clauses. It is not permissible to continue from this error. To supply your own error message, use TYPECASE with an OTHERWISE clause containing a call to ERROR. The name of this function stands for either "exhaustive type case" or "error-checking type case". Example: (SETQ X 1/3) (ETYPECASE X (INTEGER (- X)) (SYMBOL (INVERSE X))) Error: The value of X, 1/3, was neither an integer nor a symbol. CTYPECASE reference [clauses]* Special Form The syntax is the same as TYPECASE, except that no OTHERWISE clause is permitted. The reference must be a generalized variable reference acceptable to SETF. If no clause is satisfied, CTYPECASE signals an error with a message constructed from the clauses. Continuing from this error accepts a new value from the user, stores it into reference, and starts over, making the type tests again. Subforms of reference may be evaluated multiple times. The name of this function stands for "continuable exhaustive type case". ECASE value [clauses]* Special Form The syntax is the same as CASE, except that no OTHERWISE clause is permitted. If no clause is satisfied, ECASE signals an error with a message constructed from the clauses. It is not permissible to continue from this error. To supply your own error message, use CASE with an OTHERWISE clause containing a call to ERROR. The name of this function stands for either "exhaustive case" or "error-checking case". Example: (SETQ X 1/3) (ECASE X (ALPHA (FOO)) (OMEGA (BAR))) Error: The value of X, 1/3, is neither ALPHA nor OMEGA. CCASE reference [clauses]* Special Form The syntax is the same as CASE, except that no OTHERWISE clause is permitted. The reference must be a generalized variable reference acceptable to SETF. If no clause is satisfied, CCASE signals an error with a message constructed from the clauses. Continuing from this error accepts a new value from the user, stores it into reference, and starts over, making the clause tests again. Subforms of reference may be evaluated multiple times. The name of this function stands for "continuable exhaustive case". - Issues I'd like to see opinions from everyone about how we should resolve these issues. Should the manual include some way to make WARN behave like CERROR (pause in the debugger after each warning)? There are three possible ways to do this: use TRACE, just as if WARN was any other function. [I realize that currently the portable subset of TRACE does not define a way to make a function pause into the debugger. It certainly ought to.] add a new special variable *BREAK-ON-WARNINGS* put this in as part of the future condition-handling system, which seems like where it really belongs. I'm willing to change the syntax of ASSERT to include some parentheses, e.g. around the references, if the use of the error message string as a delimiter is felt to be too untasteful. Note however that that would make it non-upward-compatible with the definition in the laser edition; I don't know whether that matters. Note that that would make the case of no references somewhat ugly. Should the following function exist? It's not clear how to define what it means in an implementation-independent way. I (Moon) don't feel that it should be put in to the portable language yet. ABORT-PROGRAM This function never returns. It throws out of the user's program and restores control to the Lisp system. (In the future, when Common Lisp includes error-handling mechanisms, it will also include a way to define to where this function, and the equivalent debugger command, transfers control.) [The Lisp machine calls this (SIGNAL 'SYS:ABORT), but very few programs do this explicitly. Probably no "user" programs do it.] In CHECK-TYPE, ASSERT, CTYPECASE, and CCASE, I have specified that subforms of the references may be evaluated multiple times. Would it be better to specify that they are always evaluated exactly once? This would be "more consistent" with SETF, but might present implementation difficulties. In ASSERT there is an efficiency issue, since you would like not to deal with anything but the test-form in the usual, no-error case; thus ASSERT shouldn't be required to evaluate the references and args if it doesn't signal an error. Furthermore, "the same" references presumably appear somewhere inside the test-form, or somewhere inside something it calls, so in fact the references would really be evaluated twice anyway. In CHECK-TYPE, CTYPECASE, and CCASE the naive user might plausibly expect subforms of the reference to be evaluated only once. It might not be a good idea to make ASSERT be inconsistent with the other three, though. I'm unsure what to do here. DEFTYPE should provide a way to specify the default description string, used when that type is the second subform of CHECK-TYPE and there is no third subform. Is this what the documentation string in DEFTYPE is for, or is that something else? - Possible future extensions We anticipate that some or all of the following will be added to Common Lisp in the future, when they are better understood. A "condition system" providing names for unusual conditions (including but not limited to errors) and a taxonomic system for classifying those names. Extension of FERROR, CERROR, and WARN so that if the first argument is a symbol, it is taken to be a condition name. In this case the format-string is the second argument. If no condition name is specified, a default condition name with no interesting properties is assumed. Ways to define the behavior and relationships of conditions. Ways to use conditions as inter-module interfaces. Ways to use conditions to customize the behavior of the interactive debugger. Ways to establish condition handlers, so that programs may respond to conditions, by throwing out, by continuing, or by correcting the reason for the condition and retrying. A way to trap errors without going into the debugger, within a certain dynamic scope. Portable debugger details, e.g. TRACE and BREAKON commands. Facilities making it possible for a user to write a portable debugger. Portable floating-point exception, overflow, and rounding control.  Received: from SAIL by SCORE with Pup; Sat 7 May 83 14:15:37-PDT Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 7 May 83 14:11:23 PDT Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Sat 7-May-83 17:10:36-EDT Date: Saturday, 7 May 1983, 17:09-EDT From: David A. Moon Subject: test message--please ignore To: Common-Lisp@su-ai This is a test to see whether this message will come back to me. You don't need to send me a message saying you got it.  Received: from SAIL by SCORE with Pup; Fri 6 May 83 17:46:24-PDT Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 6 May 83 17:41:28 PDT Received: ID ; 6 May 83 20:40:54 EDT Date: Fri, 6 May 1983 20:40 EDT From: Scott E. Fahlman To: common-lisp@SU-AI Subject: Package Proposal (moby message) This is a retry of an earlier mailing that apparently never made it through SU-AI. It has been generally agreed that it is important to have a workable Package system specified in the white pages, since packages play such a large role in the production of portable code. However, all of our past attempts to agree upon a package system have failed for one reason or another. Since the manual is to be finalized very soon, I thought that it might be worthwhile to make one last attempt to propose something that, maybe, we can all agree upon. Some amount of hill climbing on this proposal is certainly possible (if we climb quickly enough), but if we don't agree on something very soon, the first edition of the white pages will simply have to say that ":" is reserved for some future package system, ":symbol" is a self-evaluating keyword, and everything else is left unbound. That would be tragic. So if you feel compelled to raise objections, it would be very helpful if you could accompany such objections with a specific counter-proposal whenever possible. It would also be useful if people could refrain from trying to think up the most perverse and convoluted cases that might ever occur, and just concentrate on what you need to get useful work done. We can patch this chapter in later editions if need be, but right now the choices are to go for something simple and workable or to have nothing at all. Obviously, work cannot begin on a yellow-pages library until this has been resolved. Moon and Weinreb have persuaded me that we really do want some sort of runtime inheritance from one package to another -- a sort of deep binding -- and that our earlier attempt to fudge this issue by proposing a copying paradigm was misguided. So this proposal features inheritance, plus the concept of internal and external symbols that was introduced (in the context of Common Lisp) by Dave Dill. Also, I have come around to the view that a package name should be a string, not a symbol. This eliminates the issue of where the package name is interned. One final point: the system proposed here is intended only to solve the problem of developing and running code with modules written by many people. It is not intended to solve version-control problems, to ensure system integrity, or to provide Ada-like modules for separate compilation. All of those issues are important to the future of Lisp as a tool for building large systems -- worthy thesis topics -- but if we try to solve them here and now we will end up with no package system at all. Here it is, then: *************************************************************************** One problem with most Lisp systems is the use of a single name space for all symbols. In large Lisp systems, with modules written by many different programmers, accidental name collisions become a serious problem. In the past, this problem has been addressed by the use of a prefix on each symbol name in a module or by some sort of clumsy ``obarray'' switching to keep the names separated. Common Lisp addresses this problem through the @i[package system], derived from an earlier package system developed for Lisp Machine Lisp. The Common Lisp package system provides an @i[export] mechanism for easily dividing the symbols in a package into @i[external symbols], which are part of the package's public interface to other packages, and @[internal symbols], which are for internal use only and are normally hidden from other packages. A @i[package] is a data structure that establishes a mapping from print names (strings) to symbols. (The package thus replaces the ``oblist'' or ``obarray'' of earlier Lisp systems.) A symbol may appear in many packages, but will always have the same name. On the other hand, the same name may refer to different symbols in different packages. No two symbols in the same package may have the same name. Some of the symbols in a package are external and some are internal. The functions @b[export] and @b[unexport] move symbols from external to internal status within a package, respectively. Each package is named by a unique string. There is a single name space for packages. The name is usually assigned when the package is created. The function @b[find-package] translates a package-name into the associated package. The function @b[package-name] returns the name of a package. The package name may be changed with @b[setf] of @b[package-name]. (This is occasionally useful when, for development purposes, it is desirable to load two versions of a package into the same Lisp. We can load one, rename it, and then load the other, without getting a lot of name conflicts.) << The LispM package system has a much more complicated system for name-to-package translation, in effect providing a tree-structured directory of names. It seems to me that this much simpler scheme will suffice for our present needs. Does anyone have a counter-example that is not too contrived? I thought about adding some synonym machinery so that a package could go by several names, but this also seems to be more trouble than it is worth. Opinions? >> The value of the special variable @b[*package*] must always be a package object (not a name). This is referred to as the @i[current package]. When the Lisp reader has, by parsing, obtained a string of characters thought to name a symbol, that name is looked up in the current package. This lookup may involve looking in other packages whose external symbols are inherited by the current package (see below). If the name is found, the corresponding symbol is returned. If the name is not found, a new symbol is created for it and is placed in the current package as an internal symbol; if the name is seen again while this same package is current, the same symbol will then be returned. When a new symbol is created, a pointer to the package in which it is initially placed is stored in the @i[package cell] of that symbol; the package is said to be the symbol's @i[home package], and is said to @i[own] the symbol. (Some symbols are not owned by any package; they are said to be @i[uninterned].) Often it is desirable, when typing an expression to be read by the Lisp reader, to refer to a symbol in some package other than the current one. This is done through the use of a @i[qualified name], which consists of the package name, followed by a colon, followed by the print name of the symbol. This causes the symbol's name to be looked up in the specified package, rather than in the current one. For example, ``@b[editor:buffer]'' refers to the symbol named ``@b[buffer]'' in the package named ``@b[editor]'', regardless of whether there is a symbol named ``@f[buffer]'' in the current package. If ``@b[buffer]'' does not exist in package ``@b[editor]'', it is created there as a new internal symbol. (If, on the other hand, there is no package named ``@b[editor]'', an error is signalled.) The package named @b[keyword] contains all keyword symbols used by the Lisp system itself and by user-written code. Such symbols must be easily accessible from any package, and name conflicts are not an issue since these symbols are used only to label arguments and never to carry package-specific values or properties. Because keyword symbols are used so frequently, Common Lisp permits ``@b[keyword:foo]'' to be abbreviated to simply ``@b[:foo]''. The @b[keyword] package is also treated specially in that whenever a symbol is added to the @b[keyword] package, the symbol is automatically declared to be a constant and is made to have itself as its value. This is why every keyword evaluates to itself. All other uses of colons within names of symbols are not defined by Common Lisp, but are reserved for implementation-dependent use; this includes names that end in a colon, contain two or more colons, or consist of just a colon. Symbols from another package may be added to the current package in two ways. First, one or more individual symbols may be added to the current package by use of the @b[import] function. The form @b[(import 'editor:buffer)] takes the symbol named @b[buffer] in the @b[editor] package (this symbol was located when the form was read by the Lisp reader) and adds it to the current package as an internal symbol. The imported symbol is not automatically exported from the current package, but if it is already present and external, that is not changed. After the call to @i[import] it is possible to refer to @b[buffer] in the current package without any qualifier. The status of @b[buffer] in the package named @b[editor] is unchanged, and @b[editor] remains the home package for this symbol. If the imported symbol already exists in the current package, this operation effectively does nothing. If a distinct symbol with the name @b[buffer] already exists in the current package, a correctable error is signalled. The user will be offered a choice of whether or not the importation of this symbol is to go forward. << Or should we just let it happen? >> The second mechanism, the @b[inherit-package] function, causes the current package to inherit all of the @b[external] symbols of some other package. These symbols can then be referred to from the current package without a qualifier, and they in effect become external symbols of the current package, passed along to any other package that inherits the current one. There is no way to inherit the @i[internal] symbols in another package; to refer to an internal symbol, you must either make that symbol's home package current or use a qualifier. When a package is created, it is given an initial list of ancestors, usually including at least the @b[lisp] package. @b[Inherit-package] adds a new package to the end of this list, if that package is not already present. @b[Uninherit-package] removes a package from the list. The @b[package-ancestors] function returns this list for a given package. << No convenient way is provided to reorder the list of ancestors. Can anyone think of a good reason why this would be needed? I can't. >> When a name N is being looked up in package X, the system first searches for N among the internal and external symbols of X itself. Then, it searches the ancestor packages of of X in the order they appear on the ancestor-list of X, but this search only succeeds if X is found as an @i[external] symbol. The search is depth-first: if the first ancestor of X is Y, then the search of Y will include a search of Y's ancestors, and so on. The first occurrence of N along this search path is the one that is returned. The system remembers which packages have been visited in a given search and does not search them a second time. In addition to being more efficient, this makes it possible to have cycles in the tree, as when two packages wish to inherit from one another; each would see its own symbols first, and then its partner's. << That sounds more complicated than it is. We need to be able to declare multiple ancestors for a given package, and there has to be SOME determinate order in which the search occurs. It is probably better to let the set of packages searched be determined at runtime, by following chains of ancestors, than to wire it into each package for the same reason that inheritance is better than copying semantics: something up in the tree of superiors might change at runtime. With a bit of care and some back-pointers, the search path for a package can be pre-computed once and can then be corrected if anything changes up in the tree of superiors, but we don't need to explain this to the users. I envision the internal and external symbols as residing in two separate hash-tables within each package structure. >> Each symbol contains a package slot that is used to record the home package of the symbol. When the symbol is printed, if it is in the keyword package then it is printed with a preceding colon; otherwise, if it is present (directly or by inheritance) in the current package, it is printed without any qualification; otherwise, it is printed with the name of the home package as the qualifier. A symbol that is uninterned (has no home package) is printed preceded by ``@b[#:]''. It is possible, by the clever use of import and unintern, to create a symbol that appears to be uninterned but that in fact is interned in some package. The system does not check for this. @Section[Built-in Packages] The following packages are built into the Common Lisp system: @begin[description] @b[lisp]@\The package named @b[lisp] contains the primitives of the Common Lisp system. Its external symbols include all of the user-visible functions and global variables that are present in the Common Lisp system, such as @b[car], @b[cdr], @b[*package*], etc. Almost all other packages will want to inherit @b[lisp] so that these symbols are available without qualification. @b[user]@\The @b[user] package is, by default, the current package at the time a Common Lisp system starts up. This package inherits the @b[lisp] package. @b[keyword]@\This package contains all of the keywords used by built-in or user-defined Lisp functions. Symbols that start with a colon are treated as if they started with "keyword:" instead. All symbols in this package are treated as constants that evaluate to themselves, so the user can type @b[:foo] instead of @b[':foo]. @b[si]@\This package name is reserved to the implementation. (The name is an abbreviation for ``system internals''.) Normally this is used to contain names of internal and implementation-dependent functions. << Note, however, that most of the things traditionally found in SI: are now internal symbols in the LISP: package. Is it worth preserving SI: ? >> @end[description] @Section[Package System Functions and Variables] @Defvar[Var {package}] The value of this variable must be either a package or a symbol that names a package; this package is said to be the current package. The initial value of @b[*package*] is the @b[user] package. The @b[load] function rebinds @b[*package*] to its current value. If some form in the file changes the value of @b[*package*] during loading, the old value will be restored when the loading is completed. @Enddefvar @Defun[Fun {make-package}, Args {@i[package-name] @optional @i[ancestor-list]}] Creates and returns a new package with the specified package name. The @i[package-name] must be a string that does not currently name a package. If a package of this name already exists, a correctable error is signalled. The @i[ancestors-list] argument is a list of packages or package names whose external symbols are to be inherited by the new package. If not supplied, this defaults to one ancestor, the @b[lisp] package. @Enddefun @Defun[Fun {in-package}, Args {@i[package-name] @optional @i[ancestor-list]}] The @b[in-package] function is intended to be placed at the start of a file containing a subsystem that is to be loaded into some package other than @b[user]. It is similar in function to @b[make-package], except that after the new package is created, the @b[*package*] variable is bound to it. This binding will remain in force until changed by the user (perhaps with another @b[in-package] call), or until the @b[*package*] variable reverts to its old value at the completion of a @b[load] operation. If a package of the same name already exists, it is assumed that @b[in-package] merely wants to augment the existing package. That package becomes the current one. The new ancestor list is merged with the old one (any new ancestors are added at the end) and any new shadow symbols are interned in the current package. @Enddefun @Defun[Fun {find-package}, Args {@i[name]}] The @b[name] must be a string. Returns the corresponding package, or NIL if no such package exists. @Enddefun @Defun[Fun {package-name}, Args {@i[package]}] The argument must be a package. This function returns the string that names that package. @b[Setf] may be used with @b[package-name] to rename the package. The new name must be a string that does not currently name a package. @Enddefun @Defun[Fun {ancestors-list}, Args {@i[package]}] The argument must be a package. This function returns that package's list of ancestor packages. @Enddefun @Defun[Fun {list-packages}, Args {}] This function returns a list of all packages that currently exist. @Enddefun @Defun[Fun {intern}, Args {@i[string] @optional @i[package]}] The @b[package] argument defaults to the current package. It is searched for a symbol with the name specified by the @b[string] argument. This search will include inherited symbols, as described above. If a symbol with the specified name is found, it is returned. If no such symbol is found, one is created and is installed in the current package as an internal symbol. This symbol is returned. @Enddefun @Defun[Fun {find-symbol}, Args {@i[string] @optional @i[package]}] This is identical to @b[intern], but it never creates a new symbol. If a symbol with the specified name is found in the current package, directly or by inheritance, the symbol found is returned. The second return value is T, indicating that the symbol was found. The third value is T if the symbol is an external symbol in the specified package, NIL otherwise. If the symbol is not found in the specified package, @b[find-symbol] returns NIL for all three values. @Enddefun @Defun[Fun {unintern}, Args {@i[symbol] @optional @i[package]}] If the specified symbol is present in the specified package, it is removed from this package. Moreover, if @i[package] is the home package for the symbol, the symbol is made to have no home package. The @i[package] defaults to the current package. @b[unintern] returns T if it actually removed a symbol, and NIL otherwise. @Incompatibility{The equivalent of this in @maclisp is @f[remob].} @Enddefun @Defun[Fun {export}, Args {@i[symbols]}] The argument should be a list of symbols, or possibly a single symbol. These symbols become external symbols in the current package, and are therefore visible to any other package that imports the current one. If a specified symbol is already an external symbol in @i[package], it is unaffected. @f[export] returns @true. By convention, a call to @f[export] listing all exported symbols is placed near the start of a file to advertise which of the symbols used mentioned the file are intended to be used by other programs. @Enddefun @Defun[Fun {unexport}, Args {@i[symbols]}] The argument should be a list of symbols, or possibly a single symbol. Any specified symbols that is an external symbol in the current package is made to be an internal symbol instead. Otherwise, it is unaffected. @f[unexport] returns @true. @Enddefun @Defun[Fun {import}, Args {@i[symbols]}] The argument should be a list of symbols, or possibly a single symbol. These symbols become internal symbols in the current package, and can therefore be referred to without a colon qualifier. @f[import] returns @true. @Enddefun @Defun[Fun {shadow}, Args {@i[symbols]}] The argument should be a list of strings, or possibly a single string. For each specified name, the current package is examined. If a symbol with that name is present in this package (directly, not by inheritance) then nothing is done. Otherwise such a symbol is created and is inserted in the current package as an internal symbol. This shadows any symbol of the same name that would otherwise be inherited by the current package. @f[shadow] returns @true. @Enddefun @Defun[Fun {inherit-package}, Args {@i[packages]}] The argument should be a list of packages or package names, or possibly a single package or package name. These packages are added to the end of the current package's list of ancestors if they are not already present in this list. This means that all external symbols in the inherited packages effectively become external symbols in the current package. Returns T. @enddefun @Defun[Fun {uninherit-package}, Args {@i[packages]}] The argument should be a list of packages or package names, or possibly a single package or package name. These packages are removed from the current package's list of ancestors. Returns T. @enddefun @Defmac[Fun {do-symbols}, Args {(@i[var] @Mopt<@i[package]> @Mopt<@i[result-form]>) @Mstar<@i[declaration]> @mstar<@i[tag] @mor @i[statement]>}] @f[do-symbols] provides straightforward iteration over the symbols of a package. The body is performed once for each symbol visible in the @i[package], in no particular order, with the variable @i[var] bound to the symbol. This includes internal symbols, external symbols, and symbols inheritied by this package from it ancestors. Then @i[resultform] (a single form, @i[not] an implicit @f[progn]) is evaluated, and the result is the value of the @f[do-symbols] form. (When the @i[resultform] is evaluated, the control variable @i[var] is still bound, and has the value @nil.) If @i[resultform] is omitted, the result is @false. @Funref[return] may be used to terminate the iteration prematurely. If execution of the body affects which symbols are contained in the @i[package], other than possibly to remove the symbol currently the value of @i[var] by using @Funref[unintern], the effects are unpredictable. @Enddefmac @Defmac[Fun {do-all-symbols}, Args {(@i[var] @Mopt<@i[result-form]>) @Mstar<@i[declaration]> @mstar<@i[tag] @mor @i[statement]>}] This is similar to @f[do-symbols], but executes the body once for every symbol contained in ``every'' package. (This may not get all symbols whatsoever, depending on the implementation.) It is @i[not] in general the case that each symbol is processed only once, since a symbol may appear in many packages. @Enddefmac  Received: from SAIL by SCORE with Pup; Fri 6 May 83 13:14:59-PDT Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 6 May 83 13:10:45 PDT Received: ID ; 6 May 83 16:10:24 EDT Date: 6 May 1983 16:10 EDT (Fri) From: Feinberg@CMU-CS-C To: Richard P. Gabriel Subject: Testing, one two... Cc: common-lisp@SU-AI In-reply-to: Msg of 6 May 1983 15:42 EDT from Richard P. Gabriel Howdy! Date: 6 May 1983 15:42 EDT From: Richard P. Gabriel To: common-lisp at SU-AI Received: from SU-SCORE by CMU-CS-C (with SMTP); 6 May 83 16:00:30 EDT Received: from SAIL by SCORE with Pup; Fri 6 May 83 13:02:03-PDT Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 6 May 83 12:57:17 PDT Received: from MIT-MC by USC-ECL; Fri 6 May 83 12:53:53-PDT This is a second test of the Common Lisp mailing list. If you receive this message, send a message to RPG@SAIL stating you got message number 2. Thanks. -rpg- Receiving loud and clear.  Received: from SAIL by SCORE with Pup; Fri 6 May 83 13:01:25-PDT Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 6 May 83 12:57:17 PDT Received: from MIT-MC by USC-ECL; Fri 6 May 83 12:53:53-PDT Date: 6 May 1983 15:42 EDT From: Richard P. Gabriel To: common-lisp @ SU-AI This is a second test of the Common Lisp mailing list. If you receive this message, send a message to RPG@SAIL stating you got message number 2. Thanks. -rpg-  Received: from SAIL by SCORE with Pup; Fri 6 May 83 12:34:28-PDT Date: 06 May 83 1229 PDT From: Dick Gabriel Subject: Test To: common-lisp%SU-AI@SU-SCORE This is a test of the Common Lisp Mailing List. Please send a confirming message to RPG@SAIL if you receive this message. -rpg-  Mail-from: ARPANET site SU-AI rcvd at 29-Apr-83 1413-PDT Received: from USC-ECL by SU-AI with NCP/FTP; 29 Apr 83 14:11:00 PDT Received: from MIT-MC by USC-ECL; Fri 29 Apr 83 14:10:53-PDT Received: from SCRC-BORZOI by SCRC-TENEX with CHAOS; Fri 29-Apr-83 17:11:30-EDT Date: Friday, 29 April 1983, 17:08-EDT From: Bernard S. Greenberg Subject: MISMATCH, From end. To: common-lisp%su-ai@usc-ecl Cc: common-lisp-implementors%SCRC-TENEX@MIT-MC About MISMATCH, with :from-end elected. I'd like to know what (mismatch "able" "table" :from-end t) returns. The second MISMATCH paragraph in the Laser manual says explicitly an index into sequence1 is returned. The sequences are not of the same length and content, so the answer isn't NIL. The "-rightmost- position at which the sequences differ" is -1, a totally useless result. This cannot be right. Is this right? Or is the answer NIL, or as I surmise, is this definition wrong? I think that the :from-end result should be 1+ what it is defined in the manual to be consistent with everything else. (mismatch "fubar" "foobar" :from-end t) should be 2, the number of elements skipped in sequence1, or the index of the beginning of the matching substring. The manual's answer of 1 seems very very peculiar. Suppose I wanted to use this to implement a (what a crazy idea!) text editor in Lisp. I would use this function to control Insert/Delete chars. I would use (mismatch :from-end nil) to position the cursor. Then (mismatch :from-end t) to give me a count (subtracting current position) of characters to delete, delete them and insert the new characters. This arithmetic is correct only if the definition of (mismatch :from-end) is corrected as I advise. This argues for its correctness.  Mail-from: ARPANET site SU-AI rcvd at 28-Apr-83 1659-PDT Received: from USC-ECL by SU-AI with NCP/FTP; 28 Apr 83 16:57:26 PDT Received: from MIT-XX by USC-ECL; Thu 28 Apr 83 16:55:50-PDT Date: Thursday, 28 April 1983, 16:42-PDT From: BENSON at SPA-NIMBUS Subject: Bugs in the Laser Edition To: Common-Lisp%su-ai at USC-ECL Here are some minor bugs (and fixes) from the Laser Edition. Most of these are just internal inconsistencies or things that should have been flushed from previous editions. There is also a serious problem which I am preparing a note about, which will require some significant changes (there is no easy way around it). This relates to what is legal as the first argument to FUNCALL or APPLY, what SYMBOL-FUNCTION returns, etc. I think it will be necessary to be more explicit about what lexical environments are, rather than the hand-waving "implementation dependent" copout. -- Chapter 3, p.28 The program example (DEFUN COMPOSE (F G) #'(LAMBDA (X) (F (G X)))) should be changed to (DEFUN COMPOSE (F G) #'(LAMBDA (X) (FUNCALL F (FUNCALL G X)))) (The author apparently thought he was writing an example of Scheme!) -- Chapter 3, p.29 The term "exit point" needs some clarification. The sentence An exit point established by a BLOCK (page 79) construct has lexical scope and dynamic extent. could be changed to An exit point established by a BLOCK (page 79) construct and referenced by RETURN (page 79) or RETURN-FROM (page 79) has lexical scope and dynamic extent. -- Section 5.3.3, p.49 The word "situation" in the first line of the description of EVAL-WHEN should be in italics, not Helvetica. -- Section 6.4, pp.58,59; Section 7.6, p.77 The special forms AND, OR and IF are defined in terms of COND. This may be considered inappropriate since COND has now been defined to be a macro rather than a special form. It might be more appropriate to define COND, AND and OR in terms of IF. -- Section 7.1.2, p.65 FSET should be flushed with all the other update functions, in favor of (SETF (SYMBOL-FUNCTION x) y). The word FSET could easily be confused with SETF. -- Section 7.10, p.93 CATCH-ALL is sometimes spelled CATCHALL in its description. -- Section 9.2, p.103 It should be mentioned in the description of the SPECIAL declaration form that DEFVAR is the recommended way of declaring a special variable. -- Section 10.1, p.109 PUTF should be flushed, since (SETF (GETF x y) z) works equally well. -- Chapter 16, p.189 All references to PUTHASH in the introduction to this chapter should be changed to (SETF (GETHASH x y) z). PUTHASH has already been flushed. -- Section 17.2, p.195 There is a reference to STRING<> in the description of STRING-NOT-EQUAL, which should be changed to STRING/=. -- Section 18.5, p.207; Section 21.1.6, p.241 The DEFSTRUCT description refers to a :PRINT-FUNCTION option, while the PRINT description refers to a :PRINTER option for DESTRUCT. One of these should be changed to the other. It should be stated in both sections what the default printed representation of a structure is, if this option is not specified. There should be a way to specify the #S(...) reader macro syntax as the printed representation without having to "do it by hand." -- Section 21.3.1, p.248 A minor point: PPRINT probably should not return its argument, in order to be useful when called from a READ-EVAL-PRINT loop. Otherwise the prettyprinted form tends to get scrolled off the screen by the "standard" printed return value. This recommendation is made on the basis of practical experience! Have it return T or NIL or some other benign object instead. -- Section 24.1, p.289 In the first paragraph of the description of the COMPILE function, the term "lambda expression or select expression" is used. This should be changed to just "lambda expression," since select expressions have been flushed.  Mail-from: ARPANET site SU-AI rcvd at 27-Apr-83 2058-PDT Received: from USC-ECL by SU-AI with NCP/FTP; 27 Apr 83 20:55:55 PDT Received: from MIT-MC by USC-ECL; Wed 27 Apr 83 19:08:41-PDT Date: 27 April 1983 15:30 EDT From: Kent M. Pitman To: MMcM @ SCRC-TENEX cc: Common-Lisp @ SU-AI The T dialect has a family of special forms called things like CASE, SELECT, etc. and a related family called XCASE, XSELECT, etc. meaning "exhaustive". I suggest that Common-Lisp could adopt a similar convention. (XSELECTQ FOO ..forms..) would be like (SELECTQ FOO ..forms.. (OTHERWISE ..error..)) Is this what you're looking for?  Mail-from: ARPANET site SU-AI rcvd at 27-Apr-83 1010-PDT Received: from USC-ECL by SU-AI with NCP/FTP; 27 Apr 83 10:09:37 PDT Received: from MIT-MC by USC-ECL; Wed 27 Apr 83 10:07:31-PDT Received: from SCRC-COLLIE by SCRC-TENEX with CHAOS; Wed 27-Apr-83 13:06:40-EDT Date: Wednesday, 27 April 1983, 13:04-EDT From: Mike McMahon Subject: Erring forms of ...CASE... To: common-lisp%SU-AI@usc-ecl I need a naming convention for a TYPECASE that automatically generates an OTHERWISE clause that gives a properly formatted error. This convention should be used for versions of other functions like CASE. Zetalisp calls this function ARGUMENT-TYPECASE. Other suggestions I have received are TYPECASE* TYPECASE-OR-ERROR ETYPECASE CHECK-TYPECASE CHECK-TYPE-CASE ERROR-TYPE-CASE Needless to say, I am seeking better ideas.  Mail-from: ARPANET site SU-AI rcvd at 26-Apr-83 0949-PDT Received: from USC-ECL by SU-AI with NCP/FTP; 26 Apr 83 09:47:29 PDT Received: from MIT-MC by USC-ECL; Tue 26 Apr 83 09:43:57-PDT Received: from SCRC-BULLDOG by SCRC-TENEX with CHAOS; Tue 26-Apr-83 12:00:51-EDT Date: Tuesday, 26 April 1983, 11:59-EDT From: Daniel L. Weinreb Subject: DEFSETF multiple-values feature To: common-lisp%sail@usc-ecl Moon and I have discussed Fahlman's proposal that the multiple-value hack in DEFSETF (used in the UNCONS example) should not be in Common Lisp. We agree that it should be removed from the language definition, with the proviso that the syntax of DEFSETF be kept the same as it is now so that if we change our minds later, we can put it back. We will proceed on the assumption that this will be accepted.  Mail-from: ARPANET site SU-AI rcvd at 23-Apr-83 2019-PST Received: from USC-ECL by SU-AI with NCP/FTP; 23 Apr 83 20:17:09 PST Received: from CMU-CS-C by USC-ECL; Sat 23 Apr 83 20:16:58-PST Received: ID ; 23 Apr 83 23:17:47 EST Date: Sat, 23 Apr 1983 23:17 EST From: Scott E. Fahlman To: common-lisp%su-ai@usc-ecl Subject: Lunar DEFSETF It took a while (and some clarifying) for me to understand Dave Moon's new DEFSETF proposal, but for the record I now believe that it is all necessary and that nothing simpler will cut it. Given the need for this much complexity, Moon's solution is elegant: even hard-core users will seldom have to deal directly with the general 5-value forms, since the simpler forms are handled automatically, but the escape hatch is there if they need it. So I endorse this proposal. I am still opposed to the inclusion of multiple new values, however. -- Scott  Mail-from: ARPANET site SU-AI rcvd at 23-Apr-83 1313-PST Received: from USC-ECL by SU-AI with NCP/FTP; 23 Apr 83 13:07:31 PST Received: from MIT-MULTICS by USC-ECL; Sat 23 Apr 83 13:05:29-PST Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Sat 23-Apr-83 16:05:47-EST Date: Saturday, 23 April 1983, 16:05-EST From: David A. Moon Subject: DEFSETF proposal, revised To: Common-Lisp%su-ai@usc-ecl This replaces the version I mailed out a few days ago. Some obscurities and Lisp-machine-specific things have been removed, and the English has been improved and clarified. Please let me know if there are any problems with this. The DEFSETF documented in the Laser edition is deficient in several respects. The UNCONS example (about as obscure as one can get!) fails to agree with the English. The manual is inconsistent about who is responsible for ensuring proper order of evaluation. It doesn't seem to be possible to write the DEFSETF for LDB; ignoring order of evaluation and returned-value issues, (SETF (LDB x y) z) turns into (SETF y (DPB z x y)); note how the "y" argument is used as both an "Lvalue" and an "Rvalue". This DEFSETF similarly gives no help in implementing such macros as INCF, SHIFTF, and PUSH, which take a place that is both read and written. The function generated by DEFSETF doesn't have a portable name, so the user may not know how to trace and otherwise debug it. (This is best attributed to the omission of function specs from Common Lisp, so I won't mention it again.) I would like to propose a modified form of DEFSETF: There are three forms of DEFSETF, rather than the two in the Laser manual. This helps a lot. The body of DEFSETF is in charge of making sure that the right value is returned. In most cases, this works simply by calling a storing function that is guaranteed to return the right value. The SETF system is in charge of evaluating the evaluatable subforms of the SETF (or other) special form in left-to-right order, and once each (no more and no less), or generating code whose effect is equivalent to that. It is aided in this by some information supplied by the body of the DEFSETF. A DEFSETF defines the "SETF method" for generalized-variable forms with a certain symbol in the car. (The use of the word "method" here has nothing to do with message-passing or flavors.) The underlying theory is that the SETF method for a given form can be expressed as five values: - a list of temporary variables - a list of values to bind them to (subforms of the given form) - a second list of temporary variables ("store variables") - a storing form - an accessing form The store variables are to be bound to the values of the form to be stored. In almost all cases we store single values and there is only one store variable. The storing form and the accessing form can be evaluated any number of times, inside the bindings of the temporary variables (and of the store variables, in the case of the storing form). The accessing form returns the value of the generalized variable. The storing form modifies the value of the generalized variable, and guarantees to return the store variable(s) as its value(s); these are the correct values for SETF, INCF, etc. to return. The value returned by the accessing form is (of course) affected by execution of the storing form. The temporary variables and the store variables are gensyms in all cases, so that there is never any issue of name clashes with them. This is necessary to make the special forms that do multiple setfs in parallel work properly; these are PSETF, SHIFTF, and ROTATEF. Computation of the SETF method must always cons new gensyms. To give some examples: - for a variable X () () (G0001) (SETQ X G0001) X - for (CAR exp) (G0001) (exp) (G0002) (RPLACA2 G0001 G0002) (CAR G0001) where RPLACA2 is assumed to be a version of RPLACA that returns its second argument. I guess &OPTIONAL and &REST should be allowed in the store variables, if we want to keep the features involving them that are in the Laser edition DEFSETF. I don't currently support this. SETF methods are defined via DEFSETF. There are three forms of DEFSETF. - the trivial form (DEFSETF access-function storing-function [documentation]) The storing-function takes the same arguments as the access-function, plus one additional argument, which is the value to store, and returns that as its value. Example: (DEFSETF SYMBOL-VALUE SET) - the functional form (DEFSETF access-function (args...) (store-variables...) [documentation] body...) The access-function is truly a function and evaluates its arguments. Furthermore a SETF reference evaluates all the arguments (i.e. this is not a "destructuring" case). Args are the lambda-list for the access-function; &OPTIONAL and &REST are permitted. Optional args may have defaults, although many cases that need them may prefer to use the general form (below). A DEFSETF of this form expands into code to return the five SETF-method values, including creating gensym temporary variables and gensym store variables. The list of values to bind the temporary variables to is simply the cdr of the reference, except when there are optional arguments in which case code is generated to plug in the default values as required. The accessing form is access-function applied to the temporary variables. The result of evaluating the body is the storing form. During the evaluation of the body, the variables in args and in store-variables will be bound to the corresponding gensyms. The gensyms will in turn be bound to the arguments to the access function, and the values being stored, at run time. Example: (DEFSETF SUBSEQ (SEQUENCE START &OPTIONAL END) (NEW-SEQUENCE) `(PROGN (REPLACE ,SEQUENCE ,NEW-SEQUENCE :START1 ,START :END1 ,END) ,NEW-SEQUENCE)) Note how in the functional form most of the "hair" required to evaluate things in the correct order is taken care of by DEFSETF and SETF, and the user need merely write a simple backquote specifying what is to be done. - the general form (DEFINE-SETF-METHOD access-function (subforms...) [documentation] body...) The result of evaluating the body must be five values, as documented above. The subforms variables are bound to a destructuring of the cdr of the reference, just as in DEFMACRO. Note that the general case differs from the functional case in that while the body is being executed the general case's subforms pattern is bound to parts of the reference form, whereas the functional case's args pattern is bound to gensyms. I gave this a separate name rather than kludging up DEFSETF's syntax somehow with an extra level of parentheses or something. It's reasonable for this to have a longer name since it is more low-level. Example: (Sorry, there are by definition no small examples of this.) (DEFINE-SETF-METHOD LDB (BYTE WORD) (MULTIPLE-VALUE-BIND (WORD-TEMPS WORD-VALS WORD-STORES WORD-STORE-FORM WORD-ACCESS-FORM) (GET-SETF-METHOD-1 WORD) ;Find out how to access WORD (LET ((BTEMP (GENSYM)) ;Temporary variable for byte specifier (STORE (GENSYM)) ;Temporary variable for byte to store (WORD (FIRST WORD-STORES))) ;Temporary variable for word to store (VALUES (CONS BTEMP WORD-TEMPS) (CONS BYTE WORD-VALS) (LIST STORE) `(LDB ,BTEMP ;To preserve value, assume optimizable out (LET ((,WORD (DPB ,STORE ,BTEMP ,WORD-ACCESS-FORM))) ,WORD-STORE-FORM)) `(LDB ,BTEMP ,WORD-ACCESS-FORM))))) GET-SETF-METHOD-1 gets the SETF-method values for a form, dealing with all macro-expansion and error-checking issues. In addition it complains if there isn't exactly one store variable. Like most SETF'able things, LDB deals with single values only, not multiple values. Another thing that is useful is DEFINE-MODIFY-MACRO name (args) function [documentation] where args may contain &OPTIONAL and &REST, and the expansion is like the following except that it has correct semantics: (DEFMACRO name (location args...) `(SETF ,location (function ,location ,args...))) Example: (DEFINE-MODIFY-MACRO INCF (&OPTIONAL (DELTA 1)) +) I anticipate that users will want to define many more of these in addition to the mere two that Common Lisp has built in. It would of course be a loss if it was too hard for users to define modify macros that follow proper order of evaluation semantics, so that they end up defining inferior ones. I have needed the following, for example: (DEFINE-MODIFY-MACRO UNIONF (OTHER-SET) UNION) A good test case for whether your SETF system works properly is to try macro-expanding (INCF (LDB FOO BAR)); if it doesn't generate a SETQ of BAR, it isn't right. This exercises most of the complexity, except for multiple values. Thanks to Alan Bawden for explaining the underlying theory of the five values to me. By the way, this is all implemented and works. The code is optimized, removing any temporary-variable bindings that are not actually necessary, using code-analysis tools that I intend to offer as a yellow-pages package once I have rewritten them to be portable. Some implementations may have smart enough compilers that they don't need this, possibly. The new LOOP will depend on some of these tools also.  Mail-from: ARPANET site SU-AI rcvd at 22-Apr-83 2121-PST Received: from USC-ECL by SU-AI with NCP/FTP; 22 Apr 83 21:18:53 PST Received: from MIT-MC by USC-ECL; Fri 22 Apr 83 21:17:24-PST Received: from SCRC-BORZOI by SCRC-TENEX with CHAOS; Sat 23-Apr-83 00:00:28-EST Date: Saturday, 23 April 1983, 00:00-EST From: David A. Moon Subject: Proposed improvement to ASSERT To: Common-Lisp%su-ai@usc-ecl In going to implement ASSERT, we found that there is a problem with it. The Laser manual says that "if the handler corrects the error, then the test is re-evaluated." However, there is no reasonable way for the handler to correct the error, because there is no explicit specification of what variables the test depends on, i.e. what variables the handler should change the values of in order to correct the error and cause the test to return true. A good way to think about this is to consider ASSERT as a generalization of CHECK-TYPE. CHECK-TYPE makes a data-type test on one variable; ASSERT makes any kind of test on any number of variables. The proposed improvement is to make the syntax for ASSERT include any number of variables whose values may be altered in order to correct the error. As with CHECK-TYPE, we allow the variables actually to be any reference that SETF understands. Any other variables that the test depends on would be parameters that are not considered adjustable. This improvement can be made in a nearly upward-compatible way: ASSERT test-form [reference]* [string [args]*] The first subform of the ASSERT special form (macro) is a test form; if it evaluates to true, ASSERT returns; if it evaluates to false, an error is signalled using the rest of the subforms. Only in the error case are the rest of the subforms evaluated. If the error is "corrected", ASSERT starts over at the beginning, evaluating the test form again. The remaining subforms, which are all optional, consist of any number of references to adjustable variables, an error message string, and any number of message-arguments. The string is not evaluated and serves as a delimiter between the references and the message-arguments. FORMAT is used with the string and the message-arguments to construct an error message. If the string is omitted, a default message such as "Assertion failed" is used; in this case there must necessarily be no message-arguments. The handler of the error has the ability to see and to change the values of the adjustable variable references, in an implementation-dependent way. It is permissible to have no references; in this case the error may be uncorrectable, depending on the implementation. Examples: (ASSERT (VALVE-CLOSED-P V1) "Live steam is escaping!") (ASSERT (VALVE-CLOSED-P V1) (VALVE-MANUAL-CONTROL V1) "Live steam is escaping!") (ASSERT (<= MINBASE BASE MAXBASE) BASE "Base ~D is out of the range ~D-~D" BASE MINBASE MAXBASE) (ASSERT (= (ARRAY-DIMENSION A 1) (ARRAY-DIMENSION B 0)) A B "The matrix multiplication ~S x ~S cannot be performed" A B)  Mail-from: ARPANET site SU-AI rcvd at 22-Apr-83 2034-PST Received: from USC-ECL by SU-AI with NCP/FTP; 22 Apr 83 20:30:14 PST Received: from CMU-CS-C by USC-ECL; Fri 22 Apr 83 19:05:56-PST Received: ID ; 22 Apr 83 21:30:38 EST Date: Fri, 22 Apr 1983 21:30 EST From: Leonard N. Zubkoff To: Skef Wholey Cc: Bernard S. Greenberg , Common-Lisp%SU-AI@USC-ECL Subject: MISMATCH/MAXPREFIX/MAXSUFFIX In-reply-to: Msg of 22 Apr 1983 16:19-EST from Skef Wholey As I recall, I requested the MAXPREFIX and MAXSUFFIX functions since there appeared to be no other way of getting the functionality without explicitly writing a loop (I don't believe MISMATCH existed at the time). Since MISMATCH can be used to compute the prefix lengths and suffix lengths, I see no further need for MAXPREFIX and MAXSUFFIX. Leonard  Mail-from: ARPANET site SU-AI rcvd at 22-Apr-83 1334-PST Received: from USC-ECL by SU-AI with NCP/FTP; 22 Apr 83 13:22:45 PST Received: from CMU-CS-C by USC-ECL; Fri 22 Apr 83 13:20:43-PST Received: ID ; 22 Apr 83 16:19:52 EST Date: Fri, 22 Apr 1983 16:19 EST From: Skef Wholey To: Common-Lisp%SU-AI@USC-ECL CC: Bernard S. Greenberg Subject: MISMATCH/MAXPREFIX/MAXSUFFIX In-reply-to: Msg of 22 Apr 1983 09:20-EST from Bernard S. Greenberg Having implemented these losers several times (as the manual changed in creative ways), I'd be overjoyed to see them flushed forever. Leonard Zubkoff told me that he suggested them to Guy as functions one might use in an editor's redisplay. The editor Rob MacLachlan and I are writing have not used these things at all -- the amount of time it takes to decide which function with which keywords to use, and what the value returned means is far greater than the time it takes to write a loop that does exactly the right thing (but this is a different problem). I can understand REMOVE, DELETE, MEMBER, and REDUCE being generic sequence functions, but if MAXPREFIX and MAXSUFFIX aren't flushed, perhaps they should be made into string-only functions.  Mail-from: ARPANET site SU-AI rcvd at 22-Apr-83 0636-PST Received: from USC-ECL by SU-AI with NCP/FTP; 22 Apr 83 06:35:09 PST Received: from MIT-MC by USC-ECL; Fri 22 Apr 83 06:31:42-PST Received: from SCRC-BORZOI by SCRC-TENEX with CHAOS; Fri 22-Apr-83 09:24:34-EST Date: Friday, 22 April 1983, 09:20-EST From: Bernard S. Greenberg Subject: MISMATCH/MAXPREFIX/MAXSUFFIX To: common-lisp%su-ai@usc-ecl It appears to me that MISMATCH and MAXPREFIX/MAXSUFFIX overlap entirely in capability and intent. They appear to do the exact same thing, modulo returning nil instead of the sequence length or zero in the all-match case. It is furthermore not in the least clear to me what :from-end means to MAXSUFFIX, or how MAXPREFIX with :from-end is different from MAXSUFFIX. Is there any reason not to flush MAXPREFIX and MAXSUFFIX?  Mail-from: ARPANET site SU-AI rcvd at 21-Apr-83 1313-PST Received: from USC-ECL by SU-AI with NCP/FTP; 21 Apr 83 13:11:16 PST Received: from MIT-ML by USC-ECL; Thu 21 Apr 83 13:10:49-PST Date: Thursday, 21 April 1983, 12:59-PST From: BENSON at SPA-Nimbus Subject: *prindepth* and *prinlength* versus *prinarray* To: dlw%SCRC-TENEX at MIT-ML, common-lisp%sail at usc-ecl In-reply-to: The message of 21 Apr 83 07:47-PST from Daniel L. Weinreb Yes, it appears that printing of arrays respects *prinlevel* and *prinlength*. This should be made clearer in the manual. Also, it should be made clear that strings and bit-vectors are not affected by *prinlength*; that is, they will not be truncated. I presume this is the behavior everyone expects? A case could be made for truncating bit-vectors (the ... is a bit strange in this case, where does it go?), but truncating strings would remove too much human-readable information. Also, if strings are truncated, symbols probably should be also!  Mail-from: ARPANET site SU-AI rcvd at 21-Apr-83 1046-PST Received: from USC-ECL by SU-AI with NCP/FTP; 21 Apr 83 10:44:26 PST Received: from MIT-ML by USC-ECL; Thu 21 Apr 83 08:04:45-PST Received: from SCRC-BEAGLE by SCRC-TENEX with CHAOS; Thu 21-Apr-83 10:45:59-EST Date: Thursday, 21 April 1983, 10:47-EST From: Daniel L. Weinreb Subject: *prindepth* and *prinlength* versus *prinarray* To: common-lisp%sail@usc-ecl While hacking the printer, I wondered: if *prinarray* is non-NIL, and *prindepth* and/or *prinlength* is being used, does the printing of vectors and arrays respect these limits? If you look at the very last example under *prinlevel*, you see a case where the answer is yes, but you have to look hard for it. I'd appreciate if the manual were changed to be more explicit about this. By the way, the manual would also benefit from a few more examples of backquote, particularly one or two cases using `#( ... ). Very simple examples would be fine.  Mail-from: ARPANET site SU-AI rcvd at 20-Apr-83 2116-PST Received: from USC-ECL by SU-AI with NCP/FTP; 20 Apr 83 20:56:08 PST Received: from CMU-CS-C by USC-ECL; Wed 20 Apr 83 20:53:03-PST Received: ID ; 20 Apr 83 23:53:46 EST Date: Wed, 20 Apr 1983 23:53 EST From: Scott E. Fahlman To: David A. Moon Cc: Common-Lisp%su-ai@usc-ecl Subject: DEFSETF In-reply-to: Msg of 20 Apr 1983 03:58-EST from David A. Moon I'm having some difficulty understanding your DEFSETF description. (Not your fault -- it seems to be impossible to describe any adequate DEFSETF in human-readable form.) Would it be possible to put the code file somewhere where the rest of us can see it? It might be easier to grok the code than the prose in this case. Whatever we do about the rest of DEFSETF, I am adamantly opposed to allowing multiple values to come in from the "new value" form, let alone multiple values with &optional and &rest provisions. I haven't implemented this in our DEFSETF and don't plan to. In part, this is because implementing this is a pain, but to a large extent the objection is philosophical. To me SETF takes a form that accesses one Lisp storage cell and stuffs a new value into that cell. This SETF business is hairy, but as long as users can hang onto that basic point of view, there is some hope that they will be able to cope with this construct. If we muck around with this, then SETF/DEFSETF is just an incredibly hairy format for defining arbitrary macros. That's too high a price to pay for cute but useless things like UNCONS. If anyone can demonstrate some real need for multiple values here, I might change my mind. -- Scott  Mail-from: ARPANET site SU-AI rcvd at 20-Apr-83 2058-PST Received: from USC-ECL by SU-AI with NCP/FTP; 20 Apr 83 20:56:08 PST Received: from CMU-CS-C by USC-ECL; Wed 20 Apr 83 20:53:03-PST Received: ID ; 20 Apr 83 23:53:46 EST Date: Wed, 20 Apr 1983 23:53 EST From: Scott E. Fahlman To: David A. Moon Cc: Common-Lisp%su-ai@usc-ecl Subject: DEFSETF In-reply-to: Msg of 20 Apr 1983 03:58-EST from David A. Moon I'm having some difficulty understanding your DEFSETF description. (Not your fault -- it seems to be impossible to describe any adequate DEFSETF in human-readable form.) Would it be possible to put the code file somewhere where the rest of us can see it? It might be easier to grok the code than the prose in this case. Whatever we do about the rest of DEFSETF, I am adamantly opposed to allowing multiple values to come in from the "new value" form, let alone multiple values with &optional and &rest provisions. I haven't implemented this in our DEFSETF and don't plan to. In part, this is because implementing this is a pain, but to a large extent the objection is philosophical. To me SETF takes a form that accesses one Lisp storage cell and stuffs a new value into that cell. This SETF business is hairy, but as long as users can hang onto that basic point of view, there is some hope that they will be able to cope with this construct. If we muck around with this, then SETF/DEFSETF is just an incredibly hairy format for defining arbitrary macros. That's too high a price to pay for cute but useless things like UNCONS. If anyone can demonstrate some real need for multiple values here, I might change my mind. -- Scott  Mail-from: ARPANET site SU-AI rcvd at 20-Apr-83 1018-PST Received: from USC-ECL by SU-AI with NCP/FTP; 20 Apr 83 07:17:14 PST Received: from MIT-ML by USC-ECL; Wed 20 Apr 83 07:16:55-PST Received: from SCRC-NEPONSET by SCRC-TENEX with CHAOS; Wed 20-Apr-83 03:57:34-EST Date: Wednesday, 20 April 1983, 03:58-EST From: David A. Moon Subject: DEFSETF To: Common-Lisp%su-ai@usc-ecl The DEFSETF documented in the Laser edition is deficient in several respects. The UNCONS example (about as obscure as one can get!) fails to agree with the English. The manual is inconsistent about who is responsible for ensuring proper order of evaluation. It doesn't seem to be possible to write the DEFSETF for LDB; ignoring order of evaluation and returned-value issues, (SETF (LDB x y) z) turns into (SETF y (DPB z x y)); note how the "y" argument is used as both an "Lvalue" and an "Rvalue". This DEFSETF similarly gives no help in implementing such macros as INCF, SHIFTF, and PUSH, which take a place that is both read and written. The function generated by DEFSETF doesn't have a portable name, so the user may not know how to trace and otherwise debug it. (This is best attributed to the omission of function specs from Common Lisp, so I won't mention it again.) I would like to propose a modified form of DEFSETF: There are three forms of DEFSETF, rather than the two in the Laser manual. This helps a lot. The body of DEFSETF is in charge of making sure that the right value is returned. In most cases, this works simply by calling a storing function that is guaranteed to return the right value. The SETF system is in charge of evaluating the evaluatable subforms of the SETF (or other) special form in left-to-right order, and once each (no more and no less), or generating code whose effect is equivalent to that. It is aided in this by some information supplied by the body of the DEFSETF. The underlying theory is that the SETF method for a given form can be expressed as five values: - a list of temporary variables - a list of values to bind them to (subforms of the given form) - a second list of temporary variables ("store variables") - a storing form - an accessing form The store variables are to be bound to the values of the form to be stored. In almost all cases we store single values and there is only one store variable. The storing form and the accessing form can be evaluated any number of times, inside the bindings of the temporary variables (and of the store variables, in the case of the storing form). The accessing form returns the value of the generalized variable. The storing form modifies the value of the generalized variable, and guarantees to return the store variable(s) as its value(s); these are the correct values for SETF, INCF, etc. to return. The value returned by the accessing form is (of course) affected by execution of the storing form. The temporary variables and the store variables are gensyms in all cases, so that there is never any issue of name clashes with them. This is necessary to make the special forms that do multiple setfs in parallel work properly; these are PSETF, SHIFTF, and ROTATEF. Computation of the SETF method must always cons new gensyms. To give some examples: - for a variable X () () (G0001) (SETQ X G0001) X - for (CAR exp) (G0001) (exp) (G0002) (RPLACA2 G0001 G0002) (CAR G0001) where RPLACA2 is assumed to be a version of RPLACA that returns its second argument. - for (LIST a b) () () (G0001) (PROGN (SETQ a (FIRST G0001)) (SETQ b (SECOND G0001)) G0001) (COMPILE-TIME-ERROR "LIST-destructuring SETF is write-only") Destructuring patterns are write-only (it doesn't seem worth putting in a third set of temporary variables to make this work!) I guess &OPTIONAL and &REST should be allowed in the store variables, if we want to keep the features involving them that are in the Laser edition DEFSETF. I don't currently support this. SETF methods are defined via DEFSETF. There are three forms of DEFSETF. - the trivial form (DEFSETF access-function storing-function [documentation]) The storing-function takes the same arguments as the access-function, plus one additional argument, which is the value to store, and returns that as its value. Example: (DEFSETF SYMBOL-VALUE SET) - the functional form (DEFSETF access-function (args...) (store-variables...) [documentation] body...) The access-function is truly a function and evaluates its arguments. Furthermore a SETF reference evaluates all the arguments (i.e. this is not a "destructuring" case). Args are the lambda-list for the access-function; &OPTIONAL and &REST are permitted. Optional args may have defaults, although many cases that need them may prefer to use the general form (below). The SETF method consists of some gensym temporary variables, some gensym store variables, (access-function temporaries...) as the accessing form, and the result of evaluating the body as the storing form. During the evaluation of the body, the variables in args and in store-variables will be bound to the corresponding gensyms. The gensyms will in turn be bound to the arguments to the access function, and the values being stored, at run time. Example: (DEFSETF SUBSEQ (SEQUENCE START &OPTIONAL END) (NEW-SEQUENCE) `(PROGN (REPLACE ,SEQUENCE ,NEW-SEQUENCE :START1 ,START :END1 ,END) ,NEW-SEQUENCE)) - the general form (DEFINE-SETF-METHOD access-function (subforms...) [documentation] body...) The result of evaluating the body must be five values, as documented above. The subforms variables are bound to a destructuring of the cdr of the reference, just as in DEFMACRO. Note that the general case differs from the functional case in that the general case's subforms pattern is bound to parts of the reference form, whereas the functional case's args pattern is bound to gensyms. I gave this a separate name rather than kludging up DEFSETF's syntax somehow with an extra level of parentheses or something. It's reasonable for this to have a longer name since it is more low-level. Example: (Sorry, there are by definition no small examples of this. Pay no attention to the non-Common-Lisp functions herein.) (DEFINE-SETF-METHOD CONS (CAR CDR) (MULTIPLE-VALUE-BIND (VARS1 VALS1 STORES1 STORE-FORM1) (GET-DESTRUCTURING-BACKQUOTE-SETF-METHOD CAR) (MULTIPLE-VALUE-BIND (VARS2 VALS2 STORES2 STORE-FORM2) (GET-DESTRUCTURING-BACKQUOTE-SETF-METHOD CDR) (LET ((CONS-VAR (GENSYM))) (VALUES (APPEND VARS1 VARS2) (APPEND VALS1 VALS2) (LIST CONS-VAR) `(PROGN ,(LET-SUBST STORES1 `((CAR ,CONS-VAR)) STORE-FORM1) ,(LET-SUBST STORES2 `((CDR ,CONS-VAR)) STORE-FORM2) ,CONS-VAR) `(COMPILE-TIME-ERROR "CONS-destructuring SETF is write-only")))))) A random, but useful, abbreviation for DEFSETF is DEFINE-SETF-EQUIVALENCE access-function outer-function inner-function [documentation] This is a kind of macro that is only expanded in references (not forms). SETF, LOCF, and their variants know about this. [The existence of LOCF in the Lisp machine makes this extra useful.] Example: (DEFINE-SETF-EQUIVALENCE CDADDR CDR CADDR) Another thing that is random but useful is DEFINE-MODIFY-MACRO name (args) function [documentation] where args may contain &OPTIONAL and &REST, and the expansion is like the following except that it has correct semantics: (DEFMACRO name (location args...) `(SETF ,location (function ,location ,args...))) Example: (DEFINE-MODIFY-MACRO INCF (&OPTIONAL (DELTA 1)) +) I anticipate that users will want to define many more of these in addition to the mere two that Common Lisp has built in. It would of course be a loss if it was too hard for users to define modify macros that follow proper order of evaluation semantics. I have needed the following, for example: (DEFINE-MODIFY-MACRO UNIONF (OTHER-SET) UNION) Thanks to Alan Bawden for explaining the underlying theory of the five values to me. By the way, this is all implemented and works. The code is optimized, removing any temporary-variable bindings that are not actually necessary, using code-analysis tools that I intend to offer as a yellow-pages package once I have rewritten them to be portable. Some implementations may have smart enough compilers that they don't need this, possibly. The new LOOP will depend on some of these tools also.  Mail-from: ARPANET site SU-AI rcvd at 20-Apr-83 0720-PST Received: from USC-ECL by SU-AI with NCP/FTP; 20 Apr 83 07:17:14 PST Received: from MIT-ML by USC-ECL; Wed 20 Apr 83 07:16:55-PST Received: from SCRC-NEPONSET by SCRC-TENEX with CHAOS; Wed 20-Apr-83 03:57:34-EST Date: Wednesday, 20 April 1983, 03:58-EST From: David A. Moon Subject: DEFSETF To: Common-Lisp%su-ai@usc-ecl The DEFSETF documented in the Laser edition is deficient in several respects. The UNCONS example (about as obscure as one can get!) fails to agree with the English. The manual is inconsistent about who is responsible for ensuring proper order of evaluation. It doesn't seem to be possible to write the DEFSETF for LDB; ignoring order of evaluation and returned-value issues, (SETF (LDB x y) z) turns into (SETF y (DPB z x y)); note how the "y" argument is used as both an "Lvalue" and an "Rvalue". This DEFSETF similarly gives no help in implementing such macros as INCF, SHIFTF, and PUSH, which take a place that is both read and written. The function generated by DEFSETF doesn't have a portable name, so the user may not know how to trace and otherwise debug it. (This is best attributed to the omission of function specs from Common Lisp, so I won't mention it again.) I would like to propose a modified form of DEFSETF: There are three forms of DEFSETF, rather than the two in the Laser manual. This helps a lot. The body of DEFSETF is in charge of making sure that the right value is returned. In most cases, this works simply by calling a storing function that is guaranteed to return the right value. The SETF system is in charge of evaluating the evaluatable subforms of the SETF (or other) special form in left-to-right order, and once each (no more and no less), or generating code whose effect is equivalent to that. It is aided in this by some information supplied by the body of the DEFSETF. The underlying theory is that the SETF method for a given form can be expressed as five values: - a list of temporary variables - a list of values to bind them to (subforms of the given form) - a second list of temporary variables ("store variables") - a storing form - an accessing form The store variables are to be bound to the values of the form to be stored. In almost all cases we store single values and there is only one store variable. The storing form and the accessing form can be evaluated any number of times, inside the bindings of the temporary variables (and of the store variables, in the case of the storing form). The accessing form returns the value of the generalized variable. The storing form modifies the value of the generalized variable, and guarantees to return the store variable(s) as its value(s); these are the correct values for SETF, INCF, etc. to return. The value returned by the accessing form is (of course) affected by execution of the storing form. The temporary variables and the store variables are gensyms in all cases, so that there is never any issue of name clashes with them. This is necessary to make the special forms that do multiple setfs in parallel work properly; these are PSETF, SHIFTF, and ROTATEF. Computation of the SETF method must always cons new gensyms. To give some examples: - for a variable X () () (G0001) (SETQ X G0001) X - for (CAR exp) (G0001) (exp) (G0002) (RPLACA2 G0001 G0002) (CAR G0001) where RPLACA2 is assumed to be a version of RPLACA that returns its second argument. - for (LIST a b) () () (G0001) (PROGN (SETQ a (FIRST G0001)) (SETQ b (SECOND G0001)) G0001) (COMPILE-TIME-ERROR "LIST-destructuring SETF is write-only") Destructuring patterns are write-only (it doesn't seem worth putting in a third set of temporary variables to make this work!) I guess &OPTIONAL and &REST should be allowed in the store variables, if we want to keep the features involving them that are in the Laser edition DEFSETF. I don't currently support this. SETF methods are defined via DEFSETF. There are three forms of DEFSETF. - the trivial form (DEFSETF access-function storing-function [documentation]) The storing-function takes the same arguments as the access-function, plus one additional argument, which is the value to store, and returns that as its value. Example: (DEFSETF SYMBOL-VALUE SET) - the functional form (DEFSETF access-function (args...) (store-variables...) [documentation] body...) The access-function is truly a function and evaluates its arguments. Furthermore a SETF reference evaluates all the arguments (i.e. this is not a "destructuring" case). Args are the lambda-list for the access-function; &OPTIONAL and &REST are permitted. Optional args may have defaults, although many cases that need them may prefer to use the general form (below). The SETF method consists of some gensym temporary variables, some gensym store variables, (access-function temporaries...) as the accessing form, and the result of evaluating the body as the storing form. During the evaluation of the body, the variables in args and in store-variables will be bound to the corresponding gensyms. The gensyms will in turn be bound to the arguments to the access function, and the values being stored, at run time. Example: (DEFSETF SUBSEQ (SEQUENCE START &OPTIONAL END) (NEW-SEQUENCE) `(PROGN (REPLACE ,SEQUENCE ,NEW-SEQUENCE :START1 ,START :END1 ,END) ,NEW-SEQUENCE)) - the general form (DEFINE-SETF-METHOD access-function (subforms...) [documentation] body...) The result of evaluating the body must be five values, as documented above. The subforms variables are bound to a destructuring of the cdr of the reference, just as in DEFMACRO. Note that the general case differs from the functional case in that the general case's subforms pattern is bound to parts of the reference form, whereas the functional case's args pattern is bound to gensyms. I gave this a separate name rather than kludging up DEFSETF's syntax somehow with an extra level of parentheses or something. It's reasonable for this to have a longer name since it is more low-level. Example: (Sorry, there are by definition no small examples of this. Pay no attention to the non-Common-Lisp functions herein.) (DEFINE-SETF-METHOD CONS (CAR CDR) (MULTIPLE-VALUE-BIND (VARS1 VALS1 STORES1 STORE-FORM1) (GET-DESTRUCTURING-BACKQUOTE-SETF-METHOD CAR) (MULTIPLE-VALUE-BIND (VARS2 VALS2 STORES2 STORE-FORM2) (GET-DESTRUCTURING-BACKQUOTE-SETF-METHOD CDR) (LET ((CONS-VAR (GENSYM))) (VALUES (APPEND VARS1 VARS2) (APPEND VALS1 VALS2) (LIST CONS-VAR) `(PROGN ,(LET-SUBST STORES1 `((CAR ,CONS-VAR)) STORE-FORM1) ,(LET-SUBST STORES2 `((CDR ,CONS-VAR)) STORE-FORM2) ,CONS-VAR) `(COMPILE-TIME-ERROR "CONS-destructuring SETF is write-only")))))) A random, but useful, abbreviation for DEFSETF is DEFINE-SETF-EQUIVALENCE access-function outer-function inner-function [documentation] This is a kind of macro that is only expanded in references (not forms). SETF, LOCF, and their variants know about this. [The existence of LOCF in the Lisp machine makes this extra useful.] Example: (DEFINE-SETF-EQUIVALENCE CDADDR CDR CADDR) Another thing that is random but useful is DEFINE-MODIFY-MACRO name (args) function [documentation] where args may contain &OPTIONAL and &REST, and the expansion is like the following except that it has correct semantics: (DEFMACRO name (location args...) `(SETF ,location (function ,location ,args...))) Example: (DEFINE-MODIFY-MACRO INCF (&OPTIONAL (DELTA 1)) +) I anticipate that users will want to define many more of these in addition to the mere two that Common Lisp has built in. It would of course be a loss if it was too hard for users to define modify macros that follow proper order of evaluation semantics. I have needed the following, for example: (DEFINE-MODIFY-MACRO UNIONF (OTHER-SET) UNION) Thanks to Alan Bawden for explaining the underlying theory of the five values to me. By the way, this is all implemented and works. The code is optimized, removing any temporary-variable bindings that are not actually necessary, using code-analysis tools that I intend to offer as a yellow-pages package once I have rewritten them to be portable. Some implementations may have smart enough compilers that they don't need this, possibly. The new LOOP will depend on some of these tools also.  Mail-from: ARPANET site SU-AI rcvd at 13-Apr-83 2034-PST Received: from USC-ECL by SU-AI with NCP/FTP; 13 Apr 83 20:31:51 PST Received: from CMU-CS-C by USC-ECL; Wed 13 Apr 83 19:05:40-PST Received: ID ; 13 Apr 83 22:05:43 EST Date: Wed, 13 Apr 1983 22:05 EST From: Scott E. Fahlman To: steele@CMU-CS-C Cc: common-lisp%su-ai@USC-ECL, fahlman@CMU-CS-C Subject: EVAL and friends Guy, Now that I've written a lexical interpreter for Slisp, I am somewhat mystified by the decisions you made in defining the various flavors of EVAL. It seems to me that there are three things needed: 1. Eval a form in the current lexical context. This is used a lot, and there is no way that I can see to do it in user-level Common Lisp, since no way is provided to get your hands on whatever it is that you pass to *EVAL as the environment stuff. I've defined a %EVAL that does this (it uses %venv% and friends as specials without rebinding them). I find that almost all of the places where I was previously using EVAL now use %EVAL, which makes these things non-portable. 2. Eval a form in the null lexical environment. Needed very rarely, but needed. EVAL currently does this. 3. Eval a form in some user-supllied lexical environment. This is what *EVAL does. It seems to me that *EVAL is not a legitimate user-level function and ought to be made a system-internal form, since the form of the environment arguments are left up to the implementation. This is needed in the debugger and a couple of other places, but is inherently unportable. (I assume that we do not want to take the step of trying to agree on the exact format of the environment across all implementations.) It seems to me that a name-rotation would clean things up a good deal. Case 1, eval in the current environment, would just be EVAL. Case 2 would get a name such as EVAL-IN-NULL-ENVIRONMENT or some such. (It could be *EVAL, but I find the random use of *'s to be confusing.) Case 3 could then inherit the name %EVAL or SI:%EVAL, and could disappear from the white pages altogether. Every implementation will need to provide this function internally, but it is not a portable user-level function since it takes implementation-dependent arguments. Macroexpand and other forms that currently take these environment args should get a parallel treatment. Perhaps case 3 is too important to flush from the white pages. I suppose we could provide a new function CURRENT-LEXICAL-ENVIRONMENT and a new (defstruct) data type called a LEXICAL-ENVIRONMENT-OBJECT or some such. The former returns one of the latter, and at any time thereafter you can pass this to *EVAL and have it used as the environment. This encapsulation keeps us from having to define the internal structure of the environment. It would not be efficient, but would give us a way of doing the current *EVAL without appeal to secret rituals. I have not really thought through all the implications of this, and the idea may be more confusing than useful. If we don't absolutely need this functionality in the white pages, flushing it would be a good thing. -- Scott  Mail-from: ARPANET site SU-AI rcvd at 13-Apr-83 0004-PST Received: from USC-ECL by SU-AI with NCP/FTP; 12 Apr 83 23:59:51 PST Received: from MIT-MC by USC-ECL; Tue 12 Apr 83 23:59:40-PST Received: from SCRC-NEPONSET by SCRC-TENEX with CHAOS; Wed 13-Apr-83 02:54:44-EST Date: Wednesday, 13 April 1983, 02:55-EST From: David A. Moon Subject: Proposed change to SPECIAL: proposed resolution To: Common-Lisp%SU-AI@usc-ecl In-reply-to: The message of 5 Apr 83 22:16-EST from Guy.Steele at CMU-CS-A, The message of 7 Apr 83 01:31-EST from MOON at SCRC-TENEX, The message of 8 Apr 83 01:33-EST from Scott E. Fahlman Part 1: (local vs. top-level declarations) Okay, I am convinced that we need two magic words that introduce a declaration. One is the one that is specially recognized at the start of certain special forms and makes local declarations. The other is a special form, intended to be used at top level (or inside a PROGN at top level), that makes global declarations. The first should be called DECLARE and the second PROCLAIM, unless anyone has better names to propose. Note that DECLARE is not a special form, but a magic symbol specially checked for by the interpreter and the compiler. In a correct Common Lisp program, EVAL should never see a DECLARE form. If it does, it will signal an undefined-function error, unless a Maclisp-compatibility package has defined a DECLARE special form for Maclisp compatibility (this should not be included in standard Common Lisp). There should probably also be an UNPROCLAIM special form, for undoing global declarations that were "accidentally" made. This would normally be typed in by users, not included in files. For example, (PROCLAIM (SPECIAL FLAG)) (DEFUN FOO (FLAG LIST) (BAR LIST)) (DEFUN BAR ...) (UNPROCLAIM (SPECIAL FLAG)) would behave differently in the interpreter than in the compiler, since it would be unreasonable to require DEFUN to make a complete copy of the current global declarations in the interpreter, yet this is effectively what it does in the compiler. Maybe PROCLAIM should be a function rather than a special form, even though its arguments would always be quoted. There are possible applications for functions calling it to add global declarations to the world. The compiler would know in either case that this is one of the several functions/special forms that get an automatic "eval-when compile" around them. I have no opinion either way. This should simplify and clarify the manual. Let me restate the rules as I understand them: A local declaration of a variable is attached to a particular binding of that variable, and affects all references captured by that particular binding. It does not affect lexically enclosed bindings of variables with the same name, nor references captured by those inner bindings. A local SPECIAL declaration not attached to a binding of the variable applies to all references that would have been lexically captured by a binding of the variable if there had been one, and makes those references use the dynamic value. This extends to a SPECIAL in a LOCALLY in the obvious fashion. A local declaration of a non-variable type is "pervasive", applying to the entire lexical body of the special form containing the declaration, including any interior special forms and including any initialization forms for bound variables. To determine the effect of a variable-related local declaration on an initialization form for a bound variable, you only need to know whether or not the scope of the variable includes that form. Global declarations (aka proclamations) of variables apply to the dynamic value of the variable. Note: the rules given above mean that LET cannot be written as a macro expanding into a lambda-combination, a small price to pay for clarifying the utterly confusing paragraph about this on page 102. Note that the example (using *princircle*) given there becomes incorrect, because special isn't pervasive. The example at the top of page 103 is incorrect also, because of the simplification of the rules about bound-variable initialization forms; the inline declaration will affect both calls to foo. There are no locally pervasive declarations of variables. Each variable declaration applies to only a single binding. Thus to determine whether a variable binding is special, one need consider only declarations immediately attached to that binding and proclamations, not declarations attached to enclosing bindings. No search of a declarations environment is required in the interpreter. There is no mechanism provided for global declarations whose scope is limited to the file in which they appear. Perhaps one will need to be added later. Perhaps not. Part 2: (efficiency of declarations in the interpreter) I am very unenthusiastic about the idea of adding syntax to the language in order to effect an improvement in the speed of the interpreter. I think I can make some plausible arguments that the speed improvement to be gained is very small (less than 1%). When the interpreter enters a lambda, or any variable-binding special form, it must check for SPECIAL declarations before binding the variables. If there are SPECIAL declarations for variables not bound by the form, a "pseudo binding" entry in the interpreter's environment structure must be made, so that variable lookup within that scope will use the dynamic value. This check consists of examining each element of the body until a non-DECLARE, non-documentation-string is found. Macro expansion is required in order to know whether an element is a DECLARE. When a DECLARE is found, each declaration within it must be checked for SPECIAL. The information from all the SPECIAL declarations encountered must be used in making the bindings. How much extra work is this? The body is going to be looked at right after binding the variables, in order to evaluate the body forms. The interpreter will cdr its handle on the body so that the DECLARE forms it found will not be looked at again. The first non-DECLARE form in the body will be macroexpanded in order to determine that it is not a DECLARE; however it should be easy to save the resulting expansion and use it as the first thing to be evaluated once the bindings have been completed, so that the form need not be macroexpanded again. So there is no extra actual "interpretation": the only real extra work is whatever function-calling and decision-making overhead it takes to do this, plus whatever overhead is required in deciding for each variable to be bound whether or not it is in fact special; this probably consists of mapping over the newly-constructed interpreter environment structure each time a SPECIAL declaration is seen, looking up the entry for the variable being declared, and bashing it so that the dynamic variable will get bound. My guess is that all of this is much less slow than implementing &OPTIONAL, &REST, and &KEY in the interpreter. Note that if the cost of looking for declarations, or of looking and determining that there are no declarations present, is determined to be too high in a particular implementation, this information is very easily memoized, just as macro expansions are memoized. This can be done by looking up the lambda or form in a hash table, getting back either a possibly empty list of variables declared special or "don't know". Or it can be done by bashing the form to contain at its front an internal parsed summary of the declarations, just as macros can be displaced. Code-understanding tools would need to know to treat this as a comment. I recommend that implementations with limited virtual memory, or much smaller physical memory than virtual memory, either use the displacing method or set a limit to the size of the hash table and use a least-recently-used discipline to purge it when it reaches that size; this applies to macro expansions as well as declarations. I would not be strongly averse to changing documentation strings to be (DECLARE (DOCUMENTATION "foo")) rather than raw strings if anyone feels that having to check for both strings and declarations is a pain. This is probably preferable to requiring that all declarations precede the documentation string. The only advantage to this is that you don't have to special-case a string at the end of the body, which is a constant value to be returned rather than a documentation string. The principal disadvantage, and it is not a trivial one, is that the string starts very far to the right on the page, so that you don't have as much width in which to write it, or else you have to grind it in a funny way. Another possible disadvantage is that documentation string declarations can be the result of macro expansion, which therefore must be done (carefully!) by DEFUN in order to record the documentation string.  Mail-from: ARPANET site SU-AI rcvd at 12-Apr-83 2242-PST Received: from USC-ECL by SU-AI with NCP/FTP; 12 Apr 83 22:40:26 PST Received: from MIT-MC by USC-ECL; Tue 12 Apr 83 22:34:45-PST Received: from SCRC-NEPONSET by SCRC-TENEX with CHAOS; Wed 13-Apr-83 01:32:02-EST Date: Wednesday, 13 April 1983, 01:33-EST From: David A. Moon Subject: What should LAST of an atom do? -- conclusion To: Common-Lisp%su-ai@usc-ecl In-reply-to: The message of 10 Apr 83 22:30-EST from David A. Moon , The message of 10 Apr 83 23:55-EST from Scott E. Fahlman , The message of 11 Apr 83 03:43-EST from Glenn S. Burke Date: Sunday, 10 April 1983, 22:30-EST From: David A. Moon On page 176 of the Laser edition of the Common Lisp manual, it says that LAST of the empty list should return NIL. It doesn't say anything about LAST of other atoms. The question is: should LAST be redefined to be an error when applied to an atom, since anything it could return would really be wrong? And should it be an error even if the atom is NIL? Date: Sun, 10 Apr 1983 23:55 EST From: Scott E. Fahlman I don't feel very strongly about this, but I would go for (LAST NIL) ==> NIL and LAST of any other atom being an error. This is nice to implement and feels right to me, given that (CDR NIL) ==> NIL and (CDR non-null-atom) is an error. Date: 11 April 1983 03:43 EST From: Glenn S. Burke At one point, in NIL it did not accept anything but a cons. I found that to be giving me a hard time (i don't remember where, it may have been some NIL-only loop expansions in part), so i changed it to accept an argument of NIL and return that. I don't completely buy the reasoning that (LAST NIL) shouldn't be an error. But I'll go along with it. Unless anyone wants to dispute, the conclusion is that LAST of anything that is LISTP is valid, and LAST of anything else is an error, and the Lisp machine is broken and will be fixed to detect the error rather than returning NIL. The CL manual should be clarified.  Mail-from: ARPANET site SU-AI rcvd at 12-Apr-83 1212-PST Date: 12 Apr 83 1210 PST From: Dick Gabriel Subject: Map To: common-lisp%SU-AI@USC-ECL A user just pointed out that Common Lisp ought to discuss use of RETURN's, GO's, and CATCH/THROW within MAP's. For the soul who comes to Common Lisp without benefit of Lisp Machine Lisp, there is the bitter memory of the 1974 MacLisp manual recommending ``breaking out of'' MAP's with RETURN's. Aside from deciding whether one needs PROG's around the MAP, the typical user is baffled because the behavior of MacLisp varies with interpreted versus compiled code, and, within compiled code, it varies with the presense versus the absence of the declaration (MAPEX T). I won't comment on the bugs in the compiler with respect to this issue, but the upshot from the user was that after the performance of MacLisp, the Common Lisp manual ought to say something about this. -rpg-  Mail-from: ARPANET site SU-AI rcvd at 11-Apr-83 0047-PST Received: from USC-ECL by SU-AI with NCP/FTP; 11 Apr 83 00:46:34 PST Received: from MIT-ML by USC-ECL; Mon 11 Apr 83 00:41:59-PST Date: 11 April 1983 03:43 EST From: Glenn S. Burke Subject: What should LAST of an atom do? To: Common-Lisp%su-ai @ USC-ECL At one point, in NIL it did not accept anything but a cons. I found that to be giving me a hard time (i don't remember where, it may have been some NIL-only loop expansions in part), so i changed it to accept an argument of NIL and return that. Otherwise, it detects non-atomic tails (does not complain), and circularity (and complains). This seems reasonable, and is compatible with Maclisp.  Mail-from: ARPANET site SU-AI rcvd at 10-Apr-83 2102-PST Received: from USC-ECL by SU-AI with NCP/FTP; 10 Apr 83 20:55:42 PST Received: from CMU-CS-C by USC-ECL; Sun 10 Apr 83 20:54:39-PST Received: ID ; 10 Apr 83 23:55:02 EST Date: Sun, 10 Apr 1983 23:55 EST From: Scott E. Fahlman To: David A. Moon Cc: Common-Lisp%su-ai@usc-ecl Subject: What should LAST of an atom do? In-reply-to: Msg of 10 Apr 1983 22:30-EST from David A. Moon I don't feel very strongly about this, but I would go for (LAST NIL) ==> NIL and LAST of any other atom being an error. This is nice to implement and feels right to me, given that (CDR NIL) ==> NIL and (CDR non-null-atom) is an error.  Mail-from: ARPANET site SU-AI rcvd at 10-Apr-83 1935-PST Received: from USC-ECL by SU-AI with NCP/FTP; 10 Apr 83 19:34:10 PST Received: from MIT-MC by USC-ECL; Sun 10 Apr 83 19:31:08-PST Received: from SCRC-BORZOI by SCRC-TENEX with CHAOS; Sun 10-Apr-83 22:26:49-EST Date: Sunday, 10 April 1983, 22:30-EST From: David A. Moon Subject: What should LAST of an atom do? To: Common-Lisp%su-ai@usc-ecl On page 176 of the Laser edition of the Common Lisp manual, it says that LAST of the empty list should return NIL. It doesn't say anything about LAST of other atoms. Page 56 of the Lisp Machine manual says the same thing, but gives an example (which in fact agrees with the actual behavior) indicating that LAST of any atom returns that atom. The Interlisp manual says that LAST of any atom is NIL. Unfortunately I don't have my Maclisp and Lisp 1.5 manuals here. However, Maclisp signals an error if LAST is given a non-NIL atom, even in (*rset nil) mode, but returns NIL if it is given NIL. The question is: should LAST be redefined to be an error when applied to an atom, since anything it could return would really be wrong? And should it be an error even if the atom is NIL? I am inclined to say "yes" to both of these, but perhaps that would be too much tinkering with the traditional foundations of Lisp. This was inspired by two people complaining about not getting an error for LAST of an atom; in one case the atom was NIL.  Mail-from: ARPANET site SU-AI rcvd at 8-Apr-83 1330-PST Received: from USC-ECL by SU-AI with NCP/FTP; 8 Apr 83 13:28:05 PST Received: from MIT-MC by USC-ECL; Fri 8 Apr 83 13:26:09-PST Date: Friday, 8 April 1983 16:12-EST From: MOON at SCRC-TENEX To: Scott E. Fahlman Cc: common-lisp%SU-AI at usc-ecl Subject: Proposed change to SPECIAL: quick poll In-reply-to: The message of Fri 8 Apr 1983 01:33 EST from Scott E. Fahlman Date: Fri, 8 Apr 1983 01:33 EST From: Scott E. Fahlman I guess I read the manual differently than Moon on one point: I don't see the business about allowing SPECIAL declarations at the start of forms that do not bind the variable in question. If it is really necessary to use the special value of a symbol that is not globally special, there is always SYMBOL-VALUE. The example at the bottom of page 103 looks rather explicit to me. This letter is not a reply to anything else in your letter; that will come later. Have to put my thinking cap on.  Mail-from: ARPANET site SU-AI rcvd at 8-Apr-83 1120-PST Received: from USC-ECL by SU-AI with NCP/FTP; 8 Apr 83 11:16:47 PST Received: from MIT-MC by USC-ECL; Fri 8 Apr 83 11:12:17-PST Received: from SCRC-BORZOI by SCRC-TENEX with CHAOS; Fri 8-Apr-83 14:09:41-EST Date: Friday, 8 April 1983, 14:10-EST From: Bernard S. Greenberg Subject: nsubstitute-if/if-not To: Common-Lisp%SU-AI@USC-ECL Cc: Common-Lisp-Implementors%SCRC-TENEX@MIT-MC Is there any reason why nsubstitute-if and nsubstitute-if-not, unlike every other if/if-not in the Laser manual, do not take their predicate argument first?  Mail-from: ARPANET site SU-AI rcvd at 7-Apr-83 2240-PST Received: from USC-ECL by SU-AI with NCP/FTP; 7 Apr 83 22:38:27 PST Received: from CMU-CS-C by USC-ECL; Thu 7 Apr 83 22:36:08-PST Received: ID ; 8 Apr 83 01:33:45 EST Date: Fri, 8 Apr 1983 01:33 EST From: Scott E. Fahlman To: common-lisp%SU-AI@usc-ecl Cc: fahlman@CMU-CS-C Subject: Proposed change to SPECIAL: quick poll In-reply-to: Msg of 7 Apr 1983 01:31-EST from MOON at SCRC-TENEX My earlier proposal to Guy was an attempt to solve the "top-level" problem with minimal changes to the language. I guess I read the manual differently than Moon on one point: I don't see the business about allowing SPECIAL declarations at the start of forms that do not bind the variable in question. If it is really necessary to use the special value of a symbol that is not globally special, there is always SYMBOL-VALUE. Of Moon's two solutions, I much prefer the second: reserving DECLARE for local declarations and using PROCLAIM for global ones. This change would make no difference for most forms, but would clearly separate the two uses of SPECIAL, just as my GLOBALLY-SPECIAL proposal would have. Moon's first proposal, that we just trat all non-local uses of SPECIAL as globally special without flagging an error seems a bit dangerous to me. As long as we're worrying about this, let me raise a problem that I hesitated to raise earlier. In defining Common Lisp, we've been pretty cavalier about including constructs that would slow the interpreter down, as long as the compiler could produce fast code. However, the current rules for SPECIAL slow the interpreter down a lot, probably more than we can afford. SPECIAL (and its inverse if this makes a comeback) is the only declaration that the interpreter has to worry about. Because of specials, every time we enter a lambda in the interpreter we have to grovel down into the body looking for instances of (declare (special ...)) and macros that might expand into the same. THEN we can do the binding and go on with the call. That's all very expensive. Maybe there's a better way. Currently Common Lisp recognizes two classes of declarations: those that pertain to some particular binding of a variable and all the others. The former class of declarations really ought to be in the lambda list, closely associated with the variable-instances they modify. This was ruled out on the grounds that lambda lists need to be human-readable and that much extra hair would push them over the brink. So we do the next best thing and hide these declarations in a DECLARE right after the lambda list. The situation is further complicated by documentation strings, multiple DECLARE forms, and macros that might expand into declarations. All of these add to the cost of finding the declarations relevant to a given binding, but that's OK in the compiler. It is not OK in the interpreter, however, and we can't ignore these declarations since there may be a SPECIAL hiding in there. This will be rare, but we pay the price for this possibility on every call. Suppose we recognize the fact that SPECIAL (and its inverse, if any) are fundamentally different kinds of declarations from the rest. Since they matter to the interpreter, they must be easily accessible. I would propose something like the following: 1. (declare (special foo)) is allowed only at top level -- it is undefined what it does elsewhere. This form declares foo to be globally special wherever it appears from that time forward. (This is easily implemented by putting some sort of SPECIAL property on the symbol.) If we want, we can define a (declare (unspecial ...)) that undoes this. 2. We may sometimes want a particular binding of FOO to be special, without declaring the symbol FOO to be globally special. We do not use an embedded declare for this. Instead, we mark this variable as special right in the lambda list where it occurs. We need some syntax to make this non-obnoxious. Perhaps #^foo would be good. This expands into something like (&special foo) internally, and the interpreter can now do the binding without all the added hair. Any reference to FOO that is lexically within the scope of this binding form and that is not shadowed by a lexical binding of FOO would refer to the special value. We could allow #^ to be used with variables to force the (symbol-value ...) interpretation. So, in doing a binding the interpreter would look first for #^ (or rather whatever this expands into), then for a special property on the symbol, and if it finds neither of these the binding is local. In evaluating a symbol, the interpreter looks in the local lexical environment, where there may be a notation to use the special value of the symbol instead. #^FOO is equivalent to (symbol-value foo) in all contexts. I suppose we could also define another bit of syntax, #_ maybe, for making a particular value lexical when it would otherwise be special. I've never had much use for this or for UNSPECIAL, but someone may have an argument for why this is necessary. (These sharpm characters are somewhat mnemonic to me: #^ says fly off to find the value, while #_ says stay on the ground. Neither seems to be in use right now.) I know that this is pretty radical, especially at this late date, but it seems to follow inevitably from our earlier radical decision to make the interpreter pay attention to specialness. I hate to see even this much syntax added to lambda lists, but it may be preferable to a very substantial slowdown in the interpreter. #^ would be very rare in real programs, since the vast majority of specials would be globally declared by DEFVAR and friends. -- Scott  Mail-from: ARPANET site SU-AI rcvd at 6-Apr-83 2239-PST Received: from USC-ECL by SU-AI with NCP/FTP; 6 Apr 83 22:37:37 PST Received: from MIT-MC by USC-ECL; Wed 6 Apr 83 22:36:07-PST Date: Thursday, 7 April 1983 01:31-EST From: MOON at SCRC-TENEX To: Guy.Steele at CMU-CS-A Cc: common-lisp%SU-AI at usc-ecl, Moon at SCRC-TENEX Subject: Proposed change to SPECIAL: quick poll In-reply-to: The message of 5 Apr 1983 2216-EST () from Guy.Steele@CMU-CS-A I started to reply to this yesterday, saying "yes, that's the right thing." Then I stopped and thought about it. I also talked it over with Glenn Burke and then slept on it. This is going to have to be a very long letter and I apologize in advance. I am convinced that you have got hold of the wrong end of the stick. First of all, none of this has anything to do with the SPECIAL declaration per se. You are just thinking in terms of the SPECIAL declaration because that is the only one the interpreter looks at. Note, for instance, that if the UNSPECIAL (or LEXICAL or LOCAL) declaration hadn't been (temporarily?) removed from the language as noted on page x of the Laser edition of the manual, the interpreter would need to look at those declarations as well, and precisely the same issues would arise. My first reaction was "yes, the concept of top-level is ill-defined, let's get rid of it." But "top-level" is perfectly well-defined! See the first sentence under DECLARE on page 101 of the manual: A DECLARE form at the beginning of the body of certain special forms is a local declaration; all other DECLARE forms are either top-level or errors. Now, what may be ill-defined is when you should signal the error versus when you treat it as top level; but this is entirely an issue for DECLARE, has nothing to do with SPECIAL, and would not be affected in any real way by renaming SPECIAL to GLOBALLY-SPECIAL. I feel reluctant to pontificate about this, since you have written a Common Lisp interpreter and I have not. But I see no way that one could possibly implement the interpreter without having lambda-expressions, and each special form that does bindings and hence allows local declarations, specially check the beginning of their body for DECLARE forms, or macros that expand into DECLARE forms. It is necessary to know what the declarations are before doing the bindings; if you go ahead and do the bindings and let EVAL find the DECLARE while doing the body, it is too late to change a binding from local to special, isn't it? Thus there is no issue of distinguishing local and top-level declarations in the interpreter; all DECLARE forms found by this special check are local, and all others are top-level, or errors. Glenn points out that it isn't really as impossible as all that to implement declaration in the interpreter according to the specifications in the Laser edition, since he has already done it. In fact I am quite willing to believe that it is impractically difficult to implement the second-to-last sentence on page 101 (that an error will be signalled if a DECLARE appears out of place) in the interpreter, and that this would have to be left to the compiler. The various issues in Fahlman's letter having to do with searching the stack and so forth seen to be really about this. If it is important to distinguish erroneous DECLAREs from top-level DECLAREs in the interpreter, then we should give the two kinds of DECLARE (local and top-level) different names. Of course people might then expect the top-level one, when used inside a function, to have a scope restricted to that function.... Seventeen months ago we decided to get rid of GLOBAL-DECLARE (issue 68 from 18 November 1981). Perhaps this was a mistake. If GLOBAL-DECLARE is a poor name, we could call it PROCLAIM. Then DECLARE would signal an error if EVAL ever saw it, while PROCLAIM would work the same way anywhere in the interpreter but would be required to appear only at top level by the compiler, exactly in analogy with DEFUN. If there is "an ugly and confusing exception" here, it is not the behavior of SPECIAL declarations at top level. The exception is the peculiar syntax for local declarations, which are tucked inside the special form they apply to instead of being wrapped around it like everything else in Lisp. Compare the LOCAL-DECLARE special form of the Lisp machine. Of course, the wrapping-around syntax for declarations has its own deep problems: in LET one could not apply a declaration to the variables being bound but not to the forms to which they were bound; the wrapping-around syntax would be highly misleading in combination with Common Lisp's non-pervasiveness of local declarations (which is different from Maclisp), since it doesn't make it obvious that the declarations are attached to one particular binding, not to everything lexically enclosed in a LOCAL-DECLARE. There seem to be good reasons for non-pervasive local declarations, on grounds of both substitution semantics (we don't want inline functions to inherit declarations of their container's variables) and interpreter efficiency (we don't want the interpreter to have to maintain a dynamic declaration list and search it when binding a variable in order to figure out whether the variable should be special or local). Another possible syntax for local declarations is to attach them even more directly to the binding, say something like (let ((x (frobdicate y) special)) ...) This has been discussed before, and it has its own set of problems, which appear to be insuperable. (Different syntax for every binding form, doesn't fit nicely into DEFUN, doesn't provide a reasonable place to put non-binding- associated local declarations). I have to bring up one other issue which Fahlman's letter glossed over. This part I think is specific to the SPECIAL declaration and applies to no other. It is legal to make a local SPECIAL declaration without binding the variable. This isn't explained very well in the Laser edition, but the idea is that such a SPECIAL declaration affects exactly the same references as it would if the variable had been bound by the form to which the declaration is attached. It's pretty easy to see how to implement this in the interpreter: by putting the same marker as you normally would into the lexical environment structure, saying "use the dynamic value", but avoiding the creation of a dynamic binding. Scott's letter might be interpreted as trying to get rid of this unusual usage of the SPECIAL declaration, or it might be interpreted as a mere oversight. I don't see how it could possibly be reasonable to get rid of it, so I assume it's just an oversight. A typical example of the use of this might be: (defun foo (x y) (let ((foo-bar-communication x)) (declare (special foo-bar-communication)) (frob #'bar y))) (defun bar (z) (declare (special foo-bar-communication)) (cdr (assoc z foo-bar-communication))) Conclusions: I suggest that we either (1) Leave everything the way it is in the Laser manual, except specify that the interpreter cannot be expected to detect misplaced declarations and will treat all declares that aren't local as top-level, even if they are inside a form. A misplaced declaration will alter your global environment with no warning. or (2) Say that DECLARE is allowed only at the front of the bodies of the forms listed on page 101 (possibly preceded by a documentation string in the places where one is allowed), and introduce a new special form, PROCLAIM, which makes top-level declarations no matter where it is used. It might make sense to make PROCLAIM a function rather than a special form; this would certainly clarify its difference from DECLARE. I have no personal preference between these.  Mail-from: ARPANET site SU-AI rcvd at 5-Apr-83 1925-PST Received: from CMU-CS-A by SU-AI with NCP/FTP; 5 Apr 83 19:19:27 PST; for: common-lisp Date: 5 April 1983 2216-EST (Tuesday) From: Guy.Steele@CMU-CS-A To: common-lisp@SU-AI Subject: Proposed change to SPECIAL: quick poll I am in favor of the following proposed change to SPECIAL declarations. Making them work two different ways in different contexts was the hardest part of writing the interpreter, and requires an ugly explanation in the manual. Opinions? --Guy - - - - Begin forwarded message - - - - Received: from CMU-CS-PT by CMU-CS-A; 5-Apr-83 10:56:01-EST Received: from CMU-CS-C by CMU-CS-PT; 5 Apr 83 10:48:53 EST Received: ID ; 5 Apr 83 10:51:19 EST Date: Tue, 5 Apr 1983 10:51 EST From: Scott E. Fahlman To: steele@CMU-CS-C Cc: slisp@CMU-CS-C Subject: global specials Guy, In working on the new lexical eval, I have come more and more to believe that the rules for the special declaration are ill-formed. As I understand it, a SPECIAL declaration at the start of a variable-binding form is relevant only to that particular incarnation of the variable in question; a SPECIAL declaration at top-level declares a variable to be globally special; a SPECIAL declaration anywhere else is an error. This "globally special" business is an exception to the general rule about variable-affecting declarations, but it seems absolutely necessary to have global specialness around for the convenient writing of code (using DEFVAR, etc.), so we can't just flush it in the name of uniformity. My problem is that I don't think the concept of TOP-LEVEL is well-defined, and any intuitively correct definition would seem to be computationally intractable. Tying this concept to READ seems wrong, since code could be generated internally or could be read in by something other than the system standard reader. Tying it to what is on the stack at present is expensive and fails in a similar way. For example, it would prevent the user from building a loop that reads things from a file, takes some notes on what is coming in, and then passes the stuff to eval. This EVAL would see user-defined functions on the stack and would not believe itself to be at top level. Any thoughts or suggestions? My best shot at this is to restrict the SPECIAL declaration to appearing at the start of binding forms and to affect only that incarnation, but to introduce a new declaration GLOBALLY-SPECIAL that can appear anywhere and that does what the current top-level SPECIAL declaration does. Then we can keep our defvars and such (converting them to the use of GLOBALLY-SPECIAL, but we don't have to appeal to the concept of "top level". It also cleans up the manual a bit, getting rid of an ugly and confusing exception. The price is that old Maclisp files would have to be converted if they use top-level SPECIAL declarations directly and not via DEFVAR, but that's a fairly small price to pay. Unless you have a better suggestion, I would like to propose this change to Common Lisp and try to get it into the manual in time. In any event, this is what I am currently implementing in the new eval, since I can't see how to make top-levelness win. -- Scott - - - - End forwarded message - - - -  Mail-from: ARPANET site SU-AI rcvd at 5-Apr-83 1920-PST Received: from CMU-CS-A by SU-AI with NCP/FTP; 5 Apr 83 19:19:27 PST; for: common-lisp Date: 5 April 1983 2216-EST (Tuesday) From: Guy.Steele@CMU-CS-A To: common-lisp@SU-AI Subject: Proposed change to SPECIAL: quick poll I am in favor of the following proposed change to SPECIAL declarations. Making them work two different ways in different contexts was the hardest part of writing the interpreter, and requires an ugly explanation in the manual. Opinions? --Guy - - - - Begin forwarded message - - - - Received: from CMU-CS-PT by CMU-CS-A; 5-Apr-83 10:56:01-EST Received: from CMU-CS-C by CMU-CS-PT; 5 Apr 83 10:48:53 EST Received: ID ; 5 Apr 83 10:51:19 EST Date: Tue, 5 Apr 1983 10:51 EST From: Scott E. Fahlman To: steele@CMU-CS-C Cc: slisp@CMU-CS-C Subject: global specials Guy, In working on the new lexical eval, I have come more and more to believe that the rules for the special declaration are ill-formed. As I understand it, a SPECIAL declaration at the start of a variable-binding form is relevant only to that particular incarnation of the variable in question; a SPECIAL declaration at top-level declares a variable to be globally special; a SPECIAL declaration anywhere else is an error. This "globally special" business is an exception to the general rule about variable-affecting declarations, but it seems absolutely necessary to have global specialness around for the convenient writing of code (using DEFVAR, etc.), so we can't just flush it in the name of uniformity. My problem is that I don't think the concept of TOP-LEVEL is well-defined, and any intuitively correct definition would seem to be computationally intractable. Tying this concept to READ seems wrong, since code could be generated internally or could be read in by something other than the system standard reader. Tying it to what is on the stack at present is expensive and fails in a similar way. For example, it would prevent the user from building a loop that reads things from a file, takes some notes on what is coming in, and then passes the stuff to eval. This EVAL would see user-defined functions on the stack and would not believe itself to be at top level. Any thoughts or suggestions? My best shot at this is to restrict the SPECIAL declaration to appearing at the start of binding forms and to affect only that incarnation, but to introduce a new declaration GLOBALLY-SPECIAL that can appear anywhere and that does what the current top-level SPECIAL declaration does. Then we can keep our defvars and such (converting them to the use of GLOBALLY-SPECIAL, but we don't have to appeal to the concept of "top level". It also cleans up the manual a bit, getting rid of an ugly and confusing exception. The price is that old Maclisp files would have to be converted if they use top-level SPECIAL declarations directly and not via DEFVAR, but that's a fairly small price to pay. Unless you have a better suggestion, I would like to propose this change to Common Lisp and try to get it into the manual in time. In any event, this is what I am currently implementing in the new eval, since I can't see how to make top-levelness win. -- Scott - - - - End forwarded message - - - -  Mail-from: ARPANET site SU-AI rcvd at 5-Apr-83 1414-PST Received: from USC-ECL by SU-AI with NCP/FTP; 5 Apr 83 14:13:32 PST Received: from MIT-MC by USC-ECL; Tue 5 Apr 83 14:08:37-PST Received: from SCRC-BEAGLE by SCRC-TENEX with CHAOS; Tue 5-Apr-83 17:13:19-EST Date: Tuesday, 5 April 1983, 17:08-EST From: Daniel L. Weinreb Subject: More trivia To: common-lisp%sail@usc-ecl The manual says that case is ignored after #; that is, #a and #A are the same. Some points are left unclear: Does (set-dispatch-macro-character #\# #\a 'foo) affect the value returned by (get-dispatch-macro-character #\# #\A), and vice versa? If I define my own dispatch macro, is case ignored after it? (I think the simplest solution is to answer "yes" to the second question, such that there's a single "cell" shared by #\a and #\A in all macro dispatch tables. Otherwise, # itself has to be different from everything else, or an indirection mechanism has to be used, or set-syntax-macro-character can make #\a be one thing and #\A be another thing.)  Mail-from: ARPANET site SU-AI rcvd at 4-Apr-83 1142-PST Received: from USC-ECL by SU-AI with NCP/FTP; 4 Apr 83 11:40:16 PST Received: from MIT-MC by USC-ECL; Mon 4 Apr 83 10:20:37-PST Received: from SCRC-BEAGLE by SCRC-TENEX with CHAOS; Mon 4-Apr-83 13:22:32-EST Date: Monday, 4 April 1983, 13:21-EST From: Daniel L. Weinreb Subject: defstruct printed representation To: common-lisp%su-ai@usc-ecl Here's another little one. In the Laser edition, p. 241, it says that structures are printed according to the ":printer" option of defstruct. The defstruct chapter, on p. 207, documents a ":print-function" option, but no ":printer" option, so the manual seems to be inconsistent. Alan says that ":print-function" is right, so we will assume so until we here further.  Mail-from: ARPANET site SU-AI rcvd at 30-Mar-83 1603-PST Received: from SU-SCORE by SU-AI with PUP; 30-Mar-83 16:03 PST Received: from MIT-MC.ARPA by SU-SCORE.ARPA with TCP; Wed 30 Mar 83 15:31:57-PST Received: from SCRC-BULLDOG by SCRC-TENEX with CHAOS; Wed 30-Mar-83 17:22:23-EST Date: Wednesday, 30 March 1983, 17:20-EST From: David A. Moon Subject: short-float-negative-epsilon To: Guy.Steele@CMU-CS-A Cc: common-lisp%su-ai@su-score, Cassels%SCRC-TENEX@MIT-MC Am I correct in guessing that the arguments to - in the Lisp-code definition of short-float-negative-epsilon in the Laser edition are backwards? The code as it stands is clearly bogus. If the arguments to - are backwards, then negative-epsilon would be the smallest positive number that you can subtract from 1.0 and get a different answer than 1.0.  Mail-from: ARPANET site SU-AI rcvd at 30-Mar-83 1135-PST Received: from USC-ECL by SU-AI with NCP/FTP; 30 Mar 83 11:34:22 PST Received: from MIT-MC by USC-ECL; Wed 30 Mar 83 11:28:05-PST Date: Wednesday, 30 March 1983, 14:18-EST From: David A. Moon Subject: char-not-equal To: Bernard S. Greenberg Cc: common-lisp@su-ai at usc-ecl at mit-mc, common-lisp-implementors@SCRC-TENEX at MIT-MC at mit-mc In-reply-to: The message of 29 Mar 83 16:07-EST from Bernard S. Greenberg Date: Tuesday, 29 March 1983, 16:07-EST From: Bernard S. Greenberg What is char-not-equal supposed to do when given more than 2 arguments, and if so, why? That is to say, do all the characters have to be not equal, or just any 2 of them? Surely the same thing as /=, i.e. true if and only if all the characters are different. Unfortunately the Laser edition of the manual requires one to indirect through two levels of "x is like y" to find this out.  Mail-from: ARPANET site SU-AI rcvd at 30-Mar-83 1135-PST Received: from USC-ECL by SU-AI with NCP/FTP; 30 Mar 83 11:34:48 PST Received: from MIT-MC by USC-ECL; Wed 30 Mar 83 11:28:50-PST Received: from SCRC-BULLDOG by SCRC-TENEX with CHAOS; Wed 30-Mar-83 14:21:17-EST Date: Wednesday, 30 March 1983, 14:19-EST From: David A. Moon Subject: char-not-equal To: Bernard S. Greenberg Cc: common-lisp%su-ai@usc-ecl, common-lisp-implementors%SCRC-TENEX@MIT-MC In-reply-to: The message of 29 Mar 83 16:07-EST from Bernard S. Greenberg Date: Tuesday, 29 March 1983, 16:07-EST From: Bernard S. Greenberg What is char-not-equal supposed to do when given more than 2 arguments, and if so, why? That is to say, do all the characters have to be not equal, or just any 2 of them? Surely the same thing as /=, i.e. true if and only if all the characters are different. Unfortunately the Laser edition of the manual requires one to indirect through two levels of "x is like y" to find this out.  Mail-from: ARPANET site SU-AI rcvd at 30-Mar-83 0800-PST Received: from USC-ECL by SU-AI with NCP/FTP; 30 Mar 83 07:59:05 PST Received: from MIT-MC by USC-ECL; Wed 30 Mar 83 07:56:10-PST Date: Wednesday, 30 March 1983, 10:39-EST From: Bernard S. Greenberg Subject: digit-weight To: Common-Lisp@SU-AI at USC-ECL at mit-mc Cc: Common-Lisp-Implementors at SCRC-TENEX at mit-mc On p. 155 of the Laser manual, is the name of the function digit-weight or digit-char?  Mail-from: ARPANET site SU-AI rcvd at 29-Mar-83 1335-PST Received: from USC-ECL by SU-AI with NCP/FTP; 29 Mar 83 13:34:33 PST Received: from MIT-MC by USC-ECL; Tue 29 Mar 83 13:33:17-PST Received: from SCRC-BORZOI by SCRC-TENEX with CHAOS; Tue 29-Mar-83 16:12:07-EST Date: Tuesday, 29 March 1983, 16:07-EST From: Bernard S. Greenberg Subject: char-not-equal To: common-lisp%su-ai@usc-ecl Cc: common-lisp-implementors%SCRC-TENEX@MIT-MC What is this function supposed to do when given more than 2 arguments, and if so, why? That is to say, do all the characters have to be not equal, or just any 2 of them? I can envision a game program that says, "Type 6 different characters to ...", and then uses this function to barf at you, but short of that, it seems pretty fraudulent. BTW, please put me on the common-lisp@su-ai mailing list, thanks.  Mail-from: ARPANET site SU-AI rcvd at 29-Mar-83 0851-PST Received: from USC-ECL by SU-AI with NCP/FTP; 29 Mar 83 08:49:42 PST Received: from MIT-MC by USC-ECL; Tue 29 Mar 83 08:46:35-PST Date: Tuesday, 29 March 1983, 11:35-EST From: Daniel L. Weinreb Subject: #nA(...) To: "common-lisp%su-ai" at usc-ecl at mit-mc Yes, indeed, in #nA format the "n" is required. Now I know why. Perhaps the next edition of the manual should make this more explicit, so that people like me who don't think hard enough won't be misled. Never mind...  Mail-from: ARPANET site SU-AI rcvd at 28-Mar-83 1541-PST Received: from USC-ECL by SU-AI with NCP/FTP; 28 Mar 83 11:37:35 PST Received: from MIT-ML by USC-ECL; Mon 28 Mar 83 11:01:09-PST Date: Monday, 28 March 1983, 13:56-EST From: Daniel L. Weinreb Subject: #A() To: "common-lisp%su-ai" at usc-ecl The syntax #A() is ambiguous; it could either mean a 1-D array with 0 elements, or a 0-D array whose (sole) element is NIL. This is because () is both a list and a symbol. I truly think that it would be in the best interests of everyone on the list if each of us would manage to refrain from re-opening the dispute as to whether the empty list and the symbol NIL should be the same or not. We have spent considerable time going over this ground, and the decision has been made. The only reasonable thing I can see is to define it to be a 1-D array with 0 elements, define it to be a 0-D array containing a NIL, or define it to signal an error. Leaving it officially undefined can only lead to trouble; surely it's no significant extra work to check for this case and signal an error. (I imagine someone will suggest making "#A()" and "#ANIL" be distinguished, and so I'd like to express my extreme disapproval of this idea right away. Primarily, it would be completely inconsistent with the rest of the language definition. Secondarily, it would be very clumsy to implement.)  Mail-from: ARPANET site SU-AI rcvd at 28-Mar-83 1209-PST Received: from USC-ECL by SU-AI with NCP/FTP; 28 Mar 83 11:37:35 PST Received: from MIT-ML by USC-ECL; Mon 28 Mar 83 11:01:09-PST Date: Monday, 28 March 1983, 13:56-EST From: Daniel L. Weinreb Subject: #A() To: "common-lisp%su-ai" at usc-ecl The syntax #A() is ambiguous; it could either mean a 1-D array with 0 elements, or a 0-D array whose (sole) element is NIL. This is because () is both a list and a symbol. I truly think that it would be in the best interests of everyone on the list if each of us would manage to refrain from re-opening the dispute as to whether the empty list and the symbol NIL should be the same or not. We have spent considerable time going over this ground, and the decision has been made. The only reasonable thing I can see is to define it to be a 1-D array with 0 elements, define it to be a 0-D array containing a NIL, or define it to signal an error. Leaving it officially undefined can only lead to trouble; surely it's no significant extra work to check for this case and signal an error. (I imagine someone will suggest making "#A()" and "#ANIL" be distinguished, and so I'd like to express my extreme disapproval of this idea right away. Primarily, it would be completely inconsistent with the rest of the language definition. Secondarily, it would be very clumsy to implement.)  Mail-from: ARPANET site SU-AI rcvd at 28-Mar-83 1156-PST Received: from USC-ECL by SU-AI with NCP/FTP; 28 Mar 83 11:37:35 PST Received: from MIT-ML by USC-ECL; Mon 28 Mar 83 11:01:09-PST Date: Monday, 28 March 1983, 13:56-EST From: Daniel L. Weinreb Subject: #A() To: "common-lisp%su-ai" at usc-ecl The syntax #A() is ambiguous; it could either mean a 1-D array with 0 elements, or a 0-D array whose (sole) element is NIL. This is because () is both a list and a symbol. I truly think that it would be in the best interests of everyone on the list if each of us would manage to refrain from re-opening the dispute as to whether the empty list and the symbol NIL should be the same or not. We have spent considerable time going over this ground, and the decision has been made. The only reasonable thing I can see is to define it to be a 1-D array with 0 elements, define it to be a 0-D array containing a NIL, or define it to signal an error. Leaving it officially undefined can only lead to trouble; surely it's no significant extra work to check for this case and signal an error. (I imagine someone will suggest making "#A()" and "#ANIL" be distinguished, and so I'd like to express my extreme disapproval of this idea right away. Primarily, it would be completely inconsistent with the rest of the language definition. Secondarily, it would be very clumsy to implement.)  Mail-from: ARPANET site SU-AI rcvd at 28-Mar-83 1139-PST Received: from USC-ECL by SU-AI with NCP/FTP; 28 Mar 83 11:37:35 PST Received: from MIT-ML by USC-ECL; Mon 28 Mar 83 11:01:09-PST Date: Monday, 28 March 1983, 13:56-EST From: Daniel L. Weinreb Subject: #A() To: "common-lisp%su-ai" at usc-ecl The syntax #A() is ambiguous; it could either mean a 1-D array with 0 elements, or a 0-D array whose (sole) element is NIL. This is because () is both a list and a symbol. I truly think that it would be in the best interests of everyone on the list if each of us would manage to refrain from re-opening the dispute as to whether the empty list and the symbol NIL should be the same or not. We have spent considerable time going over this ground, and the decision has been made. The only reasonable thing I can see is to define it to be a 1-D array with 0 elements, define it to be a 0-D array containing a NIL, or define it to signal an error. Leaving it officially undefined can only lead to trouble; surely it's no significant extra work to check for this case and signal an error. (I imagine someone will suggest making "#A()" and "#ANIL" be distinguished, and so I'd like to express my extreme disapproval of this idea right away. Primarily, it would be completely inconsistent with the rest of the language definition. Secondarily, it would be very clumsy to implement.)  Mail-from: ARPANET site SU-AI rcvd at 14-Mar-83 1111-PST Received: from SU-SCORE by SU-AI with PUP; 14-Mar-83 11:10 PST Received: from CMU-CS-SPICE ([128.2.254.139]) by SU-SCORE.ARPA with TCP; Mon 14 Mar 83 11:04:09-PST Date: Monday, 14 March 1983 13:57:16 EST From: Joseph.Ginder@CMU-CS-SPICE To: Common-Lisp%su-ai@score Subject: LetS in Common Lisp After having read Waters' recently distributed LetS proposal, I have the following comments. (1) Destructuring in general is not supported in Common Lisp; LetS is proposed as allowing destructuring. (This is obviouly a minor point.) (2) The notions of LetS sequence and generic sequence are bound to be confused by many users. If LetS is adopted as part of the Common Lisp white pages, these notions should be completely integrated so that there is only one notion of "sequence". Or at least they should be clearly differentiated, both in the manual descriptions and in name. I have no proposal for either of these alternatives. (3) Unitary operators generalizing to work for sequences is inconsistent with the rest of Common Lisp. (Eg. (+ '(1 2 3) '(4 5 6)) does not work.) (4) LetS seems (to me) at least as "experimental" as Flavors. Don't get me wrong; I like flavors. However, I do not believe them to be a generally accepted method of implementing object-oriented programming in all its glory (no pun intended); there are questions as to how inheritance should be done, etc. Therefore, I believe they should be in the yellow pages. I believe LetS to be even less generally accepted and open for further discussion. LetS seems a reasonable candidate for the yellow pages also. Now that my position on LetS in Common Lisp is clear, I have a few comments on it in general. (Those who have not read Waters' proposal probably want to ignore the rest of this.) I'm not prepared to say that it may not be useful, but I have several problems with it. Basically, it seems as though it is an attempt to get both functional composition and efficiency; functional composition for the way it satisfies Waters' three required properties of looping constructs (understandability, constructability, and modifiability -- in that order), efficiency for obvious reasons. I have two specific quarrels with the examples he gives in the section of his proposal on comparison with other loop notations using "sum-positive". (1) Tail Recursive Style. Waters defines a tail-recursive sum-positive. I would not do this. Instead, I would say something like "(sum (positives vector)). Then sum and positives could be defined in the obvious tail-recursive manner. This clearly separates the "fragments that the loop is composed of" while retaining the other advantages of the tail-recursive style which Waters acknowledges. The only advantage left for LetS is efficiency. A smart compiler (or LetS-type preprocessor even) could perform transformations similar to those performed by LetS and generate comparably efficient code, could it not? Tail recursion clearly defines an execution order, so correctness preserving should be less of a problem in doing this conversion. This is only a first reaction without too much reflection, so apologies for obvious errors in my reasoning. (2) Map Style. In Common Lisp, the mapping functions can express sum-positive very easily. First of all, define a type "positive-number" (deftype positive-number () (or (rational (0) *) (float (0.0) *))) then define a predicate (defun PlusP (n) (typep n 'positive-number)) then sum-positive: (defun sum-postive (vector) (mapcar #'+ (map 'list #'PlusP vector))) Efficiency questions are similar to those for tail recursion. Despite these arguments, I'm willing to concede that LetS may be useful in other instances and have no quarrel with putting it in the yellow pages so we can find out. Perhaps a way of generating efficient compiled code for functional compositions (and map's) is a more general solution to this problem. -Joe Ginder P.S. Due to mail problems, this is several days old ...  Mail-from: ARPANET site SU-AI rcvd at 10-Mar-83 1207-PST Received: from SU-SCORE by SU-AI with PUP; 10-Mar-83 11:47 PST Received: from PARC-MAXC.ARPA by SU-SCORE.ARPA with TCP; Thu 10 Mar 83 11:46:08-PST Date: 10 Mar 83 11:41 PST From: JonL.PA@PARC-MAXC.ARPA Subject: Upcoming Manual work, and Compatibililty issue. To: Guy.Steele@CMUA.ARPA cc: Common-Lisp%SU-AI@SU-SCORE.ARPA Presumably you're just fixing errors in the manual and not soliciting ballot-able questions. Sooner or later the issue will have to be addressed about a formal mechanism for changes and additions -- wasn't it our idea early on that at some infrequent interval (6 months, 1 year?) we'd open things up for some hopefully conservative changes? Also, about a week ago I sent out a note to Common-Lisp%SU-AI@SU-SCORE which hasn't appeared in my mail box yet, so I presume it to have been lost in the shuffle. The gist of this note was ask for re-confirmation of our original mandate of remaining generally compatible with MacLisp/LispM, unless there were verry good reason; thus APPEND remains for lists only (using a new function CONCATENATE for the others), and the name change of HAULONG to INTEGER-LENGTH was ocasioned only after a ballot vote. Since the deletion of LOAD-BYTE etc didn't go to the ballots, we may need to re-consider it; especially if the only solution to the quagmire I pointed out in December last is to force a totally incompatible change onto the MacLisp/ LispM world. A change, I might add, which would do them no good at all, since they've had LOAD-BYTE etc for many years; VAX/NIL had it from the beginning, and merely used it to build up whatever semantics LDB required (the VAX has a load-byte-indexed instruction -- EXTZV). Last fall, I put LOAD-BYTE and LDB (as specified in the "Laser Edition) into Interlisp. Since Interlisp-D has neither a load-byte-indexed nor a ldb instruction, I did it by macros which merely convert LDB into LOAD-BYTE format, and others which convert LOAD-BYTE into more primitive Lisp (which is fully adequate, given the bytelap instruction set). There has frequently been a misconception that the "conversion" just mentioned is a compiler question; I haven't maintained this position, and I don't know why it keeps popping up like a red herring; it is just macro-expansion. The only non-trivial functions needed by the expanders were one which tested a form for being a constant under EVAL, and another which tested if two forms were EVAL-independent (and thus commutable when computing them). These two functions needn't be complete; simply being fail-safe is adequate, but the more "complete" they become, the more efficient will be the output of the various macros. This code, although copyright by Xerox, would, I'm sure, be publicly available to anyone who wants it. Ocasionally, there has been confusion as to the value of having integers and bit-vector sequences as separate types. I've long ago pointed out the desirablilty of not constraining the way in which the various implementations must implement integers. But bit-vector semantics requires updating, which would rule out "immediate" number formats; they also require storage according to length, which would impose, say, zeros of differing integer-lengths -- a most odd and non-canonical, but not entirely impossible, situation for numbers. Others have recently made similar points in these mails. The confusion comes by overkill -- the idea that since there are two distinct data types, then integers can't be viewed as sequences. For an early counter to this notion, see Goedel's 1931 paper on the essential incompleteness of axiomatic arithmetic. Even the current notion, spawned as it is by the existence of binary storage devices, is machine independent. (Think about why we have INTEGER-LENGTH.) The constraint is merely that bit-vectors must not be limited to our efficiently-implemented integers. Incidentally, the pdp10 LDB instruction is surely a cretinous remnant of the fact that the pdp6/pdp10 didn't have any notion of load-byte-indexed. Evidentally, ILDB was the provision so that one could "walk" through a sequence of bytes without doing the division inherent in load-byte-indexed; LDB was an obvious "corollary". It should be no surprise that division on the pdp6 was abysmally slow. Newer hardware often has a single instruction to do the load-byte-indexed, indicating its utility over the ldb format. In Lisp, there is no particularly good reason to have a byte specifier as an independent data type -- a cons of two indices would serve just as well -- just as there is no reason to suppose that a "subsequence specifier" (used, say, to specify the 3rd through 5th elements of a vector) is a pressingly useful concept.  Mail-from: ARPANET site SU-AI rcvd at 10-Mar-83 0909-PST Received: from SU-SCORE by SU-AI with PUP; 10-Mar-83 09:06 PST Received: from PARC-MAXC.ARPA by SU-SCORE.ARPA with TCP; Thu 10 Mar 83 09:07:27-PST Date: 10 Mar 83 09:03 PST From: JonL.PA@PARC-MAXC.ARPA Subject: number of arguments limitation To: GSB@MIT-ML.ARPA cc: Common-Lisp%SU-AI@SU-SCORE.ARPA Re: your msg of 1 Mar 83 00:14 EST I think you're right about the performance penalty when a VAX lisp skirts using CALLS in a natural way; unfortunately, hard data don't come easily on this point. Perhaps one could compare, not just raw runtimes, but rather the percentage of runtime spent in the function-to-function linkage on some typical benchmarks (TAK comes to mind but . . . ). I'd expect VAX/NIL to have a modest value here, Interlisp/VAX to be moderately larger, and Spice/LISP (as currently implemented) to be quite large on this measure.  Mail-from: ARPANET site SU-AI rcvd at 4-Mar-83 1555-PST Received: from SU-SCORE by SU-AI with PUP; 04-Mar-83 15:36 PST Received: from RUTGERS by SU-SCORE.ARPA with TCP; Fri 4 Mar 83 15:35:29-PST Date: 4 Mar 1983 1832-EST From: Ron Subject: What is SPIRRAT.SLISP? To: common-lisp@SU-AI Why it's the file that contains definitions for dealing with irrationals of course... Still more *;-) (ron) -------  Mail-from: ARPANET site SU-AI rcvd at 4-Mar-83 1555-PST Received: from SU-SCORE by SU-AI with PUP; 04-Mar-83 15:50 PST Received: from RUTGERS by SU-SCORE.ARPA with TCP; Fri 4 Mar 83 15:33:01-PST Date: 4 Mar 1983 1830-EST From: Ron Subject: Re: Recent ballot To: common-lisp@SU-AI I believe that, taken in a non-mathematical context, this line from the file SPIRRAT.SLISP says it all: "...irrational functions are part of the standard Spicelisp environment." Uh hum... also :-) (ron) -------  Mail-from: ARPANET site SU-AI rcvd at 1-Mar-83 1950-PST Received: from CMU-CS-A by SU-AI with NCP/FTP; 1 Mar 83 19:50:54 PST; for: common-lisp Date: 1 March 1983 2247-EST (Tuesday) From: Guy.Steele at CMU-CS-A To: common-lisp at SU-AI Subject: NMapDelRassRevAppCatSqrtQ Perhaps I shouldn't have been so deadpan; I thought surely everyone would recognize Skef's proposal as a joke. (The last line of his message contained the glyph :-) which is a not-yet-widely-known joke indicator (it's a smiling face).) Anyway, the mailing system does seem to be improving. I am going to make another big pass at the manual during March. --Guy  Mail-from: ARPANET site SU-AI rcvd at 28-Feb-83 2123-PST Received: from SU-SCORE by SU-AI with PUP; 28-Feb-83 21:22 PST Received: from MIT-ML.ARPA by SU-SCORE.ARPA with TCP; Mon 28 Feb 83 21:19:44-PST Date: 1 March 1983 00:14 EST From: Glenn S. Burke Subject: number of arguments limitations To: common-lisp%su-ai @ SU-SCORE cc: moon @ SCRC-TENEX All NIL function calls are done as VAX procedure calls, so currently may receive no more than 252 arguments (255 minus 3 hidden args), because for some reason DEC has reserved 24 of the 32 bits in the longword where this count is stored. The number of argument checking, &optional defaulting, and &rest-vector formation is essentially inline coded (with the help of some subroutines in the more complex cases). It appears to be possible to change this restriction to (about) 250 requireds + optionals, with little or no penalty when less than that number of arguments (total) is passed. I believe there would be an efficiency penalty to removing the restriction on number of optionals, and probably a severe one for eliminating use of the VAX procedure call mechanism entirely to eliminate all restrictions.  Mail-from: ARPANET site SU-AI rcvd at 28-Feb-83 2026-PST Received: from SU-SCORE by SU-AI with PUP; 28-Feb-83 20:24 PST Received: from CMU-CS-C by SU-SCORE.ARPA with TCP; Mon 28 Feb 83 20:22:31-PST Received: ID ; 28 Feb 83 23:18:07 EST Date: 28 Feb 83 23:18:06 EST From: Scott E. Fahlman To: Common-Lisp%su-ai@SU-SCORE Subject: Implementation Limits I tried sending this earlier, but the mail came bouncing back. Just for the record, our Spice/PERQ implementation puts no limit on the number of args to an apply or to any &rest arg, unless you run out of virtual memory or disk -- this will happen before you get into bignums for the argument count. We currently cut off the number of symbols and constants in a function at 32K, locals at 2K, and non-rest arguments at 255. Our branch offsets are only 16 bits, so function objects cannot be longer than 64K bytes. If any of this ever gets in the way, we'll fix it, but I think it is safe to say that any program that violates these limits would also violate good coding style in Lisp. The only real worry is that program-generating programs might produce some bizarre giant-sized function. I believe that the Vax Common Lisp implementation has less stringent limits. -- Scott  Mail-from: ARPANET site SU-AI rcvd at 28-Feb-83 1407-PST Received: from SU-SCORE by SU-AI with PUP; 28-Feb-83 14:06 PST Received: from MIT-MC.ARPA by SU-SCORE.ARPA with TCP; Mon 28 Feb 83 13:52:21-PST Date: Monday, 28 February 1983 16:25-EST From: MOON at SCRC-TENEX to: Common-Lisp%su-ai at SU-SCORE Subject: (APPLY #'CONCATENATE 'STRING L) In-reply-to: The message of 27 FEB 83 22:29 PST from MASINTER.PA@PARC-MAXC.ARPA Date: 27 FEB 83 22:29 PST From: MASINTER.PA@PARC-MAXC.ARPA Subject: (APPLY #'CONCATENATE 'STRING L) To: Common-Lisp%su-ai@SU-SCORE.ARPA The problem is that, as far as I can tell, implementations have a limit on the number of arguments they are willing to apply. I can't find anything in the manual that would permit implementations to limit the length of an &REST argument. I certainly hope that Common Lisp does not allow such restrictions. The CADR and LM-2 Lisp machines do have such a restriction currently in certain cases, I believe including the one in the subject of this message (back-translating from Common Lisp to Zetalisp). This misimplementation of APPLY will of course have to be fixed as part of implementing Common Lisp on those machines. The 3600 Lisp machine naturally does it right already, not being so old and moldy. Does anyone else have an implementation that would have any problem with APPLY of a function with an &REST parameter to a very long list? By the way, the manual (Laser edition) says nothing about possible implementation-dependent restrictions on the number of required and optional parameters to a function, total size of a function, and things like that. I don't know about anyone else's implementations, but mine have such restrictions, although they are pretty liberal. The Xerox D machines and the PERQ are probably similar in this respect. For true portability, minimum maxima ought to be specified, I guess.  Mail-from: ARPANET site SU-AI rcvd at 28-Feb-83 1437-PST Received: from SU-SCORE by SU-AI with PUP; 28-Feb-83 14:36 PST Received: from RUTGERS by SU-SCORE.ARPA with TCP; Mon 28 Feb 83 14:32:53-PST Date: 28 Feb 1983 1727-EST From: HEDRICK@RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) Subject: Re: (APPLY #'CONCATENATE 'STRING L) To: MOON@SCRC-TENEX cc: Common-Lisp%su-ai@SU-SCORE In-Reply-To: Your message of 28-Feb-83 1725-EST I strongly oppose the concept of limiting the number of arguments allowed in function calls or APPLY. We could have saved ourselves immense amounts of work be having such a limit in the DEC-20 implementation, but we do not (except of course available address space - about 16Mbytes). -------  Mail-from: ARPANET site SU-AI rcvd at 27-Feb-83 2324-PST Received: from SU-SCORE by SU-AI with PUP; 27-Feb-83 23:24 PST Received: from PARC-MAXC.ARPA by SU-SCORE.ARPA with TCP; Sun 27 Feb 83 22:33:45-PST Date: 27 FEB 83 22:29 PST From: MASINTER.PA@PARC-MAXC.ARPA Subject: (APPLY #'CONCATENATE 'STRING L) To: Common-Lisp%su-ai@SU-SCORE.ARPA The problem is that, as far as I can tell, implementations have a limit on the number of arguments they are willing to apply. Is this not true? Larry  Mail-from: ARPANET site SU-AI rcvd at 27-Feb-83 2306-PST Received: from SU-SCORE by SU-AI with PUP; 27-Feb-83 23:06 PST Received: from MIT-MC.ARPA by SU-SCORE.ARPA with TCP; Sun 27 Feb 83 22:02:35-PST Date: Monday, 28 February 1983, 00:58-EST From: David A. Moon Subject: concatenating strings To: MASINTER.PA at PARC-MAXC, KMP at MIT-MC Cc: Common-Lisp%Su-AI at SU-SCORE In-reply-to: The message of 27 Feb 83 22:34-EST from MASINTER.PA at PARC-MAXC.ARPA, The message of 28 Feb 83 00:11-EST from Kent M. Pitman Date: 27 FEB 83 19:34 PST From: MASINTER.PA@PARC-MAXC.ARPA A simple way of taking a list of strings and turning it into a single string of the list concatenated. I don't know why KMP suggested you call STRING-APPEND, a function that was removed from the language because some people out there didn't like it. Anyway, the correct answer to that query seems to be (APPLY #'CONCATENATE 'STRING L) which doesn't seem too un-simple. You can also do it with REDUCE, but not quite as nicely. The other two queries don't have good answers. I certainly agree that this language is not the ultimate and will need a lot more work. I think it's a worthwhile start, though. Primitives for dealing with time-intervals, e.g., give me a designator for a time three hours from now. (+ (get-universal-time) (* 3 60. 60.)). But of course that doesn't work for things of variable length, like months and years. The Common Lisp time functions are distinctly oversimplified. Perhaps a more realistic set can be provided as a portable package? Simple ways of dealing with file access paths, file versions. This is pretty vague...I don't think much of the Common Lisp pathname stuff, but I'm not sure what you want. A lot of its problem is that it's too simple.  Mail-from: ARPANET site SU-AI rcvd at 27-Feb-83 1938-PST Received: from USC-ECL by SU-AI with NCP/FTP; 27 Feb 83 19:38:39 PST Received: from PARC-MAXC by USC-ECL; Sun 27 Feb 83 19:35:37-PST Date: 27 FEB 83 19:34 PST From: MASINTER.PA@PARC-MAXC.ARPA Subject: Ballot proposal To: Common-Lisp%Su-AI@USC-ECL.ARPA This is the first piece of Common-Lisp mail I've gotten since early December. I assume it is a joke. Has there been any serious mail in the last three months? More suitable for a white pages discussion are functions which are difficult to write using current primitives. We've been trying to follow the rule that, when adding things to Interlisp, we should try to follow Common Lisp if the same functionality exists in Common Lisp. So far, the three or four times I've looked for something, I've been unable to find anything suitable. This might lead one to believe that the white pages might be woefully incomplete as a sufficient base to build a machine independent environment which is written only in terms of white-pages primitives. The things we were looking for (rather simple): a simple way of taking a list of strings and turning it into a single string of the list concatenated. Primitives for dealing with time-intervals, e.g., give me a designator for a time three hours from now. Simple ways of dealing with file access paths, file versions. Larry  Mail-from: ARPANET site SU-AI rcvd at 26-Feb-83 1759-PST Received: from CMU-CS-A by SU-AI with NCP/FTP; 26 Feb 83 17:57:18 PST; for: common-lisp Date: 24 February 1983 2344-EST (Thursday) From: Guy.Steele at CMU-CS-A To: common-lisp at SU-AI Subject: Proposed Common LISP Function (forwarded) Please return your comments on the enclosed proposal no later than February 30. A ballot is enclosed for your convenience. O f f i c i a l B a l l o t - F e b r u a r y 1 9 8 3 ( ) Yes ( ) No --Guy - - - - Begin forwarded message - - - - Mail-From: CMUFTP host CMU-CS-PT received by CMU-CS-A at 21-Feb-83 14:14:47-EST Received: from CMU-CS-C by CMU-CS-PT; 21 Feb 83 14:02:55 EST Received: ID ; 21 Feb 83 14:12:15 EST Date: 21 Feb 83 14:12:10 EST From: Skef Wholey To: Slisp@CMU-CS-C Subject: Newly proposed Common Lisp Function: NMapDelAssCarQ Gee, I've been writing tons of code recently in which I've been destructively MapCar'ing and DelAssQ'ing at the same time. Common Lisp has neither NMapCar (which destructively modifies the list passed to it to build the result) nor DelAssQ (a good old MacLisp function). But NMapDelAssCarQ is essential to my work. Here's a proposed definition (which comiles into less than 50 Spice Lisp instructions): ;;; -*- Lisp -*- ;;; ;;; NMapDelAssCarQ for Common Lisp. ;;; (defun nmapdelasscarq (function item list) "NMapDelAssCarQ cdrs down the given List. If the car of the car of the list is EQ to the given Item, the car is spliced out of the list, and the Function is called with it's car. A result is built from those function calls using the deleted conses. This result and the altered List are returned as multiple values." (let ((map-result (list nil)) (del-result list)) (do ((list list (cdr list)) (map-splice map-result) (del-splice ())) ((atom list) (rplacd map-splice nil)) (cond ((eq item (car list)) (cond ((null del-splice) (setq map-splice (cdr (rplacd map-splice (rplaca (car list) (funcall function (car list)))))) (setq list (cdr list))) (t (rplacd del-splice (cdr list))))) (t (setq del-splice list)))) (values (cdr map-result) del-result))) In addition, it might be useful to define NMapDelAssCarQ*, which is like NMapDelAssCarQ, but returns the values in reverse order. --Skef :-) - - - - End forwarded message - - - -  Date: Wednesday, 12 January 1983 15:36-EST From: MOON at SCRC-TENEX To: common-lisp at sail Subject: Two small issues, and a test of whether the DCA has broken this mailing list 1. symbol-print-name should be called symbol-name. This is more consistent with everything else that has a name, and there is nothing sacred about the term "print name". 2. Making READ-PRESERVING-WHITESPACE a function rather than a special variable you bind around a call to READ is nice. However, it brings up the same problem with recursive calls to READ as #= does (my comment about that, extracted from my general Laser-edition comments, is enclosed for reference). Suppose you do (READ-PRESERVING-WHITESPACE)'FOO; that should preserve the space just as if there were no quote. But if the quote macro character is defined the way it is in the example on page 236, this won't happen; the inner call to READ will swallow the space. If the quote macro character isn't really defined that way, and that is just an oversimplified pedagogical example, then how are users supposed to define their own macros? I think the old Maclisp "TYIMAN" family of crocks are still with us. * 233: (#=) It says the scope is "the outermost call to READ". Interaction between recursive calls to READ is certainly mysterious. Probably there is a kludge in BREAK to prevent the next READ from thinking it is called recursively. I'd rather see a different function for macro-character functions that want to read sub-expressions to call. This would unfortunately imply that READ-DELIMITED-LIST is illegal for anything but a macro-character to call, since it has to know which version of READ to use. If we don't add a separate function, this mysteriosity should be carefully documented. -- Moon  Date: Thursday, 23 December 1982, 17:09-EST From: Bernard S. Greenberg Sender: jek at SCRC-VIXEN Subject: parse-number To: Moon at SCRC-TENEX at mit-mc Cc: lisp-designers at SCRC-TENEX at mit-mc, Common-Lisp at SU-AI at mit-mc In-reply-to: The message of 22 Dec 82 22:42-EST from Moon at SCRC-TENEX Date: Wednesday, 22 December 1982, 22:42-EST From: David A. Moon Date: Tuesday, 21 December 1982, 14:57-EST From: Bernard S. Greenberg I was willing to believe that zwei appreciates the fact that zwei:parse-number by default did not complain about non-numeric digits. However, I refuse to believe that this is the correct default for the now globalized parse-number, documented in the 4.0 Release Notes. I cannot believe that the world will believe a number parsing routine that by default does not complain about invalid numbers: the time to fix it is now. The Common Lisp copy of this function is compatible with this except for the names of the arguments. But perhaps it is wrong, too? Note, however, that READ-FROM-STRING does exactly the same thing. Yes, it is wrong. I would like to hear any arguments for why it is thought to be right.  Date: Thursday, 23 December 1982, 13:40-EST From: Daniel L. Weinreb Subject: parse-number To: DLA at SCRC-TENEX at MIT-MC Cc: lisp-designers at SCRC-TENEX at MIT-MC, Common-Lisp at SU-AI In-reply-to: The message of 23 Dec 82 00:06-EST from David L. Andre Ah. That reminds me why parse-number works the way it does. parse-number is intended to be a tool to help you parse your way through a string. If you encounter a digit on your way from the left end of the string to the right end, you call parse-number, and it reads in as much of the string as is a number and tells you where it stopped so that you can continue to parse the string. Whether you expected the entire string to be a number or not is up to you, and parse-number can be useful in both cases so the "best" default value for the fail-if-not-whole-string argument is not obvious. I don't think it's too important as long as the documentation makes it clear.  Date: Thursday, 23 December 1982, 15:37-EST From: Bernard S. Greenberg Subject: parse-number To: dlw at SCRC-TENEX at mit-mc, DLA at SCRC-TENEX at mit-mc Cc: lisp-designers at SCRC-TENEX at mit-mc, Common-Lisp at SU-AI at mit-mc In-reply-to: The message of 23 Dec 82 13:40-EST from Daniel L. Weinreb Date: Thursday, 23 December 1982, 13:40-EST From: Daniel L. Weinreb Ah. That reminds me why parse-number works the way it does. parse-number is intended to be a tool to help you parse your way through a string. If you encounter a digit on your way from the left end of the string to the right end, you call parse-number, and it reads in as much of the string as is a number and tells you where it stopped so that you can continue to parse the string. Whether you expected the entire string to be a number or not is up to you, and parse-number can be useful in both cases so the "best" default value for the fail-if-not-whole-string argument is not obvious. I don't think it's too important as long as the documentation makes it clear. Now I see. So parse-number is designed to help you implement user interfaces where fields are delimited from each other by what kind of characters they contain, not spaces, commas, or other such. I have used parse-number countless times since I came here, and not once wanted its current behavior. Does anyone acknowledge this point about the current behavior implying peculiar user interfaces?  Date: Thursday, 23 December 1982, 13:40-EST From: Daniel L. Weinreb Subject: parse-number To: DLA at SCRC-TENEX at MIT-MC Cc: lisp-designers at SCRC-TENEX at MIT-MC, Common-Lisp at SU-AI In-reply-to: The message of 23 Dec 82 00:06-EST from David L. Andre Ah. That reminds me why parse-number works the way it does. parse-number is intended to be a tool to help you parse your way through a string. If you encounter a digit on your way from the left end of the string to the right end, you call parse-number, and it reads in as much of the string as is a number and tells you where it stopped so that you can continue to parse the string. Whether you expected the entire string to be a number or not is up to you, and parse-number can be useful in both cases so the "best" default value for the fail-if-not-whole-string argument is not obvious. I don't think it's too important as long as the documentation makes it clear.  Date: Thursday, 23 December 1982, 13:40-EST From: Daniel L. Weinreb Subject: parse-number To: DLA at SCRC-TENEX at MIT-MC Cc: lisp-designers at SCRC-TENEX at MIT-MC, Common-Lisp at SU-AI In-reply-to: The message of 23 Dec 82 00:06-EST from David L. Andre Ah. That reminds me why parse-number works the way it does. parse-number is intended to be a tool to help you parse your way through a string. If you encounter a digit on your way from the left end of the string to the right end, you call parse-number, and it reads in as much of the string as is a number and tells you where it stopped so that you can continue to parse the string. Whether you expected the entire string to be a number or not is up to you, and parse-number can be useful in both cases so the "best" default value for the fail-if-not-whole-string argument is not obvious. I don't think it's too important as long as the documentation makes it clear.  Date: Thursday, 23 December 1982, 12:42-EST From: Bernard S. Greenberg Subject: parse-number To: Moon at SCRC-TENEX at mit-mc Cc: lisp-designers at SCRC-TENEX at mit-mc, Common-Lisp at SU-AI at mit-mc In-reply-to: The message of 22 Dec 82 22:42-EST from David A. Moon Date: Wednesday, 22 December 1982, 22:42-EST From: David A. Moon Date: Tuesday, 21 December 1982, 14:57-EST From: Bernard S. Greenberg I was willing to believe that zwei appreciates the fact that zwei:parse-number by default did not complain about non-numeric digits. However, I refuse to believe that this is the correct default for the now globalized parse-number, documented in the 4.0 Release Notes. I cannot believe that the world will believe a number parsing routine that by default does not complain about invalid numbers: the time to fix it is now. The Common Lisp copy of this function is compatible with this except for the names of the arguments. But perhaps it is wrong, too? Note, however, that READ-FROM-STRING does exactly the same thing. Yes, it is wrong. I would like to hear any arguments for why it is thought to be right.  Date: Thursday, 23 December 1982, 00:06-EST From: David L. Andre Subject: parse-number To: Moon at SCRC-TENEX at mit-mc Cc: BSG at SCRC-TENEX at mit-mc, lisp-designers at SCRC-TENEX at mit-mc, Common-Lisp at SU-AI at mit-mc In-reply-to: The message of 22 Dec 82 22:42-EST from David A. Moon Date: Wednesday, 22 December 1982, 22:42-EST From: David A. Moon Date: Tuesday, 21 December 1982, 14:57-EST From: Bernard S. Greenberg I was willing to believe that zwei appreciates the fact that zwei:parse-number by default did not complain about non-numeric digits. However, I refuse to believe that this is the correct default for the now globalized parse-number, documented in the 4.0 Release Notes. I cannot believe that the world will believe a number parsing routine that by default does not complain about invalid numbers: the time to fix it is now. The Common Lisp copy of this function is compatible with this except for the names of the arguments. But perhaps it is wrong, too? Note, however, that READ-FROM-STRING does exactly the same thing. No, (READ-FROM-STRING "123FOO") ==> # (PARSE-NUMBER "123FOO") ==> 123., 3 This is an artifact of FS:PARSE-NUMBER first being used to parse file names such as "AI: LCADR; UCADR 666MCR", I believe.  Date: Wednesday, 22 December 1982, 22:42-EST From: David A. Moon Subject: parse-number To: Bernard S. Greenberg Cc: lisp-designers at SCRC-TENEX at MIT-MC, Common-Lisp at SU-AI In-reply-to: The message of 21 Dec 82 14:57-EST from Bernard S. Greenberg Date: Tuesday, 21 December 1982, 14:57-EST From: Bernard S. Greenberg I was willing to believe that zwei appreciates the fact that zwei:parse-number by default did not complain about non-numeric digits. However, I refuse to believe that this is the correct default for the now globalized parse-number, documented in the 4.0 Release Notes. I cannot believe that the world will believe a number parsing routine that by default does not complain about invalid numbers: the time to fix it is now. The Common Lisp copy of this function is compatible with this except for the names of the arguments. But perhaps it is wrong, too? Note, however, that READ-FROM-STRING does exactly the same thing.  Date: 21 December 1982 18:05-EST From: Glenn S. Burke Subject: LDB vs LOAD-BYTE To: MOON at SCRC-TENEX cc: common-lisp at SU-AI Date: Monday, 20 December 1982 21:37-EST From: MOON at SCRC-TENEX In-reply-to: The message of 2 DEC 1982 0504-PST from JONL at PARC-MAXC . . . and that (LDB (BYTE n-bits position) word) is slightly preferable to the introduction of a new function LOAD-BYTE, and would generate precisely the same code in any reasonable VAX compiler. An unreasonable compiler can too. The NIL compiler can (and does). We have already broken with the #oPPSS format. More complicated are dealing with the differences of byte extraction from subsequencing. Integers are treated as if they have infinite length, normal sequences are not, and this is where hair arises when attempting to inline code a byte-extract on a fixnum.  Date: 21 December 1982 18:05-EST From: Glenn S. Burke Subject: LDB vs LOAD-BYTE To: MOON at SCRC-TENEX cc: common-lisp at SU-AI Date: Monday, 20 December 1982 21:37-EST From: MOON at SCRC-TENEX In-reply-to: The message of 2 DEC 1982 0504-PST from JONL at PARC-MAXC . . . and that (LDB (BYTE n-bits position) word) is slightly preferable to the introduction of a new function LOAD-BYTE, and would generate precisely the same code in any reasonable VAX compiler. An unreasonable compiler can too. The NIL compiler can (and does). We have already broken with the #oPPSS format. More complicated are dealing with the differences of byte extraction from subsequencing. Integers are treated as if they have infinite length, normal sequences are not, and this is where hair arises when attempting to inline code a byte-extract on a fixnum.  Date: 21 December 1982 18:05-EST From: Glenn S. Burke Subject: LDB vs LOAD-BYTE To: MOON at SCRC-TENEX cc: common-lisp at SU-AI Date: Monday, 20 December 1982 21:37-EST From: MOON at SCRC-TENEX In-reply-to: The message of 2 DEC 1982 0504-PST from JONL at PARC-MAXC . . . and that (LDB (BYTE n-bits position) word) is slightly preferable to the introduction of a new function LOAD-BYTE, and would generate precisely the same code in any reasonable VAX compiler. An unreasonable compiler can too. The NIL compiler can (and does). We have already broken with the #oPPSS format. More complicated are dealing with the differences of byte extraction from subsequencing. Integers are treated as if they have infinite length, normal sequences are not, and this is where hair arises when attempting to inline code a byte-extract on a fixnum.  Date: Monday, 20 December 1982 21:37-EST From: MOON at SCRC-TENEX To: common-lisp at SU-AI Subject: Speaking of issues left of the Ballots ... In-reply-to: The message of 2 DEC 1982 0504-PST from JONL at PARC-MAXC Sorry to be so slow in responding to this, the message got lost somehow. Date: 2 DEC 1982 0504-PST From: JONL at PARC-MAXC Subject: Speaking of issues left of the Ballots ... To: common-lisp at SU-AI At the meeting in August, I mentioned that LOAD-BYTE and DEPOSIT-BYTE had been dropped without discussion. My memory is that it was discussed extensively. Last spring, perhaps? Around that time also, EAK and I offered reasons why they are better choices than LDB and DPB. I hope that after considering them, you'll feel more inclined to at least include LOAD-BYTE in the white pages, regardless of the status of LDB. 1) LDB presents us with a fatal flaw -- either we break compatibility with the LispMachine definition (and the PDP10 MacLisp definition) or we are stuck with a primitive which cant address more than 63 bits worth of byte, nor any bits beyond the 64'th. Despite the manual's best intention of abstracting the notion of a "byte specifier" (section 12.7), the LispM/MacLisp practice is to use a 4-digit octal number. When, in existing code, the bytespec isn't the PDP-10 determined 4 octal digits (say, some variable) then a mechanical converter *cant't* turn that code into the use of the BYTE function (unless "byte specifiers" are a new data type which will be type-certified by each use of LDB; for if such a conversion happened with out type-integrity, then assuming that a "byte specifier" is still some integer, there would be no guarantee that the conversion wasn't happening on an integer already converted elsewhere. This is completely bogus. The Lisp machine and Maclisp as they exist now are not Common Lisp. Of course all use of 4-digit octal numbers as arguments to LDB will be replaced with use of the BYTE primitive. I expect that Symbolics will encourage this by using a different format of byte specifier on each of its hardware lines. And a macro named LDB can easily be provided for programs that for some reason have not been converted to Common Lisp but want to run in a Common Lisp system. This incompatible change to LDB is no worse than the incompatible change to MEMBER, which also is not mechanically translatable in all cases. 2) LDB and LOAD-BYTE tend to treat ingeters as sequences; as such, the syntax of subsequence specification is totally out of character with the other sequence functions. At the very least, we should have (INTEGER-SUBSEQ &optional ) which would translate into something like a currently-defined LDB with bytespec of (BYTE (1+ (- )) ). It may be that I've forgotten EAK's original complaint against LDB, but I thought it was essentially this. This was discussed extensively last spring. I think the conclusion was that the analogy of integers to sequences was a false one, or that bit vectors would be used in that case. The problem with adding a SUBSEQ function for integers is coming up with an excuse not to add all the other sequence functions. I would not be averse to adding such a function if you really think it is important. Note, however, that DPB has no analogue among the sequence functions. 3) the name Lid-ub (or Ell-dib, if you prefer) is the worst asssault on the reasonableness of names in the CommonLisp lexicon. Who, who hasn't been contaminated with PDP10 lore, would think this an appropriate name? How can a community as sensitive to the implications of nomenclature as to change "haulong" into "integer-length" not be swayed to prefer "integer-subseq" to L.D.B. Good names are hard to find, and heavily-used primitives (although perhaps heavily-used only in systems programming) should have short names. This is why we renamed "DIFFERENCE" to "-". LDB is not that good a name, but I have seen no proposed alternatives that aren't inferior to it. I think one could do a lot worse in choosing a name for the byte extraction operation than to follow the lead of the machine that was the standard Lisp engine throughout the AI community for 15 years. One reason for LOAD-BYTE that EAK brought up, which you did not include in your message, is that it can be useful to specify the size and position as separate arguments. This is true. I think you also pointed out that LOAD-BYTE would generate better code on the VAX. My feeling is that it is extremely important that byte-specifiers be first-class data objects (although no one has yet proposed that they print in a portable fashion), and that (LDB (BYTE n-bits position) word) is slightly preferable to the introduction of a new function LOAD-BYTE, and would generate precisely the same code in any reasonable VAX compiler.  Date: 4 December 1982 20:37-EST From: George J. Carrette Subject: bitvectors verses bignums To: EAK at MIT-MC cc: COMMON-LISP at SU-AI MOON's original note pointed out that no side-effecting operations had been given at the time for bitvectors. This was a fairly silly oversight, now fixed. In any case there is a subtle difference between them, the meaning of the LENGTH. You can have a bitvector 100 bits long, with all bits zero, but you cannot have a number 100 bits long which is 0. -GJC p.s. On the lexical-scoping issue: I am working on a note summarizing USER-EXPERIENCE and comments collected over the last year that the "hail-mary" versions of NIL have been in use, since lexical-scoping caused the most people the most problems.  Date: 4 December 1982 18:23-EST From: Alan Bawden Subject: ` and ' To: EAK at MIT-MC cc: common-lisp at SU-AI Yes there is a very good reason to keep ` and ' distinct. Consider something like: (defmacro foo-bar-or-else-p (x y) `(memq ,x '(foo bar ,y)))  Date: 4 December 1982 18:06-EST From: Earl A. Killian Subject: bit-vectors To: common-lisp at SU-AI Moon once sent a message asking why Common Lisp had both bit-vectors and bignums, since many operations on bit-vectors exist in other forms for integers. No one really answered him, as I remember. Where does this issue stand?  Date: 4 December 1982 18:13-EST From: Earl A. Killian Subject: ` and ' To: common-lisp at SU-AI Is there any reason to have ` and ' actually be separate characters? Presumably `(a b c) could read in as (quote (a b c)) because there are no commas in it. Is there some cognitive advantage to keeping them separate, or is it simply a distinction that derives from the historical development of Maclisp?  Date: 3 Dec 1982 1659-MST From: Eric Benson Subject: Re: EAK's fuction ballot To: KMP at MIT-MC, EAK at MIT-MC cc: common-Lisp at SU-AI In-Reply-To: Your message of 3-Dec-82 1602-MST What about (APPLY 'FOO ...) as opposed to (APPLY #'FOO ...)? Also, in the following: (DEFUN FOO () 1) (DEFUN BAR () (FUNCALL #'FOO) (DEFUN FOO () 2) does (BAR) return 1 or 2? 2 is consistent with the assumption that #'... is treated the same as the CAR of a form. ENCLOSE would presumably have (BAR) returning 1, however. -------  Date: 3 December 1982 18:02-EST From: Kent M. Pitman Subject: EAK's fuction ballot To: EAK at MIT-MC cc: common-Lisp at SU-AI Common-Lisp should define only the things we want and need to write clean, transportable code. There are already a sufficient number of things changed from existing dialects that code will have to be reviewed before it will run in Common-Lisp. As such, I think it's appropriate and desirable that we leave (apply '(lambda ...) ...) undefined and guarantee only that APPLYing #'(lambda ...) will work. I would advocate in the red pages that language implementors try to phase out the old '(lambda ...) notation, but we could just leave that undefined in the white pages for now so that implementations would have the option of retaining backward compatibility for now at their individual discretion. --kmp  Date: 3 December 1982 1754-EST (Friday) From: Guy.Steele at CMU-CS-A To: Kent M. Pitman Subject: Re: ENCLOSE and EVAL CC: common-lisp at SU-AI In-Reply-To: Kent M. Pitman's message of 3 Dec 82 17:47-EST Indeed, ENCLOSE is what the evaluator uses to handle the evaluation of a LAMBDA-expression. So one may be defined using the other. --Guy  Date: 3 December 1982 18:02-EST From: Kent M. Pitman Subject: EAK's fuction ballot To: EAK at MIT-MC cc: common-Lisp at SU-AI Common-Lisp should define only the things we want and need to write clean, transportable code. There are already a sufficient number of things changed from existing dialects that code will have to be reviewed before it will run in Common-Lisp. As such, I think it's appropriate and desirable that we leave (apply '(lambda ...) ...) undefined and guarantee only that APPLYing #'(lambda ...) will work. I would advocate in the red pages that language implementors try to phase out the old '(lambda ...) notation, but we could just leave that undefined in the white pages for now so that implementations would have the option of retaining backward compatibility for now at their individual discretion. --kmp  Date: 3 December 1982 17:50-EST From: Kent M. Pitman Subject: ENCLOSE and EVAL To: dlw at SCRC-TENEX cc: COMMON-LISP at SU-AI, Guy.Steele at CMU-CS-A I wrote an ENCLOSE for an early simulator of T and I forgot to put in the check for LAMBDA-ness and found out that if you did (ENCLOSE '(+ 5 1)) you got back 6, which is maybe suggestive of something. After all, what's the difference between (ENCLOSE '(LAMBDA (X) X)) and (EVAL '(LAMBDA (X) X))? Answer: nothing. Only that ENCLOSE looks like: (DEFUN ENCLOSE (LAMBDA-EXP &OPTIONAL (ENV *THE-TOPLEVEL-ENVIRONMENT*)) (CHECK-ARG ...lambda-expression-p of LAMBDA-EXP...) (*EVAL LAMBDA-EXP ENV)) If you are not going to put EVAL or *EVAL in the language, I'd definitely say something along the lines of ENCLOSE would be a good idea because it constraints things a bit. Since EVAL and/or *EVAL will be there, I'd say ENCLOSE may still be notationally useful because this is a very constrained kind of EVAL. eg, SYMEVAL is nice for the same reason. EVAL could do its work, but somehow it doesn't feel like you're letting loose the full unconstrained hair of the language by calling it in the same way as you would if you called EVAL. Since Guy was in on Scheme's replacement of EVAL with ENCLOSE, perhaps he could comment on my conclusions here...?  Date: Friday, 3 December 1982, 12:54-EST From: Daniel L. Weinreb Subject: function ballot To: MOON at SCRC-TENEX at MIT-MC, common-lisp at SU-AI In-reply-to: The message of 1 Dec 82 22:16-EST from MOON at SCRC-TENEX Date: Wednesday, 1 December 1982 22:16-EST From: MOON at SCRC-TENEX This means, of course, that you need a "subr version" of FUNCTION for use by programs that used to construct functions by consing up lists whose car was LAMBDA. I think that the later schemes had such a function, called ENCLOSE or something. It should take an optional argument which is an environment which means, of course, that an interpreter-environment data type has to be added to the language. Can we use the thing that *EVAL takes for this purpose?  Date: Friday, 3 December 1982, 12:51-EST From: Daniel L. Weinreb Subject: 0^0 To: Guy.Steele at CMU-CS-A, common-lisp at SU-AI In-reply-to: The message of 2 Dec 82 01:54-EST from Guy.Steele at CMU-CS-A Date: 2 December 1982 0154-EST (Thursday) From: Guy.Steele at CMU-CS-A Kahan further assumes that, in languages that distinguish between 0 and 0.0 (which APL does not), the value 0 is likely to be exact, whereas the 0.0 might be exact or might be ther result of underflow. Yes, this is exactly what Alan said. On the other hand, I observe that there is an essential problem here: you just can't tell whether a 0.0 is an exact value or not. I am inclined to let any zero raised to any zero be 1 or 1.0, as appropriate, in Common LISP. It seems you are erring more on the side of danger than safety. I think I agree with Kahan.  Date: Friday, 3 December 1982, 12:54-EST From: Daniel L. Weinreb Subject: function ballot To: MOON at SCRC-TENEX at MIT-MC, common-lisp at SU-AI In-reply-to: The message of 1 Dec 82 22:16-EST from MOON at SCRC-TENEX Date: Wednesday, 1 December 1982 22:16-EST From: MOON at SCRC-TENEX This means, of course, that you need a "subr version" of FUNCTION for use by programs that used to construct functions by consing up lists whose car was LAMBDA. I think that the later schemes had such a function, called ENCLOSE or something. It should take an optional argument which is an environment which means, of course, that an interpreter-environment data type has to be added to the language. Can we use the thing that *EVAL takes for this purpose?  Date: Friday, 3 December 1982, 12:51-EST From: Daniel L. Weinreb Subject: 0^0 To: Guy.Steele at CMU-CS-A, common-lisp at SU-AI In-reply-to: The message of 2 Dec 82 01:54-EST from Guy.Steele at CMU-CS-A Date: 2 December 1982 0154-EST (Thursday) From: Guy.Steele at CMU-CS-A Kahan further assumes that, in languages that distinguish between 0 and 0.0 (which APL does not), the value 0 is likely to be exact, whereas the 0.0 might be exact or might be ther result of underflow. Yes, this is exactly what Alan said. On the other hand, I observe that there is an essential problem here: you just can't tell whether a 0.0 is an exact value or not. I am inclined to let any zero raised to any zero be 1 or 1.0, as appropriate, in Common LISP. It seems you are erring more on the side of danger than safety. I think I agree with Kahan.  Date: 2 DEC 1982 0504-PST From: JONL at PARC-MAXC Subject: Speaking of issues left of the Ballots ... To: common-lisp at SU-AI At the meeting in August, I mentioned that LOAD-BYTE and DEPOSIT-BYTE had been dropped without discussion. Around that time also, EAK and I offered reasons why they are better choices than LDB and DPB. I hope that after considering them, you'll feel more inclined to at least include LOAD-BYTE in the white pages, regardless of the status of LDB. 1) LDB presents us with a fatal flaw -- either we break compatibility with the LispMachine definition (and the PDP10 MacLisp definition) or we are stuck with a primitive which cant address more than 63 bits worth of byte, nor any bits beyond the 64'th. Despite the manual's best intention of abstracting the notion of a "byte specifier" (section 12.7), the LispM/MacLisp practice is to use a 4-digit octal number. When, in existing code, the bytespec isn't the PDP-10 determined 4 octal digits (say, some variable) then a mechanical converter *cant't* turn that code into the use of the BYTE function (unless "byte specifiers" are a new data type which will be type-certified by each use of LDB; for if such a conversion happened with out type-integrity, then assuming that a "byte specifier" is still some integer, there would be no guarantee that the conversion wasn't happening on an integer already converted elsewhere. 2) LDB and LOAD-BYTE tend to treat ingeters as sequences; as such, the syntax of subsequence specification is totally out of character with the other sequence functions. At the very least, we should have (INTEGER-SUBSEQ &optional ) which would translate into something like a currently-defined LDB with bytespec of (BYTE (1+ (- )) ). It may be that I've forgotten EAK's original complaint against LDB, but I thought it was essentially this. 3) the name Lid-ub (or Ell-dib, if you prefer) is the worst asssault on the reasonableness of names in the CommonLisp lexicon. Who, who hasn't been contaminated with PDP10 lore, would think this an appropriate name? How can a community as sensitive to the implications of nomenclature as to change "haulong" into "integer-length" not be swayed to prefer "integer-subseq" to L.D.B.  Date: 2 DEC 1982 0406-PST From: JONL at PARC-MAXC Subject: Re: x^0.0 To: HEDRICK at RUTGERS, dlw at MIT-AI cc: Kim.fateman at UCB-C70, common-lisp at SU-AI, JONL In response to the message sent 1 Dec 1982 1810-EST from HEDRICK@RUTGERS I'm not sure that you really do have *two* choices; INF has to have certain properties, such as being larger in magnitude than any other (non-INF) number, and being an additive sink. Similarly, UNDEFINED has to be an operative sink; trying to make an exception for zero seems to lead to another of those discontinuities like 0^0 = 0. But I certainly agree that a user-settable option calling for an error upon generation of UNDEFINED would be a good idea.  Date: 2 December 1982 0205-EST (Thursday) From: Guy.Steele at CMU-CS-A To: common-lisp at SU-AI Subject: More on 0^0 If you take the limit of x^x as x approaches 0 from the northeast (that is, taking on values of the form q+iq where q is real), then, according to my calculations, the limit is e^(-sqrt(2)*pi/8+sqrt(2)*pi/8*i) which is approximately 0.4876+.30275i. Ain't that a kick in he head??? --Guy  Date: 2 December 1982 0154-EST (Thursday) From: Guy.Steele at CMU-CS-A To: common-lisp at SU-AI Subject: 0^0 Here's the scoop! The exponentiation function has an essential singularity at (0,0). You can get 0^0 to equal any of an infinite number of values by causing the limit to be computed by an approach from an appropriate direction. For example, LIM [x->0] x^x = 1 if x approaches 0 along the real axis; but if it approaches along the imaginary axis, the limit is e^(-pi/2), if I have done my calculations correctly. Many languages define 0^0=1 because that preserves a number of interesting identities that are more useful in practice than 0^x=0. Kahan agrees with that in his latest paper on branch cuts. Kahan further assumes that, in languages that distinguish between 0 and 0.0 (which APL does not), the value 0 is likely to be exact, whereas the 0.0 might be exact or might be ther result of underflow. This is why he recommends 0^0 = 0.0^0 = 1 but 0.0^0 = 0.0^0.0 = error, because if the exponent is the result of underflow then you get an anomaly; if only that underflowed value had been preserved (call it EPS), then 0.0^EPS = 0.0, not 1, and you don't want the problem of underflow to cause discontinuities in the result. On the other hand, I observe that there is an essential problem here: you just can't tell whether a 0.0 is an exact value or not. I am inclined to let any zero raised to any zero be 1 or 1.0, as appropriate, in Common LISP. --Guy  Date: Wednesday, 1 December 1982 22:16-EST From: MOON at SCRC-TENEX to: common-lisp at SU-AI Subject: function ballot In-reply-to: The message of 1 Dec 1982 21:38-EST from Scott E. Fahlman Date: Wednesday, 1 December 1982 21:38-EST From: Scott E. Fahlman I assume that this will not affect the evaluation of forms whose car is a lambda expression. That much tradition is too heavy to mess with. Well, of COURSE not, since putting #' in front of something means "evaluate" this as if it was the car of a form. And I guess that forces me to agree with EAK. This means, of course, that you need a "subr version" of FUNCTION for use by programs that used to construct functions by consing up lists whose car was LAMBDA. It should take an optional argument which is an environment which means, of course, that an interpreter-environment data type has to be added to the language.  Date: Wednesday, 1 December 1982 22:16-EST From: MOON at SCRC-TENEX to: common-lisp at SU-AI Subject: function ballot In-reply-to: The message of 1 Dec 1982 21:38-EST from Scott E. Fahlman Date: Wednesday, 1 December 1982 21:38-EST From: Scott E. Fahlman I assume that this will not affect the evaluation of forms whose car is a lambda expression. That much tradition is too heavy to mess with. Well, of COURSE not, since putting #' in front of something means "evaluate" this as if it was the car of a form. And I guess that forces me to agree with EAK. This means, of course, that you need a "subr version" of FUNCTION for use by programs that used to construct functions by consing up lists whose car was LAMBDA. It should take an optional argument which is an environment which means, of course, that an interpreter-environment data type has to be added to the language.  Date: 1 December 1982 21:17-EST From: Earl A. Killian Subject: function ballot To: common-lisp at SU-AI Some time ago I sent out a message suggesting that a cons with its car eq to lambda not be considered a function. No one replied negatively. However, the issue was omitted from the various ballots that were taken. I'd really like to survey peoples opinions on this, and remove this requirement from Common Lisp if there is a consensus. Briefly, as in Lisp 1.5, the Common Lisp manual currently specifies that the LIST (lambda (x) (+ x 1)) is a function. In particular, one can write (apply '(lambda (x) (+ x 1)) '(5)) I consider retaining this in Common Lisp to be a wart. Common Lisp programs should write (apply #'(lambda (x) (+ x 1)) '(5)) instead. There are no advantages to allowing the list as a function, except maybe compatibility. There are disadvantages: inefficiency, confusion (with respect to lexical scoping), and needless complexity. As far as compatibility goes, it is completely minor, as the functionality still exists, just with a minor syntax change, and most Maclisp programs already use #'. Also, nothing prevents an implementation from supporting lists beginning with lambda as functions: I am only suggesting that portable Common Lisp programs not use this.  Date: Wednesday, 1 December 1982 21:38-EST From: Scott E. Fahlman To: Earl A. Killian Cc: common-lisp at SU-AI Subject: function ballot EAK's suggestion sounds good to me. In fact, our Spice implementation makes rude noises at you if you put '(lambda ...) where #'(lambda...) would be more appropriate. (I guess the rude noises were a non-standard extension in our implementation...) I assume that this will not affect the evaluation of forms whose car is a lambda expression. That much tradition is too heavy to mess with. -- Scott  Date: 1 December 1982 21:17-EST From: Earl A. Killian Subject: function ballot To: common-lisp at SU-AI Some time ago I sent out a message suggesting that a cons with its car eq to lambda not be considered a function. No one replied negatively. However, the issue was omitted from the various ballots that were taken. I'd really like to survey peoples opinions on this, and remove this requirement from Common Lisp if there is a consensus. Briefly, as in Lisp 1.5, the Common Lisp manual currently specifies that the LIST (lambda (x) (+ x 1)) is a function. In particular, one can write (apply '(lambda (x) (+ x 1)) '(5)) I consider retaining this in Common Lisp to be a wart. Common Lisp programs should write (apply #'(lambda (x) (+ x 1)) '(5)) instead. There are no advantages to allowing the list as a function, except maybe compatibility. There are disadvantages: inefficiency, confusion (with respect to lexical scoping), and needless complexity. As far as compatibility goes, it is completely minor, as the functionality still exists, just with a minor syntax change, and most Maclisp programs already use #'. Also, nothing prevents an implementation from supporting lists beginning with lambda as functions: I am only suggesting that portable Common Lisp programs not use this.  Date: 1 December 1982 21:17-EST From: Earl A. Killian Subject: function ballot To: common-lisp at SU-AI Some time ago I sent out a message suggesting that a cons with its car eq to lambda not be considered a function. No one replied negatively. However, the issue was omitted from the various ballots that were taken. I'd really like to survey peoples opinions on this, and remove this requirement from Common Lisp if there is a consensus. Briefly, as in Lisp 1.5, the Common Lisp manual currently specifies that the LIST (lambda (x) (+ x 1)) is a function. In particular, one can write (apply '(lambda (x) (+ x 1)) '(5)) I consider retaining this in Common Lisp to be a wart. Common Lisp programs should write (apply #'(lambda (x) (+ x 1)) '(5)) instead. There are no advantages to allowing the list as a function, except maybe compatibility. There are disadvantages: inefficiency, confusion (with respect to lexical scoping), and needless complexity. As far as compatibility goes, it is completely minor, as the functionality still exists, just with a minor syntax change, and most Maclisp programs already use #'. Also, nothing prevents an implementation from supporting lists beginning with lambda as functions: I am only suggesting that portable Common Lisp programs not use this.  Date: Wednesday, 1 December 1982, 16:44-EST From: Daniel L. Weinreb Subject: x^0.0 To: Kim.fateman at UCB-C70 Cc: common-lisp at su-ai In-reply-to: <8211011913.20888@UCBVAX.BERKELEY.ARPA> Date: 1-Dec-82 11:12:16-PST (Wed) From: Kim.fateman@Berkeley Awrighty, we've settled y^0=1. I don't understand what you mean by this. As far as I am concerned, we have not necessarily settled on this; I think it might be a mistake to do so. If you want to worry about these things, you have + and - infinity, in the IEEE arithmetic. Some implementations of Common Lisp will not have IEEE arithmetic, but they will all have zero. Even if we don't define all those weird infinity cases, we should try to do the right thing for zeroes. If you are trying to tell me that I'm not allowed to discuss zeroes unless I compose an entire essay on infinities, accuracy rules, and so on, I disagree.  Date: 1 Dec 1982 1810-EST From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) Subject: Re: x^0.0 To: dlw at SCRC-TENEX at MIT-MC cc: Kim.fateman at UCB-C70, common-lisp at SU-AI In-Reply-To: Your message of 1-Dec-82 1706-EST I would like for any computation that doesn't have a well-defined value to be either an error or result in some item which can never turn into a normal number, even after being multiplied by 0.0. The problem with things like +UNDEFINED is that when you multiply them by 0.0, you get 0.0. But depending upon the exact expression involved and how you take the limit, that is not necessarily a good result. The problem with +UNDEFINED or +INF is that you have only choices, neither of them very attractive: - make them contagious. Any computation involving one of them produces a result that is either UNDEFINED or INF. The problem there is that you can do an hour-long computation that returns UNDEFINED, and have no idea where the error occured. - make 0 * UNDEFINED = 0. But that can result in meaningless answers. It seems that you you supply, at least as an option, the ability to generate an error whenever something questionable is happening. -------  Date: 1 Dec 1982 1810-EST From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) Subject: Re: x^0.0 To: dlw at SCRC-TENEX at MIT-MC cc: Kim.fateman at UCB-C70, common-lisp at SU-AI In-Reply-To: Your message of 1-Dec-82 1706-EST I would like for any computation that doesn't have a well-defined value to be either an error or result in some item which can never turn into a normal number, even after being multiplied by 0.0. The problem with things like +UNDEFINED is that when you multiply them by 0.0, you get 0.0. But depending upon the exact expression involved and how you take the limit, that is not necessarily a good result. The problem with +UNDEFINED or +INF is that you have only choices, neither of them very attractive: - make them contagious. Any computation involving one of them produces a result that is either UNDEFINED or INF. The problem there is that you can do an hour-long computation that returns UNDEFINED, and have no idea where the error occured. - make 0 * UNDEFINED = 0. But that can result in meaningless answers. It seems that you you supply, at least as an option, the ability to generate an error whenever something questionable is happening. -------  Date: 1 Dec 1982 1810-EST From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) Subject: Re: x^0.0 To: dlw at SCRC-TENEX at MIT-MC cc: Kim.fateman at UCB-C70, common-lisp at SU-AI In-Reply-To: Your message of 1-Dec-82 1706-EST I would like for any computation that doesn't have a well-defined value to be either an error or result in some item which can never turn into a normal number, even after being multiplied by 0.0. The problem with things like +UNDEFINED is that when you multiply them by 0.0, you get 0.0. But depending upon the exact expression involved and how you take the limit, that is not necessarily a good result. The problem with +UNDEFINED or +INF is that you have only choices, neither of them very attractive: - make them contagious. Any computation involving one of them produces a result that is either UNDEFINED or INF. The problem there is that you can do an hour-long computation that returns UNDEFINED, and have no idea where the error occured. - make 0 * UNDEFINED = 0. But that can result in meaningless answers. It seems that you you supply, at least as an option, the ability to generate an error whenever something questionable is happening. -------  Date: Wednesday, 1 December 1982, 16:44-EST From: Daniel L. Weinreb Subject: x^0.0 To: Kim.fateman at UCB-C70 Cc: common-lisp at su-ai In-reply-to: <8211011913.20888@UCBVAX.BERKELEY.ARPA> Date: 1-Dec-82 11:12:16-PST (Wed) From: Kim.fateman@Berkeley Awrighty, we've settled y^0=1. I don't understand what you mean by this. As far as I am concerned, we have not necessarily settled on this; I think it might be a mistake to do so. If you want to worry about these things, you have + and - infinity, in the IEEE arithmetic. Some implementations of Common Lisp will not have IEEE arithmetic, but they will all have zero. Even if we don't define all those weird infinity cases, we should try to do the right thing for zeroes. If you are trying to tell me that I'm not allowed to discuss zeroes unless I compose an entire essay on infinities, accuracy rules, and so on, I disagree.  Date: 1-Dec-82 11:12:10-PST (Wed) From: Kim.fateman@Berkeley Message-Id: <8211011913.20885@UCBVAX.BERKELEY.ARPA> Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82]) id A20876; 1-Dec-82 11:13:07-PST (Wed) To: dlw@scrc-tenex@mit-mc Cc: common-lisp@su-ai Awrighty, we've settled y^0=1. If you want to worry about these things, you have + and - infinity, in the IEEE arithmetic. You need to specify inf^(- inf) = 0, 0^(-infinity) = infinity, (or should that be a division by zero?) And if you've gotten all that set up, we can start talking about accuracy. :-)  Date: 1-Dec-82 11:12:10-PST (Wed) From: Kim.fateman@Berkeley Message-Id: <8211011913.20885@UCBVAX.BERKELEY.ARPA> Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82]) id A20876; 1-Dec-82 11:13:07-PST (Wed) To: dlw@scrc-tenex@mit-mc Cc: common-lisp@su-ai Awrighty, we've settled y^0=1. If you want to worry about these things, you have + and - infinity, in the IEEE arithmetic. You need to specify inf^(- inf) = 0, 0^(-infinity) = infinity, (or should that be a division by zero?) And if you've gotten all that set up, we can start talking about accuracy. :-)  Date: Wednesday, 1 December 1982, 12:30-EST From: Daniel L. Weinreb Subject: (^ 0.0 0.0) AND (^ 0 0.0) To: common-lisp at su-ai In-reply-to: The message of 1 Dec 82 02:03-EST from Alan Bawden I want to forward this to the rest of you. Common Lisp currently says that zero to the zero is one, although it isn't careful about what data types it's talking about; I assume that is means floating point. Date: Wednesday, 1 December 1982 02:03-EST From: Alan Bawden Just for the record let me clarify the issue about 0.0^0.0 . Consider taking the limit of A^X as X approaches 0.0 (from above). If A is different from 0.0 (and 0 as well incidentally), then the limit of this is 1.0 . On the other hand, if A=0.0 (or 0) then the limit is 0.0 . Thus there would be a discontinuity of the function 0.0^X (as well as 0^X) at the point 0.0 if we were to decide that 0.0^0.0 (and 0^0.0) = 1.0 . Discontinuities in floating point functions are bad (as I understand the philosophy of floating point) because they mean that a small difference in floating point truncation and roundoff can be magnified arbitrarily.