perm filename COMMON.2[COM,LSP] blob sn#712228 filedate 1983-05-17 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00342 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00048 00002	 Common.1[com,lsp] is the portion of the Common Lisp file preceeding this.
C00049 00003	∂02-Oct-82  0033	MOON at SCRC-TENEX 	DEFSTRUCT options syntax 
C00052 00004	∂02-Oct-82  0928	Guy.Steele at CMU-10A 	Apalled
C00054 00005	∂02-Oct-82  0939	Guy.Steele at CMU-10A 	keyword pairs and DEFSTRUCT
C00055 00006	∂03-Oct-82  1104	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings
C00056 00007	∂04-Oct-82  0046	Alan Bawden <ALAN at MIT-MC> 	Documentation strings in defstruct 
C00058 00008	∂04-Oct-82  0759	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings in defstruct  
C00059 00009	∂04-Oct-82  1420	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	keyword pairs and OPEN    
C00066 00010	∂04-Oct-82  1642	Ginder at CMU-20C 	dlw's OPEN proposal  
C00068 00011	∂04-Oct-82  2042	Guy.Steele at CMU-10A 	Explanation of "Sesame"    
C00069 00012	∂04-Oct-82  2042	Guy.Steele at CMU-10A 	HIC lambda macros
C00070 00013	∂04-Oct-82  2047	Howard I. Cannon <HIC at MIT-MC> 	HIC lambda macros    
C00072 00014	∂04-Oct-82  2130	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	suggestions on floating point numbers and hash tables
C00077 00015	∂04-Oct-82  2138	Scott E. Fahlman <Fahlman at Cmu-20c> 	White, red, and yellow pages   
C00079 00016	∂04-Oct-82  2148	Guy.Steele at CMU-10A 	Moon's floating-point extractors proposal 
C00080 00017	∂04-Oct-82  2145	STEELE at CMU-20C 	/BALLOT/   
C00176 00018	∂05-Oct-82  0533	ZVONA at MIT-MC 	/BALLOT/
C00178 00019	∂05-Oct-82  1002	Guy.Steele at CMU-10A 	Addendum to voting procedure    
C00180 00020	∂05-Oct-82  1517	Scott E. Fahlman <Fahlman at Cmu-20c> 	/BALLOT/   
C00184 00021	∂05-Oct-82  1532	Dave Dyer       <DDYER at USC-ISIB> 	comment on lambda macros    
C00186 00022	∂05-Oct-82  1552	Earl A. Killian <EAK at MIT-MC> 	defun semantics  
C00188 00023	∂05-Oct-82  1612	Brian G. Milnes <Milnes at CMU-20C> 	/BALLOT/
C00189 00024	∂05-Oct-82  1625	Earl A. Killian <EAK at MIT-MC> 	arrays 
C00191 00025	∂05-Oct-82  1927	Alan Bawden <ALAN at MIT-MC> 	ZVONA: ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx    
C00193 00026	∂05-Oct-82  2032	Masinter at PARC-MAXC 	Re: keyword pairs and OPEN 
C00196 00027	∂05-Oct-82  2317	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	arrays   
C00198 00028	∂06-Oct-82  0106	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN   
C00203 00029	∂06-Oct-82  0126	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	GLS's change to Moon's floating-point extractors proposal  
C00206 00030	∂06-Oct-82  0708	Guy.Steele at CMU-10A 	Re: defun semantics   
C00207 00031	∂06-Oct-82  0732	Guy.Steele at CMU-10A 	FLOAT-SIGN and SIGNUM 
C00209 00032	∂06-Oct-82  1112	ZVONA at MIT-MC
C00213 00033	∂06-Oct-82  1222	Dave Dyer       <DDYER at USC-ISIB> 	votes   
C00214 00034	∂06-Oct-82  1225	Kent M. Pitman <KMP at MIT-MC> 	insults 
C00217 00035	∂06-Oct-82  1423	Kent M. Pitman <KMP at MIT-MC> 	defun semantics   
C00219 00036	∂06-Oct-82  1503	MOON at SCRC-TENEX 	suggestions on floating point numbers and hash tables  
C00224 00037	∂06-Oct-82  1735	Masinter at PARC-MAXC 	Re: /BALLOT/
C00226 00038	∂06-Oct-82  1828	Scott E. Fahlman <Fahlman at Cmu-20c> 	suggestions on floating point numbers and hash tables   
C00227 00039	∂06-Oct-82  1919	Kent M. Pitman <KMP at MIT-MC> 	/BALLOT/
C00231 00040	∂06-Oct-82  2238	Guy.Steele at CMU-10A 	Documentation and error messages
C00236 00041	∂07-Oct-82  1017	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
C00240 00042	∂07-Oct-82  1622	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Documentation and error messages  
C00249 00043	∂07-Oct-82  1803	MIT VAX/VMS Lisp Implementors <NIL at MIT-ML> 	/BALLOT/
C00250 00044	∂07-Oct-82  1814	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
C00253 00045	∂07-Oct-82  1904	BROOKS at MIT-OZ at MIT-MC 	/BALLOT/    
C00254 00046	∂07-Oct-82  2221	Glenn S. Burke <GSB at MIT-ML> 	[Re: MIT VAX/VMS Lisp Implementors, Ballot]
C00256 00047	∂07-Oct-82  2351	Guy.Steele at CMU-10A 	Documentation and errors, etc.  
C00257 00048	∂08-Oct-82  1101	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
C00258 00049	∂08-Oct-82  1111	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
C00259 00050	∂08-Oct-82  1524	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Hash tables => Hashing functions    
C00261 00051	∂08-Oct-82  1526	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
C00263 00052	∂08-Oct-82  1740	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
C00270 00053	∂08-Oct-82  1800	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
C00277 00054	∂11-Oct-82  1500	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
C00279 00055	∂11-Oct-82  2005	MOON at SCRC-TENEX 	Re: macro expansion 
C00286 00056	∂13-Oct-82  1309	STEELE at CMU-20C 	Ballot results  
C00326 00057	∂14-Oct-82  2110	Guy.Steele at CMU-10A 	Here is a good idea, I think    
C00328 00058	∂14-Oct-82  2139	Scott E. Fahlman <Fahlman at Cmu-20c> 	Here is a good idea, I think   
C00330 00059	∂14-Oct-82  2144	Guy.Steele at CMU-10A 	Here is a terrible idea, I think
C00331 00060	∂14-Oct-82  2210	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
C00333 00061	∂14-Oct-82  2222	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
C00335 00062	∂14-Oct-82  2356	HEDRICK at RUTGERS 	A bunch of lousy ideas   
C00337 00063	∂15-Oct-82  0011	HEDRICK at RUTGERS 	A bunch of lousy ideas   
C00339 00064	∂15-Oct-82  0110	Kent M. Pitman <KMP at MIT-MC> 	conservatism in extensions  
C00341 00065	∂15-Oct-82  0152	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Here is a tired quux, I think
C00343 00066	∂15-Oct-82  1214	The Great Quux at CMU-10A 	Conservatism in extensions  
C00344 00067	∂15-Oct-82  1233	Guy.Steele at CMU-10A 	Tried Quux vindicated 
C00345 00068	∂16-Oct-82  0001	Alan Bawden <ALAN at MIT-MC> 	Overconservatism in extensions
C00347 00069	∂16-Oct-82  1055	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
C00348 00070	∂16-Oct-82  1111	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
C00349 00071	∂17-Oct-82  1255	Guy.Steele at CMU-10A 	What can I say?  
C00351 00072	∂17-Oct-82  2120	Guy.Steele at CMU-10A 	STRING-OUT, LINE-OUT and READLINE    
C00352 00073	∂17-Oct-82  2303	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	STRING-OUT -> WRITE-STRING, etc.  
C00353 00074	∂18-Oct-82  1458	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	STRING-OUT, LINE-OUT and READLINE   
C00354 00075	∂19-Oct-82  1211	George J. Carrette <GJC at MIT-ML> 
C00356 00076	∂20-Oct-82  1612	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
C00358 00077	∂20-Oct-82  1700	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Proposed evaluator for Common LISP
C00360 00078	∂20-Oct-82  1743	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
C00361 00079	∂27-Oct-82  0010	Guy.Steele at CMU-10A 	Macros and TAGBODY tags    
C00362 00080	∂27-Oct-82  0012	Guy.Steele at CMU-10A 	SCALE-FLOAT and friends    
C00363 00081	∂27-Oct-82  0119	MOON at SCRC-TENEX 	SCALE-FLOAT and friends  
C00365 00082	∂27-Oct-82  0138	MOON at SCRC-TENEX 	Macros and TAGBODY tags  
C00366 00083	∂27-Oct-82  0141	Kent M. Pitman <KMP at MIT-MC> 	No. Don't let macros expand into prog tags.
C00369 00084	∂27-Oct-82  0704	Scott E. Fahlman <Fahlman at Cmu-20c> 	Macros and TAGBODY tags   
C00370 00085	∂04-Nov-82  1413	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Destructuring   
C00371 00086	∂06-Nov-82  1314	Scott E. Fahlman <Fahlman at Cmu-20c> 	Destructuring   
C00373 00087	∂08-Nov-82  1424	Guy.Steele at CMU-10A 	Mini-ballot 
C00376 00088	∂08-Nov-82  1524	MOON at SCRC-TENEX 	Mini-ballot    
C00378 00089	∂08-Nov-82  1659	Skef Wholey <Wholey at CMU-20C> 	Mini-ballot 
C00380 00090	∂08-Nov-82  1703	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Mini-ballot   
C00383 00091	∂08-Nov-82  1711	Eric Benson <BENSON at UTAH-20> 	Re: Mini-ballot  
C00384 00092	∂08-Nov-82  1744	Earl A. Killian <EAK at MIT-MC> 	Mini-ballot 
C00386 00093	∂08-Nov-82  1743	ZVONA at MIT-MC 	Mini-ballot  
C00388 00094	∂08-Nov-82  1756	Scott E. Fahlman <Fahlman at Cmu-20c> 	Mini-ballot
C00390 00095	∂08-Nov-82  1803	Kent M. Pitman <KMP at MIT-MC>
C00393 00096	∂08-Nov-82  1846	MOON at SCRC-TENEX 	asterisks around variables    
C00395 00097	∂08-Nov-82  1850	MOON at SCRC-TENEX 	function specs 
C00397 00098	∂08-Nov-82  1859	MOON at SCRC-TENEX 	function specs 
C00399 00099	∂08-Nov-82  2005	Scott E. Fahlman <Fahlman at Cmu-20c> 	Revised Mini-Ballot  
C00403 00100	∂08-Nov-82  2051	Glenn S. Burke <GSB at MIT-ML> 	Mini-ballot  
C00406 00101	∂08-Nov-82  2308	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: function specs
C00410 00102	∂09-Nov-82  0000	Guy.Steele at CMU-10A 	Remarks on mini-ballot
C00413 00103	∂09-Nov-82  0055	David A. Moon <Moon at SCRC-POINTER at MIT-MC> 	Remarks on mini-ballot
C00416 00104	∂09-Nov-82  0132	Guy.Steele at CMU-10A 	Re: Remarks on mini-ballot 
C00418 00105	∂09-Nov-82  0444	Scott E. Fahlman <Fahlman at Cmu-20c> 	Remarks on mini-ballot    
C00420 00106	∂09-Nov-82  0752	ZVONA at MIT-MC 	function specs    
C00422 00107	∂09-Nov-82  0803	ZVONA at MIT-MC 	function specs    
C00424 00108	∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC>
C00427 00109	∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC> 	Mini-ballot  
C00432 00110	∂09-Nov-82  1603	Eric Benson <BENSON at UTAH-20> 	#'(LAMBDA ...) ==> CODE    
C00433 00111	∂09-Nov-82  1755	David.Dill at CMU-10A (L170DD60) 	mini-ballot
C00435 00112	∂09-Nov-82  1933	Guy.Steele at CMU-10A 	Named lambdas    
C00436 00113	∂09-Nov-82  2120	Guy.Steele at CMU-10A 	Quick query about CONSTANTP
C00438 00114	∂09-Nov-82  2234	STEELE at CMU-20C 	New proposed evaluators   
C00524 00115	∂10-Nov-82  0037	JONL at PARC-MAXC 	Re: Quick query about CONSTANTP
C00527 00116	∂10-Nov-82  0526	Scott E. Fahlman <Fahlman at Cmu-20c> 	Quick query about CONSTANTP    
C00528 00117	∂10-Nov-82  0530	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00530 00118	∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
C00531 00119	∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: Mini-ballot 
C00539 00120	∂11-Nov-82  0725	Masinter at PARC-MAXC 	Named lambdas    
C00540 00121	∂11-Nov-82  0750	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00543 00122	∂11-Nov-82  0824	Masinter at PARC-MAXC 	Re: Named lambdas
C00545 00123	∂11-Nov-82  0857	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00548 00124	∂11-Nov-82  0943	Eric Benson <BENSON at UTAH-20> 	Re: Quick query about CONSTANTP 
C00550 00125	∂11-Nov-82  1253	Guy.Steele at CMU-CS-A 	Benson's remarks on CONSTANTP  
C00551 00126	∂11-Nov-82  1348	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
C00555 00127	∂11-Nov-82  1349	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
C00559 00128	∂12-Nov-82  0003	MOON at SCRC-TENEX 	Named lambdas  
C00561 00129	∂12-Nov-82  0100	MOON at SCRC-TENEX 	primitives, and dynamic binding    
C00565 00130	∂12-Nov-82  0608	Kent M. Pitman <KMP at MIT-MC> 	primitives   
C00567 00131	∂12-Nov-82  0932	Eric Benson <BENSON at UTAH-20> 	Re: primitives   
C00568 00132	∂12-Nov-82  1000	Earl A. Killian            <Killian at MIT-MULTICS> 	NAMED-LAMBDA
C00571 00133	∂12-Nov-82  1025	Earl A. Killian            <Killian at MIT-MULTICS> 	#,
C00572 00134	∂12-Nov-82  1231	MOON at SCRC-TENEX 	NAMED-LAMBDA and function cells    
C00575 00135	∂12-Nov-82  1327	Eric Benson <BENSON at UTAH-20> 	Re: NAMED-LAMBDA and function cells  
C00577 00136	∂12-Nov-82  2157	STEELE at CMU-20C 	Revised evaluators   
C00665 00137	∂13-Nov-82  0118	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	#,  
C00667 00138	∂13-Nov-82  0232	Kent M. Pitman <KMP at MIT-MC> 	#, 
C00668 00139	∂13-Nov-82  1044	JONL at PARC-MAXC 	Re: Named lambdas    
C00670 00140	∂13-Nov-82  1128	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00672 00141	∂13-Nov-82  1147	JONL at PARC-MAXC 	Re: Named lambdas    
C00673 00142	∂13-Nov-82  1516	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: Named lambdas  
C00675 00143	∂13-Nov-82  1950	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	implementing multiple values 
C00682 00144	∂13-Nov-82  2158	Kim.fateman@Berkeley 	multiple-value return  
C00686 00145	∂13-Nov-82  2207	Kim.fateman@Berkeley 	multiple-value return  
C00690 00146	∂13-Nov-82  2355	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	multiple-value return   
C00694 00147	∂14-Nov-82  0927	Martin.Griss <Griss at UTAH-20> 	Re: multiple-value return  
C00695 00148	∂14-Nov-82  1012	Kim.fateman@Berkeley 	Re:  multiple-value return  
C00698 00149	∂14-Nov-82  1314	UCBERNIE.jkf@Berkeley (John Foderaro) 	m-v on conventional machines   
C00703 00150	∂14-Nov-82  1350	Scott E. Fahlman <Fahlman at Cmu-20c> 	Multiple Values 
C00705 00151	∂14-Nov-82  1535	HEDRICK at RUTGERS 	results of analyzing answers to my question about m.v.'s    
C00719 00152	∂14-Nov-82  2207	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	implementing multiple values
C00725 00153	∂16-Nov-82  0848	Kent M. Pitman <KMP at MIT-MC> 	Multiple Value Return and Continuation Passing Style 
C00728 00154	∂16-Nov-82  0856	Kim.fateman@Berkeley 	multiple thanks   
C00730 00155	∂16-Nov-82  0859	Masinter at PARC-MAXC 	Named lambdas    
C00732 00156	∂16-Nov-82  0900	JONL at PARC-MAXC 	Multiple-Value implementations 
C00738 00157	∂16-Nov-82  0900	Masinter at PARC-MAXC 	Re: #, 
C00740 00158	∂16-Nov-82  0957	DLW at MIT-MC 	multiple-value return    
C00743 00159	∂16-Nov-82  1028	BROOKS at MIT-OZ at MIT-MC 	Re: DLW's message and Fateman's FLOOR.    
C00745 00160	∂16-Nov-82  1052	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
C00747 00161	∂16-Nov-82  1106	HEDRICK at RUTGERS 	Re: #,    
C00749 00162	∂16-Nov-82  1117	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
C00751 00163	∂16-Nov-82  1151	Guy.Steele at CMU-CS-A 	1000th message  
C00752 00164	∂16-Nov-82  1227	MOON at SCRC-TENEX 	Defining the forms to which the # constructs expand    
C00755 00165	∂16-Nov-82  1247	BROOKS at MIT-OZ at MIT-MC 	(prog1 (trunc x y))   
C00757 00166	∂16-Nov-82  1334	Alan Bawden <ALAN at MIT-MC> 	(prog1 (trunc x y)) 
C00758 00167	∂16-Nov-82  1333	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
C00759 00168	∂16-Nov-82  1423	Ron <FISCHER at RUTGERS> 	Re: Obliquity of the vernacular...
C00760 00169	∂16-Nov-82  1555	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
C00761 00170	∂16-Nov-82  1805	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
C00762 00171	∂16-Nov-82  1806	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
C00765 00172	∂16-Nov-82  1817	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
C00766 00173	∂16-Nov-82  1817	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
C00769 00174	∂16-Nov-82  1817	Glenn S. Burke <GSB at MIT-ML> 	Re: #,  
C00776 00175	∂16-Nov-82  1852	Guy.Steele at CMU-CS-A 	Masinter's remarks on #,  
C00778 00176	∂16-Nov-82  2007	MOON at SCRC-TENEX 	Re: Defining the forms to which the # constructs expand
C00780 00177	∂16-Nov-82  2113	Glenn S. Burke <GSB at MIT-ML> 	multiple values   
C00782 00178	∂17-Nov-82  0305	Masinter at PARC-MAXC 	Re: #, 
C00784 00179	∂17-Nov-82  0305	Alan Bawden <ALAN at MIT-MC> 	Defining the forms to which the # constructs expand    
C00787 00180	∂17-Nov-82  1323	JONL at PARC-MAXC 	Expansion of #, and the "residential" question.    
C00793 00181	∂17-Nov-82  1359	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
C00798 00182	∂17-Nov-82  1541	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
C00803 00183	∂17-Nov-82  2259	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
C00804 00184	∂17-Nov-82  2316	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
C00805 00185	∂18-Nov-82  0847	Masinter at PARC-MAXC 	Re: Masinter's remarks on #,    
C00807 00186	∂19-Nov-82  1904	Glenn S. Burke <GSB at MIT-ML> 	named lambdas
C00810 00187	∂19-Nov-82  1940	MOON at SCRC-TENEX 	named lambdas  
C00813 00188	∂19-Nov-82  1720	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
C00816 00189	∂22-Nov-82  0156	Kent M. Pitman <KMP at MIT-MC> 	a LAMBDA special form  
C00819 00190	∂22-Nov-82  1255	Masinter at PARC-MAXC 	Re: Named lambdas
C00821 00191	∂22-Nov-82  1459	MOON at SCRC-TENEX 	Re: Named lambdas   
C00823 00192	∂22-Nov-82  1630	JONL at PARC-MAXC 	Re: Named lambdas    
C00825 00193	∂01-Dec-82  0933	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	(↑ 0.0 0.0) AND (↑ 0 0.0) 
C00828 00194	∂01-Dec-82  1126	Kim.fateman@Berkeley
C00829 00195	∂01-Dec-82  1412	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML> 	x↑0.0 
C00831 00196	∂01-Dec-82  1513	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: x↑0.0    
C00834 00197	∂01-Dec-82  1530	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: x↑0.0    
C00837 00198	∂01-Dec-82  1822	Earl A. Killian <EAK at MIT-MC> 	function ballot  
C00840 00199	∂01-Dec-82  1838	Scott E. Fahlman <Fahlman at CMU-CS-C> 	function ballot
C00842 00200	∂01-Dec-82  1838	Earl A. Killian <EAK at MIT-MC> 	function ballot  
C00845 00201	∂01-Dec-82  1928	MOON at SCRC-TENEX 	function ballot
C00847 00202	∂01-Dec-82  2306	Guy.Steele at CMU-CS-A 	More on 0↑0
C00848 00203	∂01-Dec-82  2304	Guy.Steele at CMU-CS-A 	0↑0   
C00851 00204	∂02-Dec-82  0404	JONL at PARC-MAXC 	Re: x↑0.0  
C00853 00205	∂02-Dec-82  0502	JONL at PARC-MAXC 	Speaking of issues left of the Ballots ...    
C00857 00206	∂03-Dec-82  1102	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	0↑0   
C00859 00207	∂03-Dec-82  1102	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	function ballot 
C00861 00208	∂03-Dec-82  1451	Kent M. Pitman <KMP at MIT-MC> 	ENCLOSE and EVAL  
C00864 00209	∂03-Dec-82  1502	Guy.Steele at CMU-CS-A 	Re: ENCLOSE and EVAL 
C00865 00210	∂03-Dec-82  1513	Kent M. Pitman <KMP at MIT-MC> 	EAK's fuction ballot   
C00867 00211	∂03-Dec-82  1538	Kent M. Pitman <KMP at MIT-MC> 	EAK's fuction ballot   
C00869 00212	∂03-Dec-82  1603	Eric Benson <BENSON at UTAH-20> 	Re: EAK's fuction ballot   
C00871 00213	∂04-Dec-82  1505	Earl A. Killian <EAK at MIT-MC> 	bit-vectors 
C00872 00214	∂04-Dec-82  1511	Earl A. Killian <EAK at MIT-MC> 	` and '
C00873 00215	∂04-Dec-82  1522	Alan Bawden <ALAN at MIT-MC> 	` and '   
C00874 00216	∂04-Dec-82  1739	George J. Carrette <GJC at MIT-MC> 	bitvectors verses bignums    
C00876 00217	∂20-Dec-82  1845	MOON at SCRC-TENEX 	Speaking of issues left of the Ballots ...   
C00885 00218	∂21-Dec-82  1502	Glenn S. Burke <GSB at MIT-ML> 	LDB vs LOAD-BYTE  
C00887 00219	∂21-Dec-82  1557	Glenn S. Burke <GSB at MIT-ML> 	LDB vs LOAD-BYTE  
C00889 00220	∂22-Dec-82  1948	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	parse-number  
C00891 00221	∂23-Dec-82  0507	David L. Andre <DLA at SCRC-TENEX at mit-mc> 	parse-number  
C00894 00222	∂23-Dec-82  1012	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	parse-number 
C00897 00223	∂23-Dec-82  1119	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	parse-number    
C00899 00224	∂23-Dec-82  1304	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	parse-number 
C00902 00225	∂23-Dec-82  1315	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	parse-number    
C00904 00226	∂23-Dec-82  1412	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	parse-number 
C00907 00227	∂12-Jan-83  1236	MOON at SCRC-TENEX 	Two small issues, and a test of whether the DCA has broken this mailing list    
C00911 00228	∂26-Feb-83  1757	Guy.Steele at CMU-CS-A 	Proposed Common LISP Function (forwarded)
C00915 00229	∂27-Feb-83  1938	MASINTER.PA@PARC-MAXC.ARPA 	Ballot proposal  
C00918 00230	∂27-Feb-83  2306	Moon@SCRC-TENEX 	concatenating strings  
C00921 00231	∂27-Feb-83  2324	MASINTER.PA@PARC-MAXC 	(APPLY #'CONCATENATE 'STRING L) 
C00922 00232	∂28-Feb-83  1406	MOON@SCRC-TENEX 	(APPLY #'CONCATENATE 'STRING L)  
C00926 00233	∂28-Feb-83  1437	HEDRICK@RUTGERS 	Re: (APPLY #'CONCATENATE 'STRING L)   
C00928 00234	∂28-Feb-83  2025	FAHLMAN@CMU-CS-C 	Implementation Limits 
C00931 00235	∂28-Feb-83  2122	GSB@MIT-ML 	number of arguments limitations  
C00933 00236	∂01-Mar-83  1951	Guy.Steele at CMU-CS-A 	NMapDelRassRevAppCatSqrtQ 
C00935 00237	∂04-Mar-83  1553	FISCHER@RUTGERS 	Re: Recent ballot 
C00936 00238	∂04-Mar-83  1553	FISCHER@RUTGERS 	What is <SLISP.CODE>SPIRRAT.SLISP?    
C00937 00239	∂10-Mar-83  0906	JonL.pa@PARC-MAXC 	number of arguments limitation 
C00939 00240	∂10-Mar-83  1147	JonL.pa@PARC-MAXC 	Upcoming Manual work, and Compatibililty issue.    
C00947 00241	∂14-Mar-83  1110	Mailer@SU-SCORE 	LetS in Common Lisp    
C00954 00242	∂28-Mar-83  1208	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML> 	#A()  
C00957 00243	∂28-Mar-83  1541	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML> 	#A()  
C00960 00244	∂29-Mar-83  0849	Daniel L. Weinreb <dlw at SCRC-TENEX> 	#nA(...)   
C00961 00245	∂29-Mar-83  1334	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	char-not-equal
C00963 00246	∂30-Mar-83  0759	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	digit-weight 
C00964 00247	∂30-Mar-83  1135	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	char-not-equal 
C00966 00248	∂30-Mar-83  1134	David A. Moon <Moon at SCRC-TENEX at mit-mc> 	char-not-equal
C00968 00249	∂30-Mar-83  1603	Moon%SCRC-TENEX@MIT-MC 	short-float-negative-epsilon   
C00970 00250	∂04-Apr-83  1140	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-MC> 	defstruct printed representation
C00972 00251	∂05-Apr-83  1413	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-MC> 	More trivia 
C00974 00252	∂05-Apr-83  1924	Guy.Steele@CMU-CS-A 	Proposed change to SPECIAL: quick poll 
C00980 00253	∂06-Apr-83  2237	MOON at SCRC-TENEX 	Proposed change to SPECIAL: quick poll  
C00993 00254	∂07-Apr-83  2238	Scott E. Fahlman <Fahlman@CMU-CS-C> 	Proposed change to SPECIAL: quick poll
C01003 00255	∂08-Apr-83  1117	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	nsubstitute-if/if-not   
C01005 00256	∂08-Apr-83  1328	MOON at SCRC-TENEX 	Proposed change to SPECIAL: quick poll  
C01007 00257	∂10-Apr-83  1934	David A. Moon <MOON%SCRC-TENEX@MIT-MC> 	What should LAST of an atom do?    
C01010 00258	∂10-Apr-83  2101	Scott E. Fahlman <Fahlman@CMU-CS-C> 	What should LAST of an atom do?  
C01012 00259	∂11-Apr-83  0046	Glenn S. Burke <GSB @ MIT-ML> 	What should LAST of an atom do?   
C01014 00260	∂12-Apr-83  1210	RPG  	Map 
C01016 00261	∂12-Apr-83  2240	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	What should LAST of an atom do? -- conclusion
C01020 00262	∂13-Apr-83  0000	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	Proposed change to SPECIAL: proposed resolution   
C01035 00263	∂13-Apr-83  2031	Scott E. Fahlman <Fahlman@CMU-CS-C> 	EVAL and friends  
C01041 00264	∂20-Apr-83  0717	David A. Moon <Moon%SCRC-TENEX@MIT-ML> 	DEFSETF   
C01055 00265	∂20-Apr-83  1011	David A. Moon <Moon%SCRC-TENEX@MIT-ML> 	DEFSETF   
C01069 00266	∂20-Apr-83  2115	Scott E. Fahlman <Fahlman@CMU-CS-C> 	DEFSETF 
C01072 00267	∂21-Apr-83  1044	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-ML> 	*prindepth* and *prinlength* versus *prinarray*
C01074 00268	∂21-Apr-83  1311	BENSON at SPA-Nimbus 	*prindepth* and *prinlength* versus *prinarray* 
C01076 00269	∂22-Apr-83  0635	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	MISMATCH/MAXPREFIX/MAXSUFFIX 
C01078 00270	∂22-Apr-83  1332	Skef Wholey <Wholey@CMU-CS-C> 	MISMATCH/MAXPREFIX/MAXSUFFIX 
C01081 00271	∂22-Apr-83  2032	Leonard N. Zubkoff <Zubkoff@CMU-CS-C> 	MISMATCH/MAXPREFIX/MAXSUFFIX   
C01083 00272	∂22-Apr-83  2119	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	Proposed improvement to ASSERT
C01088 00273	∂23-Apr-83  1310	David A. Moon <Moon%SCRC-TENEX@MIT-MULTICS> 	DEFSETF proposal, revised
C01104 00274	∂23-Apr-83  2017	Scott E. Fahlman <Fahlman@CMU-CS-C> 	Lunar DEFSETF
C01106 00275	∂26-Apr-83  0947	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-MC> 	DEFSETF multiple-values feature 
C01108 00276	∂27-Apr-83  1009	Mike McMahon <MMcM@SCRC-TENEX> 	Erring forms of ...CASE...  
C01110 00277	∂27-Apr-83  2056	Kent M. Pitman <KMP @ MIT-MC> 
C01112 00278	∂28-Apr-83  1657	BENSON at SPA-NIMBUS 	Bugs in the Laser Edition   
C01119 00279	∂29-Apr-83  1411	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	MISMATCH, From end.
C01122 00280	∂06-May-83  1229	RPG  	Test
C01123 00281	∂06-May-83  1257	@USC-ECL:RPG@MIT-MC 
C01124 00282	∂06-May-83  1311	FEINBERG@CMU-CS-C 	Testing, one two...  
C01126 00283	∂06-May-83  1742	FAHLMAN@CMU-CS-C 	Package Proposal (moby message) 
C01162 00284	∂07-May-83  1411	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	test message--please ignore    
C01163 00285	∂07-May-83  1506	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	error proposal  
C01192 00286	∂07-May-83  1804	FAHLMAN@CMU-CS-C 	error proposal   
C01198 00287	∂07-May-83  2027	@USC-ECL,@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	Errors 
C01223 00288	∂07-May-83  2057	LARGE@CMU-CS-C 	error proposal
C01224 00289	∂07-May-83  2105	LARGE@CMU-CS-C 	error proposal
C01225 00290	∂08-May-83  0902	@USC-ECL,@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	Package Proposal (moby message) 
C01287 00291	∂09-May-83  2215	DILL@CMU-CS-C 	package proposal comments
C01299 00292	∂09-May-83  2351	FAHLMAN@CMU-CS-C 	New Package Proposal  
C01300 00293	∂10-May-83  0834	@MIT-MC:MOON@SCRC-TENEX 	package proposal comments
C01301 00294	∂10-May-83  0956	@MIT-MC:MOON@SCRC-TENEX 	package.mss.108
C01309 00295	∂10-May-83  1230	@MIT-MC:MOON%SCRC-TENEX%MIT-MC@SU-DSN 	suggestion for ballot: :allow-other-keys 
C01312 00296	∂10-May-83  1447	@USC-ECL,@MIT-MC:BENSON@SPA-NIMBUS 	Function objects   
C01324 00297	∂10-May-83  1452	@USC-ECL,@MIT-ML:BENSON@SPA-NIMBUS 	suggestion for ballot: :allow-other-keys    
C01326 00298	∂10-May-83  1509	KMP@MIT-MC 	Packages
C01339 00299	∂10-May-83  1557	FAHLMAN@CMU-CS-C 	suggestion for ballot: :allow-other-keys  
C01341 00300	∂10-May-83  1641	@USC-ECL,@MIT-MC:BENSON@SPA-NIMBUS 	Function objects   
C01353 00301	∂10-May-83  1721	@USC-ECL,@MIT-XX:BENSON@SPA-NIMBUS 	Summary of message on function objects 
C01356 00302	∂10-May-83  1728	@MIT-MC:MOON@SCRC-TENEX 	not about suggestion for ballot: :allow-other-keys
C01358 00303	∂10-May-83  1807	FAHLMAN@CMU-CS-C 	&allow-other-keys
C01360 00304	∂10-May-83  1841	FAHLMAN@CMU-CS-C 	package proposal comments  
C01363 00305	∂10-May-83  1943	@MIT-MC:MOON@SCRC-TENEX 	Packages  
C01383 00306	∂10-May-83  2012	FAHLMAN@CMU-CS-C 	Packages    
C01385 00307	∂10-May-83  2039	ALAN@MIT-MC 	Summary of message on function objects & :allow-other-keys    
C01388 00308	∂10-May-83  2118	ALAN@MIT-MC 	Two New Package Proposal Comments (and a grotesque suggestion)
C01390 00309	∂10-May-83  2146	FAHLMAN@CMU-CS-C 	package.mss.108  
C01400 00310	∂10-May-83  2236	FAHLMAN@CMU-CS-C 	[Mailer: Message of 11 May 83 00:55:02 EDT]    
C01403 00311	∂10-May-83  2350	KMP@MIT-MC 	Request for clarification about "package users/owners"    
C01408 00312	∂10-May-83  2349	@MIT-MC:MOON@SCRC-TENEX 	package.mss.108
C01421 00313	∂11-May-83  0309	KMP@MIT-MC 	New Error Proposal
C01432 00314	∂11-May-83  1223	FAHLMAN@CMU-CS-C 	package.mss.108  
C01435 00315	∂11-May-83  1443	@USC-ECL,@MIT-ML:MOON@SCRC-TENEX 	need for export controls  
C01441 00316	∂11-May-83  1955	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	package.mss.108 
C01445 00317	∂12-May-83  0321	DILL@CMU-CS-C 	package changes
C01459 00318	∂12-May-83  1016	RPG  
C01513 00319	∂12-May-83  1200	@MIT-MC:MOON@SCRC-TENEX 	package changes
C01516 00320	∂12-May-83  1347	@MIT-MC:dlw%SCRC-TENEX%MIT-MC@SU-DSN 	More about packages, from DLW and BSG
C01532 00321	∂12-May-83  1611	FAHLMAN@CMU-CS-C 	More about packages, from DLW and BSG
C01533 00322	∂12-May-83  1611	FAHLMAN@CMU-CS-C 	More about packages, from DLW and BSG
C01535 00323	∂14-May-83  2208	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	New Error Proposal: suggestions to be incorporated 
C01550 00324	∂14-May-83  2228	FAHLMAN@CMU-CS-C 	New Error Proposal: suggestions to be incorporated  
C01552 00325	∂14-May-83  2302	@USC-ECL,@MIT-ML:Moon%SCRC-TENEX%MIT-ML@SU-DSN 	package changes  
C01566 00326	∂14-May-83  2308	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	New Error Proposal: suggestions to be incorporated 
C01568 00327	∂15-May-83  1137	KMP@MIT-MC 	Keywords, :Keywords, &More-Keywords   
C01572 00328	∂15-May-83  1256	@MIT-MC:KMP@MIT-MC 	[Griss@UTAH-20: Forwarded]    
C01573 00329	∂15-May-83  2205	FAHLMAN@CMU-CS-C 	issues 
C01575 00330	∂15-May-83  2154	FAHLMAN@CMU-CS-C 	packages, yet again   
C01637 00331	∂16-May-83  0040	@MIT-MC:MOON@SCRC-TENEX 	Keywords, :Keywords, &More-Keywords
C01639 00332	∂16-May-83  0101	KMP@MIT-MC
C01642 00333	∂16-May-83  1611	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	error.proposal.9
C01673 00334	∂16-May-83  1647	@USC-ECL:GSB@MIT-ML 	args to error, cerror, & warn
C01675 00335	∂16-May-83  2016	KMP@MIT-MC 	error.proposal.9  
C01678 00336	∂16-May-83  2032	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	args to error, cerror, & warn  
C01681 00337	∂16-May-83  2040	FAHLMAN@CMU-CS-C 	args to error, cerror, & warn   
C01683 00338	∂16-May-83  2048	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	packages, yet again  
C01692 00339	∂16-May-83  2103	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	error.proposal.9
C01695 00340	∂17-May-83  0822	GRISS%UTAH-20.ARPA@SUMEX-AIM 	Debug vs Break 
C01698 00341	∂17-May-83  1917	FAHLMAN@CMU-CS-C 	Break  
C01700 00342	∂17-May-83  2109	FAHLMAN@CMU-CS-C 	Conservation of nits  
C01713 ENDMK
C⊗;
;;; Common.1[com,lsp] is the portion of the Common Lisp file preceeding this.
∂02-Oct-82  0033	MOON at SCRC-TENEX 	DEFSTRUCT options syntax 
Date: Saturday, 2 October 1982  03:30-EDT
From: MOON at SCRC-TENEX
To:   Common-Lisp at SU-AI
Subject: DEFSTRUCT options syntax
In-reply-to: The message of 1 Oct 1982  08:48-EDT from Scott E. Fahlman <Fahlman at Cmu-20c>

    Date: Friday, 1 October 1982  08:48-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    ....
    my point is just that OPEN is pretty much like the others.
Except that it is a function.

    I'm uneasy about making special forms too special, and creating forms
    that the user cannot duplicate with macros or some such.  
No one proposes to make forms that the user cannot duplicate with macros.
Indeed, I can think of no possible way to do that.

							      Perhaps we can
    extend the basic keyword mechanism to allow keyword/value, but also
    allow calling forms like (foo :key1 value1 (:key2 value2a value2b) ...)
    However, coming up with an attractive way to specify this in a macro's
    lambda-list will be pretty tough.
I assume you don't mean doing this for functions.  That would be utterly wrong.

We could easily add another & word to DEFMACRO if we decide it is desirable
to have an even more trivial way to accept such syntax in macros than the
straightforward way of looping over the form checking LISTP and CAR.

∂02-Oct-82  0928	Guy.Steele at CMU-10A 	Apalled
Date:  2 October 1982 1229-EDT (Saturday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Apalled

A marvelous word, this.  Perhaps KMP meant that Common LISP is in
danger of being "APPLEd", that is, forced into the Procrustean bed
of an APPLE's memory size.  This danger can be avoided by making the
language so large that it cannot possiblt be shoehorned into an APPLE.
However, I think this is already the case without RESTART being
added.
Or perhaps Common LISP is being "APL'd", but better to blame that on
REDUCE and MAP than on RESTART.
But most likely is that he simply wished to "applaud" the RESTART form.

(Sorry, KMP, don't mean to tease, but it's wonderful how this typo
landed splat between four or five applicable words.)
--Quux

∂02-Oct-82  0939	Guy.Steele at CMU-10A 	keyword pairs and DEFSTRUCT
Date:  2 October 1982 1240-EDT (Saturday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: keyword pairs and DEFSTRUCT

I am in sympathy with leaving DEFSTRUCT as is.  Indeed, there may be
something odd about DEF-forms.  OPEN was the biggest thorn, to my mind.

∂03-Oct-82  1104	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings
Date: Sunday, 3 October 1982  14:03-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Documentation strings


Gary Brown noticed that DEFMACRO and DEFSTRUCT are not documented as
taking documentation strings.  DEFMACRO certainly should, since its form
parallels that of DEFUN, and adding this to DEFSTRUCT seems to be a good
idea as well.  Any problems with this?

-- Scott

∂04-Oct-82  0046	Alan Bawden <ALAN at MIT-MC> 	Documentation strings in defstruct 
Date: 4 October 1982 03:45-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Documentation strings in defstruct
To: common-lisp at SU-AI

    Date: Sunday, 3 October 1982  14:03-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    Gary Brown noticed that DEFMACRO and DEFSTRUCT are not documented as
    taking documentation strings.  DEFMACRO certainly should, since its form
    parallels that of DEFUN, and adding this to DEFSTRUCT seems to be a good
    idea as well.  Any problems with this?

How about:

(defstruct (spaceman (:include person)
		     (:documentation "A spaceman.
The definition of a spaceman includes the definition of a person.
Additionally a spaceman has a helmit-size and a favorite-beverage.
The default favorite-beverage is Tang (tm)."))
  helmet-size
  (favorite-beverage 'tang))

∂04-Oct-82  0759	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings in defstruct  
Date: Monday, 4 October 1982  10:49-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Alan Bawden <ALAN at MIT-MC>
Cc:   common-lisp at SU-AI
Subject: Documentation strings in defstruct


The use of a :DOCUMENTATION keyword in DEFSTRUCT looks OK, modulo the
auto-fill issues discussed earlier.

-- Scott

∂04-Oct-82  1420	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	keyword pairs and OPEN    
Date: Monday, 4 October 1982, 17:08-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: keyword pairs and OPEN
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-reply-to: The message of 2 Oct 82 12:40-EDT from Guy.Steele at CMU-10A

Speaking of OPEN being the biggest thorn, I owe you a proposal.  Here it
is.

OPEN takes a filename as its first argument.  The rest of its arguments
are keyword/value pairs.

WITH-OPEN-STREAM's first subform is a list of a variable (to be bound to
a stream), a filename, and the rest of the elements are keyword/value
pairs.

The keywords are as follows, with their possible values and defaults:

:DIRECTION	:INPUT (the default), :OUTPUT, :APPEND, :OVERWRITE, :PROBE
	:INPUT - The file is expected to exist.  Output operations are not allowed.
	:OUTPUT - The file is expected to not exist.  A new file is created.  Input
			operations are not allowed.
	:APPEND - The file is expected to exist.  Input operations are not allowed.
			New characters are appened to the end of the existing file.
	:OVERWRITE - The file is expected to exist.  All operations are allowed.
			The "file pointer" starts at the beginning of the file.
	:PROBE - The file may or may not exist.  Neither input nor output operations
			are allowed.  Furthermore, it is not necessary to close the stream.

:CHARACTERS	T (the default), NIL, :DEFAULT
	T - Open the file for reading/writing of characters.
	NIL - Open the file for reading/writing of bytes (non-negative integers).
	:DEFAULT - Let the file system decide, based on the file it finds.

:BYTE-SIZE	a fixnum or :DEFAULT (the default)
	a fixnum - Use this byte size.
	:DEFAULT - Let the file system decide, based on the file it finds.

:IF-EXISTS	:ERROR (the default), :NEW-VERSION, :RENAME,
		:RENAME-AND-DELETE, :OVERWRITE, :APPEND, :REPLACE
	Ignored if direction is not :OUTPUT.  This tells what to do if the file
	that you're trying to create already exists.
	:ERROR - Signal an error.
	:NEW-VERSION - Create a file with the same filename except with "latest" version.
	:RENAME - Rename the existing file to something else and proceed.
	:RENAME-AND-DELETE - Rename the existing file and delete (but don't expunge,
		if your system has undeletion) it, and proceed.
	:OVERWRITE - Open for :OVERWRITE instead.  (If your file system doesn't have
		this, use :RENAME-AND-DELETE if you have undeletion and :RENAME otherwise.)
	:APPEND - Open for :APPEND instead.
	:REPLACE - Replace the existing file, deleting it when the stream is closed.

:IF-DOES-NOT-EXIST	:ERROR (the default), :CREATE
	Ignored if direction is neither :APPEND nor :OVERWRITE
	:ERROR - Signal an error.
	:CREATE - Create the file and proceed.


Notes:

I renamed :READ-ALTER to :OVERWRITE; :READ-WRITE might also be good.

The :DEFAULT values are very useful, although some systems cannot figure
out this information.  :CHARACTERS :DEFAULT is especially useful for
LOAD.  Having the byte size come from the file only when the option is
missing, as the latest Common Lisp manual says, is undesirable because
it makes things harder for programs that are passing the value of that
keyword argument as computed from an expression.

Example of OPEN:
     (OPEN "f:>dlw>lispm.init" :DIRECTION :OUTPUT)

Example of WITH-OPEN-FILE:
     (WITH-OPEN-FILE (STREAM "f:>dlw>lispm.init" :DIRECTION :OUTPUT) ...)

OPEN can be kept Maclisp compatible by recognizing whether the second
argument is a list or not.  Lisp Machine Lisp does this for the benefit
of old programs.  The new syntax cannot be mistaken for the old one.

I removed :ECHO because we got rid of MAKE-ECHO-STREAM at the last
meeting.

Other options that the Lisp Machine will probably have, and which might
be candidates for Common Lisp, are: :INHIBIT-LINKS, :DELETED,
:PRESERVE-DATES, and :ESTIMATED-SIZE.

∂04-Oct-82  1642	Ginder at CMU-20C 	dlw's OPEN proposal  
Date:  4 Oct 1982 1940-EDT
From: Ginder at CMU-20C
Subject: dlw's OPEN proposal
To: steele at CMU-20C
cc: common-lisp at SU-AI

The :APPEND keyword may be misleading in conjuction with Sesame's
"write once" files.  I suppose you could copy the contents of the
:APPEND'ed file into a new one and start from there and consider this
an implementation detail.  Where would stuff like this be explained in
the manual?  Where would the LM people's extensions be explained?  I
realize that these explanations are to be in the "red pages", but does
that mean that I have to look up both the white pages and red pages
documentation for a system fun?  What if it's also extended in the
yellow pages?  Will red and yellow pages be inserted into the middle
of the white pages at "appropriate" places?  Pointers to them?  
-Joe
-------

∂04-Oct-82  2042	Guy.Steele at CMU-10A 	Explanation of "Sesame"    
Date:  4 October 1982 2250-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Explanation of "Sesame"

Sesame is the Spice file system, to which Spice LISP must eventually
interface.  If we are lucky, they'll let us tell them what we need.

∂04-Oct-82  2042	Guy.Steele at CMU-10A 	HIC lambda macros
Date:  4 October 1982 2341-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: HIC lambda macros

I have a question about the proposed lambda macros: do they occupy the
function name space, or a separate name space?  That is, can I have
a lambda macro and also an ordinary macro with the same name?  Or
a function and a lambda-macro with the same name?

∂04-Oct-82  2047	Howard I. Cannon <HIC at MIT-MC> 	HIC lambda macros    
Date: 4 October 1982 23:46-EDT
From: Howard I. Cannon <HIC at MIT-MC>
Subject:  HIC lambda macros
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

    Date: 4 October 1982 2341-EDT (Monday)
    From: Guy.Steele at CMU-10A
    To:   common-lisp at SU-AI
    Re:   HIC lambda macros

    I have a question about the proposed lambda macros: do they occupy the
    function name space, or a separate name space?  That is, can I have
    a lambda macro and also an ordinary macro with the same name?  Or
    a function and a lambda-macro with the same name?

They occupy a different namespace.  On the Lisp Machine, lambda macros
reside on the LAMBDA-MACRO property of their name.  However, there is
a function-spec to reference them by, so you don't need to know this.

∂04-Oct-82  2130	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	suggestions on floating point numbers and hash tables
Date:  5 Oct 1982 0030-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: suggestions on floating point numbers and hash tables
To: common-lisp at SU-AI

We have just finished most of the code needed to support Common Lisp
numbers, and are working on hash tables.  In the process, we have
noticed a few things:

When you see 1.0, it is hard to know what the precision is. We would
like to make sure that if you write something out and read it back in,
it is EQUAL to what you started with.  Thus you should consider doing
one of the following:

  - adopt a convention where you can tell the precision based on the
	number of digits printed.  E.g. 1.00000 would be single, but
	1.000000000000000 would be double.  If you follow such a
	convention in both READ and PRINT, it should be possible to
	preserve the type.  (This would replace the
	READ-DEFAULT-FLOAT-FORMAT flag.) This has the advantage of being
	to some extent machine-independent, in that 1.0000 might be
	single-precision on the VAX and short on the DEC-20.

  - always print an exponent marker, or maybe always print it when the
	it is not the same as READ-DEFAULT-FLOAT-FORMAT.

(At the moment, we are always supplying an exponent marker when it is
different from the default.)

We do not notice any way to write out hash tables.  We suggest that you
adopt a # syntax for that.  In my opinion, it should be possible to
write out and read back in as many kinds of user data structures as is
possible.

You specify a default packing factor of .8 for hash tables. I wonder
whether you really want this number to be defined in the manual. It
seems to me that the best packing factor may well be
implementation-dependent, because it will depend upon the way the
implementors have taken certain space-time tradeoffs. For various
reasons we are looking at using a algorithm where resolving clashes will
be fairly expensive.  Thus we intend to use a much lower default packing
factor.  (The method involved would use less storage space per item, so
we could afford the larger tables implied.)  

Finally, we wonder whether having separate MAKE-xxx-HASH-TABLE functions
but the same PUT-HASH and GET-HASH for all types is the right way to go.
At least in our implementation, the structure of all hash tables is
identical.  What is different among the tables is how you compare
entries.  We think it would make more sense to have one MAKE-HASH-TABLE
and separate access functions.  Since the user supplies to hash table
type when he creates it, we just have to save it somewhere in the table,
and then use it behind his back to change the meaning of the access
functions.  Although I don't quite know how one would use it, in
principle it would make sense to put different kinds of items into the
same hash table using different functions, something that is ruled out
by your proposal.  Also, if there were only one kind of hash table, it
would be slightly easier to PRINT and READ them.

-------

∂04-Oct-82  2138	Scott E. Fahlman <Fahlman at Cmu-20c> 	White, red, and yellow pages   
Date: Tuesday, 5 October 1982  00:37-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Ginder at CMU-20C
Cc:   common-lisp at SU-AI
Subject: White, red, and yellow pages


There are a number of operating systems that will not be able to support
:APPEND to files.  Where it is clear that there will be some differences
between implementations, the white pages should mention this: "Note: not
all implementations will be able to support :APPEND."  Or some such.

In general, it is impossible for the white pages to flag all extensions
made by all current and future Common Lisp implementations, so you will
indeed have to be familiar with the red pages for your implementation.
Most of the extensions will be easy to remember, or will be things you
never want to use anyway; for the others, an obvious techniques is to
mark the passage in the white pages that are modified in the red.
I assume that Zetalisp will continue to have a separate manual, so their
very extensive supersetting will not be a problem.

-- Scott

∂04-Oct-82  2148	Guy.Steele at CMU-10A 	Moon's floating-point extractors proposal 
Date:  4 October 1982 2355-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Moon's floating-point extractors proposal

I support Moon's proposal, but would like to suggest that FLOAT-SIGN
be modified to
	(FLOAT-SIGN x &optional (y (float 1 x)))
	returns z such that x and z have same sign and (= (abs y) (abs z)).
In this way (FLOAT-SIGN x) returns 1.0 or -1.0 of the same format as x,
and FLOAT-SIGN of two arguments is what the IEEE proposal calls COPYSIGN,
a useful function indeed in numerical code.
--Guy

∂04-Oct-82  2145	STEELE at CMU-20C 	/BALLOT/   
Date:  5 Oct 1982 0041-EDT
From: STEELE at CMU-20C
Subject: /BALLOT/
To: common-lisp at SU-AI
cc: b.steele at CMU-10A

?????????????????????????????????????????????????????????????????????????????
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?  %  =================================================================  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  #  /  The October 1982 Common LISP Ballot  /  #  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =================================================================  %  ?
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?????????????????????????????????????????????????????????????????????????????

Here is what you have all been waiting for!  I need an indication of
consensus or lack thereof on the issues that have been discussed by
network mail since the August 1982 meeting, particularly on those issues
that were deferred for proposal for which proposals have now been made.

There are 28 questions, each requiring only a one-letter answer.  As always,
if you don't like any of the choices, answer "x".  To make my life easier
by permitting mechanical collation of responses, please respond as follows:
	(a) send a reply message to Guy.Steele @ CMU-10A.
	(b) *PLEASE* be sure the string "/BALLOT/" is in the subject line,
	    as it is in this message (the double quotes, not the slashes,
	    are metasyntactic!).
	(c) The very first non-blank line of your message should have
	    exactly 29 non-blank characters on it.  The first should be a
	    tilde ("~") and the rest should be your votes.
	    You may put spaces between the letters to improve readability.
	(d) Following the first non-blank line, place any remarks about
	    issues on which you voted "x".
Thank you for your help.  I would appreciate response by Friday, October 8.
--Guy

1.  How shall the case for a floating-point exponent specifier
output by PRINT and FORMAT be determined?
	(a) upper case, for example 3.5E6
	(b) lower case, for example 3.5e6
	(c) a switch
	(d) implementation-dependent

2.  Shall we change the name SETF to be SET?   (y) yes   (n) no

3.  Shall there be a type specifier QUOTE, such that (QUOTE x) = (MEMBER x)?
Then MEMBER can be eliminated; (MEMBER x y z) = (OR 'x 'y 'z).  Also one can
write such things as (OR INTEGER 'FOO) instead of (OR INTEGER (MEMBER FOO)).
	(y) yes   (n) no

4.  Shall MOON's proposal for LOAD keywords, revised as shown below, be used?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Wednesday, 25 August 1982, 14:01-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
	[slightly revised]
Here is a revised proposal:

Keyword		Default		Meaning

:PACKAGE	NIL		NIL means use file's native package, non-NIL
				is a package or name of package to load into.

:VERBOSE	*LOAD-VERBOSE*	T means print a message saying what file is
				being loaded into which package.

:PRINT		NIL		T means print values of forms as they are evaluated.

:ERROR		T		T means handle errors normally; NIL means that
				a file-not-found error should return NIL
				rather than signalling an error.  LOAD returns
				the pathname (or truename??) of the file it
				loaded otherwise.

:SET-DEFAULT-PATHNAME	*LOAD-SET-DEFAULT-PATHNAME*
				T means update the pathname default
				for LOAD from the argument, NIL means don't.

:STREAM		NIL		Non-NIL means this is an open stream to be
				loaded from.  (In the Lisp machine, the
				:CHARACTERS message to the stream is used to
				determine whether it contains text or binary.)
				The pathname argument is presumed to be associated
				with the stream, in systems where that information
				is needed.

The global variables' default values are implementation dependent, according
to local conventions, and may be set by particular users according to their
personal taste.

I left out keywords to allow using a different set of defaults from the normal
one and to allow explicit control over whether a text file or a binary file
is being loaded, since these don't really seem necessary.  If we put them in,
the consistent names would be :DEFAULT-PATHNAME, :CHARACTERS, and :BINARY.
----------------------------------------------------------------

5.  Shall closures over dynamic variables be removed from Common LISP?
	(y) yes   (n) no

6.  Shall LOOP, as summarized below, be included in Common LISP?
	(y) yes   (n) no
----------------------------------------------------------------
Date: 26 August 1982 18:51-EDT
From: David A. Moon <MOON at MIT-MC>

Here is an extremely brief summary of the proposed new LOOP design, which
has not yet been finalized.  Consult the writeup on LOOP in the Lisp
Machine manual or MIT LCS TM-169 for background information.  Constructive
comments are very welcome, but please reply to BUG-LOOP at MIT-ML, not to
me personally.

(LOOP form form...) repeatedly evaluates the forms.

In general the body of a loop consists of a series of clauses.  Each
clause is either: a series of one or more lists, which are forms to be
evaluated for effect, delimited by a symbol or the end of the loop; or
a clause-introducing symbol followed by idiosyncratic syntax for that
kind of clause.  Symbols are compared with SAMEPNAMEP.  Atoms other than
symbols are in error, except where a clause's idiosyncratic syntax permits.

1. Primary clauses

1.1 Iteration driving clauses

These clauses run a local variable through a series of values and/or
generate a test for when the iteration is complete.

REPEAT <count>
FOR/AS <var> ...
CYCLE <var> ...

  I won't go into the full syntax here.  Features include: setting
  to values before starting/on the first iteration/on iterations after
  the first; iterating through list elements/conses; iterating through
  sequence elements, forwards or backwards, with or without sequence-type
  declaration; iterating through arithmetic progressions.  CYCLE reverts
  to the beginning of the series when it runs out instead of terminating
  the iteration.

  It is also possible to control whether or not an end-test is generated
  and whether there is a special epilogue only evaluated when an individual
  end-test is triggered.

1.2 Prologue and Epilogue

INITIALLY form form...		forms to be evaluated before starting, but
				after binding local variables.
FINALLY form form...		forms to be evaluated after finishing.

1.3 Delimiter

DO	a sort of semicolon needed in odd situations to terminate a clause,
	for example between an INITIALLY clause and body forms when no named
	clause (e.g. an iteration-driving clause) intervenes.
	We prefer this over parenthesization of clauses because of the
	general philosophy that it is more important to make the simple cases
	as readable as possible than to make micro-improvements in the
	complicated cases.

1.4 Blockname

NAMED name		Gives the block generated by LOOP a name so that
			RETURN-FROM may be used.

This will be changed to conform with whatever is put into Common Lisp
for named PROGs and DOs, if necessary.

2. Relevant special forms

The following special forms are useful inside the body of a LOOP.  Note
that they need not appear at top level, but may be nested inside other
Lisp forms, most usefully bindings and conditionals.

(COLLECT <value> [USING <collection-mode>] [INTO <var>] [BACKWARDS]
		[FROM <initial-value>] [IF-NONE <expr>] [[TYPE] <type>])
This special form signals an error if not used lexically inside a LOOP.
Each time it is evaluated, <value> is evaluated and accumulated in a way
controlled by <collection-mode>; the default is to form an ordered list.
The accumulated values are returned from the LOOP if it is finished
normally, unless INTO is used to put them into a variable (which gets
bound locally to the LOOP).  Certain accumulation modes (boolean AND and
OR) cause immediate termination of the LOOP as soon as the result is known,
when not collecting into a variable.

Collection modes are extensible by the user.  A brief summary of predefined
ones includes aggregated boolean tests; lists (both element-by-element and
segment-by-segment); commutative/associative arithmetic operators (plus,
times, max, min, gcd, lcm, count); sets (union, intersection, adjoin);
forming a sequence (array, string).

Multiple COLLECT forms may appear in a single loop; they are checked for
compatibility (the return value cannot both be a list of values and a
sum of numbers, for example).

(RETURN value) returns immediately from a LOOP, as from any other block.
RETURN-FROM works too, of course.

(LOOP-FINISH) terminates the LOOP, executing the epilogue and returning
any value defined by a COLLECT special form.

[Should RESTART be interfaced to LOOP, or only be legal for plain blocks?]

3. Secondary clauses

These clauses are useful abbreviations for things that can also be done
using the primary clauses and Lisp special forms.  They exist to make
simple cases more readable.  As a matter of style, their use is strongly
discouraged in complex cases, especially those involving complex or
nested conditionals.

3.1 End tests

WHILE <expr>		(IF (NOT <expr>) (LOOP-FINISH))
UNTIL <expr>		(IF <expr> (LOOP-FINISH))

3.2 Conditionals

WHEN <expr> <clause>	The clause is performed conditionally.
IF <expr> <clause>	synonymous with WHEN
UNLESS <expr> <clause>	opposite of WHEN

AND <clause>		May be suffixed to a conditional.  These two
ELSE <clause>		might be flushed as over-complex.

3.3 Bindings

WITH <var> ...		Equivalent to wrapping LET around the LOOP.
			This exists to promote readability by decreasing
			indentation.

3.4 Return values

RETURN <expr>		synonymous with (RETURN <expr>)

COLLECT ...		synonymous with (COLLECT ...)
NCONC ...		synonymous with (COLLECT ... USING NCONC)
APPEND, SUM, COUNT, MINIMIZE, etc. are analogous
ALWAYS, NEVER, THEREIS	abbreviations for boolean collection

4. Extensibility

There are ways for users to define new iteration driving clauses which
I will not go into here.  The syntax is more flexible than the existing
path mechanism.

There are also ways to define new kinds of collection.

5. Compatibility

The second generation LOOP will accept most first-generation LOOP forms
and execute them in the same way, although this was not a primary goal.
Some complex (and unreadable!) forms will not execute the same way or
will be errors.

6. Documentation

We intend to come up with much better examples.  Examples are very
important for developing a sense of style, which is really what LOOP
is all about.
----------------------------------------------------------------

7.  Regardless of the outcome of the previous question, shall CYCLE
be retained and be renamed LOOP, with the understanding that statements
of the construct must be non-atomic, and atoms as "statements" are
reserved for extensions, and any such extensions must be compatible
with the basic mening as a pure iteration construct?
	(y) yes   (n) no

8.  Shall ARRAY-DIMENSION be changed by exchanging its arguments,
to have the array first and the axis number second, to parallel
other indexing operations?
	(y) yes   (n) no

9.  Shall MACROEXPAND, as described below, replace the current definition?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Sunday, 29 August 1982, 21:26-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>

Here is my promised proposal, with some help from Alan.

MACRO-P becomes a predicate rather than a pseudo-predicate.
Everything on pages 92-93 (29July82) is flushed.

Everything, including the compiler, expands macros by calling MACROEXPAND
or MACROEXPAND-1.  A variable, *MACROEXPAND-HOOK*, is provided to allow
implementation of displacing, memoization, etc.

The easiest way to show the details of the proposal is as code.  I'll try to
make it exemplary.

(DEFVAR *MACROEXPAND-HOOK* 'FUNCALL)

(DEFUN MACROEXPAND (FORM &AUX CHANGED)
  "Keep expanding the form until it is not a macro-invocation"
  (LOOP (MULTIPLE-VALUE (FORM CHANGED) (MACROEXPAND-1 FORM))
	(IF (NOT CHANGED) (RETURN FORM))))

(DEFUN MACROEXPAND-1 (FORM)
  "If the form is a macro-invocation, return the expanded form and T.
  This is the only function that is allowed to call macro expander functions.
  *MACROEXPAND-HOOK* is used to allow memoization."
  (DECLARE (VALUES FORM CHANGED-FLAG))

  (COND ((AND (PAIRP FORM) (SYMBOLP (CAR FORM)) (MACRO-P (CAR FORM)))
	 (LET ((EXPANDER (---get expander function--- (CAR FORM))))
	   ---check for wrong number of arguments---
	   (VALUES (FUNCALL *MACROEXPAND-HOOK* EXPANDER FORM) T)))
	(T FORM)))

;You can set *MACROEXPAND-HOOK* to this to get traditional displacing
(DEFUN DISPLACING-MACROEXPAND-HOOK (EXPANDER FORM)
  (LET ((NEW-FORM (FUNCALL EXPANDER FORM)))
    (IF (ATOM NEW-FORM)
	(SETQ NEW-FORM `(PROGN ,NEW-FORM)))
    (RPLACA FORM (CAR NEW-FORM))
    (RPLACD FORM (CDR NEW-FORM))
    FORM))

The above definition of MACROEXPAND-1 is oversimplified, since it can
also expand other things, including lambda-macros (the subject of a separate
proposal that has not been sent yet) and possibly implementation-dependent
things (substs in the Lisp machine, for example).

The important point here is the division of labor.  MACROEXPAND-1 takes care
of checking the length of the macro-invocation to make sure it has the right
number of arguments [actually, the implementation is free to choose how much
of this is done by MACROEXPAND-1 and how much is done by code inserted into
the expander function by DEFMACRO].  The hook takes care of memoization.  The
macro expander function is only concerned with translating one form into
another, not with bookkeeping.  It is reasonable for certain kinds of
program-manipulation programs to bind the hook variable.

I introduced a second value from MACROEXPAND-1 instead of making MACROEXPAND
use the traditional EQ test.  Otherwise a subtle change would have been
required to DISPLACING-MACROEXPAND-HOOK, and some writers of hooks might get
it wrong occasionally, and their code would still work 90% of the time.


Other issues:

On page 93 it says that MACROEXPAND ignores local macros established by
MACROLET.  This is clearly incorrect; MACROEXPAND has to get called with an
appropriate lexical context available to it in the same way that EVAL does.
They are both parts of the interpreter.  I don't have anything to propose
about this now; I just want to point out that there is an issue.  I don't
think we need to deal with the issue immediately.

A related issue that must be brought up is whether the Common Lisp subset
should include primitives for accessing and storing macro-expansion
functions.  Currently there is only a special form (MACRO) to set a
macro-expander, and no corresponding function.  The Lisp machine expedient of
using the normal function-definition primitive (FDEFINE) with an argument of
(MACRO . expander) doesn't work in Common Lisp.  Currently there is a gross
way to get the macro expander function, but no reasonable way.  I don't have
a clear feeling whether there are programs that would otherwise be portable
except that they need these operations.
----------------------------------------------------------------

10.  Shall all global system-defined variables have names beginning
and ending with "*", for example *PRINLEVEL* instead of PRINLEVEL
and *READ-DEFAULT-FLOAT-FORMAT* instead of READ←DEFAULT-FLOAT-FORMAT?
	(y) yes   (n) no

11.  Same question for named constants (other than T and NIL), such as
*PI* for PI and *MOST-POSITIVE-FIXNUM* for MOST-POSITIVE-FIXNUM.
	(y) yes   (n) no   (o) yes, but use a character other than "*"

12.  Shall a checking form CHECK-TYPE be introduced as described below?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Thursday, 26 August 1982, 03:04-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>

See p.275 of the 29 July Common Lisp manual and p.275 of the revision
handed out at the Lisp conference.

I suggest that we include CHECK-ARG-TYPE in the language.  Although
CHECK-ARG, CHECK-ARG-TYPE, and ASSERT have partially-overlapping
functionality, each has its own valuable uses and I think all three
ought to be in the language.

Note that CHECK-ARG and CHECK-ARG-TYPE are used when you want explicit
run-time checking, including but not limited to writing the interpreter
(which of course is written in Lisp, not machine language!).

The details:
CHECK-ARG-TYPE arg-name type &OPTIONAL type-string	[macro]

If (TYPEP arg-name 'type) is false, signal an error.  The error message
includes arg-name and a "pretty" English-language form of type, which
can be overridden by specifying type-string (this override is rarely
used).  Proceeding from the error sets arg-name to a new value and
makes the test again.

Currently arg-name must be a variable, but it should be generalized to
any SETF'able place.

type and type-string are not evaluated.

This isn't always used for checking arguments, since the value of any
variable can be checked, but it is usually used for arguments and there
isn't an alternate name that more clearly describes what it does.

Date: 2 Sep 1982 12:30 PDT
From: JonL at PARC-MAXC

PDP10 MacLisp and VAX/NIL have had the name CHECK-TYPE for several 
years for essentially this functionality (unless someone has recently renamed
it).   Since it is used to certify the type of any variable's value,  it did not
include the "-ARG" part.  The motivation was to have a "checker" which was
more succinct than CHECK-ARGS, but which would generally open-code the
type test (and hence introduce no delay to the non-error case).  

I rather prefer the semantics you suggested, namely that the second argument 
to CHECK-TYPE be a type name (given the CommonLisp treatment of type
hierarchy).  At some level, I'd think a "promise" of fast type checking should
be guaranteed (in compiled code) so that persons will prefer to use this
standardized facililty;  without some indication of performance, one would
be tempted to write his own in order not to slow down the common case.
----------------------------------------------------------------

13.  Shall a checking form CHECK-SUBSEQUENCE be introduced as described below?
	(y) yes   (n) no
----------------------------------------------------------------
Date: 2 Sep 1982 12:30 PDT
From: JonL at PARC-MAXC

If the general sequence functions continue to thrive in CommonLisp, I'd
like to suggest that the corresponding CHECK-SUBSEQUENCE macro (or
whatever renaming of it should occur) be included in CommonLisp.  

  CHECK-SUBSEQUENCE (<var> <start-index> <count>) &optional <typename>)

provides a way to certify that <var> holds a sequence datum of the type
<typename>, or of any suitable sequence type (e.g., LIST, or STRING or 
VECTOR etc) if <typename> is null; and that the indicated subsequence
in it is within the size limits.

[GLS: probably <end> is more appropriate than <count> for Common LISP.]
----------------------------------------------------------------

14.  Shall the functions LINE-OUT and STRING-OUT, eliminated in November,
be reinstated?
	(y) yes   (n) no

15.  Shall the REDUCE function be added as described below?
	(y) yes   (n) no
----------------------------------------------------------------
Date:  3 September 1982 1756-EDT (Friday)
From: Guy.Steele at CMU-10A

I would like to mildly re-propose the REDUCE function for Common
LISP, now that adding it would require only one new function, not ten
or fifteen:

REDUCE function sequence &KEY :START :END :FROM-END :INITIAL-VALUE
    The specified subsequence of "sequence" is reduced, using the "function"
    of two arguments.  The reduction is left-associative, unless
    :FROM-END is not false, in which case it is right-associative.
    If the an :INITIAL-VALUE is given, it is logically placed before the
    "sequence" (after it if :FROM-END is true) and included in the
    reduction operation.  If no :INITIAL-VALUE is given, then the "sequence"
    must not be empty.  (An alternative specification: if no :INITIAL-VALUE
    is given, and "sequence" is empty, then "function" is called with
    zero arguments and the result returned.  How about that?  This idea
    courtesy of Dave Touretzky.)

    (REDUCE #'+ '(1 2 3 4)) => 10
    (REDUCE #'- '(1 2 3 4)) => -8
    (REDUCE #'- '(1 2 3 4) :FROM-END T) => -2   ;APL-style
    (REDUCE #'LIST '(1 2 3 4)) => (((1 2) 3) 4)
    (REDUCE #'LIST '(1 2 3 4) :FROM-END T) => (1 (2 (3 4)))
    (REDUCE #'LIST '(1 2 3 4) :INITIAL-VALUE 'FOO) => ((((FOO 1) 2) 3) 4)
    (REDUCE #'LIST '(1 2 3 4) :FROM-END T :INITIAL-VALUE 'FOO)
				 => (1 (2 (3 (4 FOO))))
----------------------------------------------------------------

16.  Shall the Bawden/Moon solution to the "invisible block" problem
be accepted?  The solution is to define (RETURN x) to mean precisely
(RETURN-FROM NIL x), and to specify that essentially all standard
iterators produce blocks named NIL.  A block with a name other than
NIL cannot capture a RETURN, only a RETURN-FROM with a matching name.
	(y) yes   (n) no

17.  Shall the TAGBODY construct be incorporated?  This expresses just
the behavior of the GO aspect of a PROG.  Any atoms in the body
are not evaluated, but serve as tags that may be specified to GO.
Tags have lexical scope and dynamic extent.  TAGBODY always returns NIL.
	(y) yes   (n) no

18.  What shall be done about RESTART?  The following alternatives seem to
be the most popular:
	(a) Have no RESTART form.
	(b) RESTART takes the name of a block.  What happens when you say
	    (RESTART NIL) must be clarified for most iteration constructs.
	(c) There is a new binding form called, say, RESTARTABLE.
	    Within (RESTARTABLE FOO . body), (RESTART FOO) acts as a jump
	    to the top of the body of the enclosing, matching RESTARTABLE form.
	    RESTART tags have lexical scope and dynamic extent.

19.  Shall there be a built-in identity function, and if so, what shall it
be called?
	(c) CR   (i) IDENTITY   (n) no such function

20.  Shall the #*... bit-string syntax replace #"..."?  That is, shall what
was before written #"10010" now be written #*10010 ?
	(y) yes   (n) no

21.  Which of the two outstanding array proposals (below) shall be adopted?
	(s) the "simple" proposal
	(r) the "RPG memorial" proposal
	(m) the "simple" proposal as amended by Moon
----------------------------------------------------------------
*********** "Simple" proposal **********
Date: Thursday, 16 September 1982  23:27-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>

Here is a revision of my array proposal, fixed up in response to some of
the feedback I've received.  See if you like it any better than the
original.  In particular, I have explictly indicated that certain
redundant forms such as MAKE-VECTOR should be retained, and I have
removed the :PRINT keyword, since I now believe that it causes more
trouble than it is worth.  A revised printing proposal appears at the
end of the document.


Arrays can be 1-D or multi-D.  All arrays can be created by MAKE-ARRAY
and can be accessed with AREF.  Storage is done via SETF of an AREF.
The term VECTOR refers to any array of exactly one dimension.
Vectors are special, in that they are also sequences, and can be
referenced by ELT.  Also, only vectors can have fill pointers.

Vectors can be specialized along several distinct axes.  The first is by
the type of the elements, as specified by the :ELEMENT-TYPE keyword to
MAKE-ARRAY.  A vector whose element-type is STRING-CHAR is referred to
as a STRING.  Strings, when they print, use the "..." syntax; they also
are the legal inputs to a family of string-functions, as defined in the
manual.  A vector whose element-type is BIT (alias (MOD 2)), is a
BIT-VECTOR.  These are special because they form the set of legal inputs
to the boolean bit-vector functions.  (We might also want to print them
in a strange way -- see below.)

Some implementations may provide a special, highly efficient
representation for simple vectors.  A simple vector is (of course) 1-D,
cannot have a fill pointer, cannot be displaced, and cannot be altered
in size after its creation.  To get a simple vector, you use the :SIMPLE
keyword to MAKE-ARRAY with a non-null value.  If there are any
conflicting options specified, an error is signalled.  If an
implementation does not support simple vectors, this keyword/value is
ignored except that the error is still signalled on inconsistent cases.

We need a new set of type specifiers for simple things: SIMPLE-VECTOR,
SIMPLE-STRING, and SIMPLE-BIT-VECTOR, with the corresponding
type-predicate functions.  Simple vectors are referenced by AREF in the
usual way, but the user may use THE or DECLARE to indicate at
compile-time that the argument is simple, with a corresponding increase
in efficiency.  Implementations that do not support simple vectors
ignore the "simple" part of these declarations.

Strings (simple or non-simple) self-eval; all other arrays cause an
error when passed to EVAL.  EQUAL descends into strings, but not
into any other arrays.  EQUALP descends into arrays of all kinds,
comparing the corresponding elements with EQUALP.  EQUALP is false
if the array dimensions are not the same, but it is not sensitive to
the element-type of the array, whether it is simple, etc.  In comparing
the dimensions of vectors, EQUALP uses the length from 0 to the fill
pointer; it does not look at any elements beyond the fill pointer.

The set of type-specifiers required for all of this is ARRAY, VECTOR,
STRING, BIT-VECTOR, SIMPLE-VECTOR, SIMPLE-STRING, SIMPLE-BIT-VECTOR.
Each of these has a corresponding type-P predicate, and each can be
specified in list from, along with the element-type and dimension(s).

MAKE-ARRAY takes the following keywords: :ELEMENT-TYPE, :INITIAL-VALUE,
:INITIAL-CONTENTS, :FILL-POINTER, and :SIMPLE.  There is still some
discussion as to whether we should retain array displacement, which
requires :DISPLACED-TO and :DISPLACED-INDEX-OFFSET.

The following functions are redundant, but should be retained for
clarity and emphasis in code: MAKE-VECTOR, MAKE-STRING, MAKE-BIT-VECTOR.
MAKE-VECTOR takes the same keywords as MAKE-ARRAY, but can only take a
single integer as the dimension argument.  MAKE-STRING and
MAKE-BIT-VECTOR are like MAKE-VECTOR, but do not take the :ELEMENT-TYPE
keyword, since the element-type is implicit.  Similarly, we should
retain the forms VREF, CHAR, and BIT, which are identical in operation
to AREF, but which declare their aray argument to be VECTOR, STRING, or
BIT-VECTOR, respectively.

If the :SIMPLE keyword is not specified to MAKE-ARRAY or related forms,
the default is NIL.  However, vectors produced by random forms such as
CONCATENATE are simple, and vectors created when the reader sees #(...)
or "..." are also simple.

As a general rule, arrays are printed in a simple format that, upon
being read back in, produces a form that is EQUALP to the original.
However, some information may be lost in the printing process:
element-type restrictions, whether a vector is simple, whether it has a
fill pointer, whether it is displaced, and the identity of any element
that lies beyond the fill pointer.  This choice was made to favor ease
of interactive use; if the user really wants to preserve in printed form
some complex data structure containing non-simple arrays, he will have
to develop his own printer.

A switch, SUPPRESS-ARRAY-PRINTING, is provided for users who have lots
of large arrays around and don't want to see them trying to print.  If
non-null, this switch causes all arrays except strings to print in a
short, non-readable form that does not include the elements:
#<array-...>.  In addition, the printing of arrays and vectors (but not
of strings) is subject to PRINLEVEL and PRINLENGTH.

Strings, simple or otherwise, print using the "..."  syntax.  Upon
read-in, the "..." syntax creates a simple string.

Bit-vectors, simple or otherwise, print using the #"101010..." syntax.
Upon read-in, this format produces a simple bit-vector.  Bit vectors do
observe SUPPRESS-ARRAY-PRINTING.

All other vectors print out using the #(...) syntax, observing
PRINLEVEL, PRINLENGTH, and SUPPRESS-ARRAY-PRINTING.  This format reads
in as a simple vector of element-type T.

All other arrays print out using the syntax #nA(...), where n is the
number of dimensions and the list is a nest of sublists n levels deep,
with the array elements at the deepest level.  This form observes
PRINLEVEL, PRINLENGTH, and SUPPRESS-ARRAY-PRINTING.  This format reads
in as an array of element-type T.

Query: I am still a bit uneasy about the funny string-like syntax for
bit vectors.  Clearly we need some way to read these in that does not
turn into a type-T vector.  An alternative might be to allow #(...) to
be a vector of element-type T, as it is now, but to take the #n(...)
syntax to mean a vector of element-type (MOD n).  A bit-vector would
then be #2(1 0 1 0...) and we would have a parallel notation available
for byte vectors, 32-bit word vectors, etc.  The use of the #n(...)
syntax to indicate the length of the vector always struck me as a bit
useless anyway.  One flaw in this scheme is that it does not extend to
multi-D arrays.  Before someone suggests it, let me say that I don't
like #nAm(...), where n is the rank and m is the element-type -- it
would be too hard to remember which number was which.  But even with
this flaw, the #n(...) syntax might be useful.

********** "RPG memorial" proposal **********
Date: Thursday, 23 September 1982  00:38-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>

Several people have stated that they dislike my earlier proposal because
it uses the good names (VECTOR, STRING, BIT-VECTOR, VREF, CHAR, BIT) on
general 1-D arrays, and makes the user say "simple" when he wants one of
the more specialized high-efficiency versions.  This makes extra work
for users, who will want simple vectors at least 95% of the time.  In
addition, there is the argument that simple vectors should be thought of
as a first-class data-type (in implementations that provide them) and
not as a mere degenerate form of array.

Just to see what it looks like, I have re-worked the earlier proposal to
give the good names to the simple forms.  This does not really eliminate
any of the classes in the earlier proposal, since each of those classes
had some attributes or operations that distinguished it from the others.

Since there are getting to be a lot of proposals around, we need some
nomencalture for future discussions.  My first attempt, with the
user-settable :PRINT option should be called the "print-switch"
proposal; the next one, with the heavy use of the :SIMPLE switch should
be the "simple-switch" proposal; this one can be called the "RPG
memorial" proposal.  Let me know what you think about this vs. the
simple-switch version -- I can live with either, but I really would like
to nail this down pretty soon so that we can get on with the
implementation.

Arrays can be 1-D or multi-D.  All arrays can be created by MAKE-ARRAY
and can be accessed with AREF.  Storage is done via SETF of an AREF.
1-D arrays are special, in that they are also of type SEQUENCE, and can
be referenced by ELT.  Also, only 1-D arrays can have fill pointers.

Some implementations may provide a special, highly efficient
representation for simple 1-D arrays, which will be of type VECTOR.  A
vector is 1-dimensional, cannot have a fill pointer, cannot be
displaced, and cannot be altered in size after its creation.  To get a
vector, you use the :VECTOR keyword to MAKE-ARRAY with a non-null value.
If there are any conflicting options specified, an error is signalled.
The MAKE-VECTOR form is equivalent to MAKE-ARRAY with :VECTOR T.

A STRING is a VECTOR whose element-type (specified by the :ELEMENT-TYPE
keyword) is STRING-CHAR.  Strings are special in that they print using
the "..." syntax, and they are legal inputs to a class of "string
functions".  Actually, these functions accept any 1-D array whose
element type is STRING-CHAR.  This more general class is called a
CHAR-SEQUENCE. 

A BIT-VECTOR is a VECTOR whose element-type is BIT, alias (MOD 2).
Bit-vectors are special in that they print using the #*... syntax, and
they are legal inputs to a class of boolean bit-vector functions.
Actually, these functions accept any 1-D array whose element-type is
BIT.  This more general class is called a BIT-SEQUENCE.

All arrays can be referenced via AREF, but in some implementations
additional efficiency can be obtained by declaring certain objects to be
vectors, strings, or bit-vectors.  This can be done by normal
type-declarations or by special accessing forms.  The form (VREF v n) is
equivalent to (AREF (THE VECTOR v) n).  The form (CHAR s n) is
equivalent to (AREF (THE STRING s) n).  The form (BIT b n) is equivalent
to (AREF (THE BIT-VECTOR b) n).

If an implementation does not support vectors, the :VECTOR keyword is
ignored except that the error is still signalled on inconsistent cases;
The additional restrictions on vectors are not enforced.  MAKE-VECTOR is
treated just like the equivalent make-array.  VECTORP is true of every
1-D array, STRINGP of every CHAR-SEQUENCE, and BIT-VECTOR of every
BIT-SEQUENCE.

CHAR-SEQUENCEs, including strings, self-eval; all other arrays cause an
error when passed to EVAL.  EQUAL descends into CHAR-SEQUENCEs, but not into
any other arrays.  EQUALP descends into arrays of all kinds, comparing
the corresponding elements with EQUALP.  EQUALP is false if the array
dimensions are not the same, but it is not sensitive to the element-type
of the array, whether it is a vector, etc.  In comparing the dimensions of
vectors, EQUALP uses the length from 0 to the fill pointer; it does not
look at any elements beyond the fill pointer.

The set of type-specifiers required for all of this is ARRAY, VECTOR,
STRING, BIT-VECTOR, SEQUENCE, CHAR-SEQUENCE, and BIT-SEQUENCE.
Each of these has a corresponding type-P predicate, and each can be
specified in list from, along with the element-type and dimension(s).

MAKE-ARRAY takes the following keywords: :ELEMENT-TYPE, :INITIAL-VALUE,
:INITIAL-CONTENTS, :FILL-POINTER, :DISPLACED-TO, :DISPLACED-INDEX-OFFSET,
and :VECTOR.

The following functions are redundant, but should be retained for
clarity and emphasis in code: MAKE-VECTOR, MAKE-STRING, MAKE-BIT-VECTOR.
MAKE-VECTOR takes a single length argument, along with :ELEMENT-TYPE,
:INITIAL-VALUE, and :INITIAL-CONTENTS.  MAKE-STRING and MAKE-BIT-VECTOR
are like MAKE-VECTOR, but do not take the :ELEMENT-TYPE keyword, since
the element-type is implicit.

If the :VECTOR keyword is not specified to MAKE-ARRAY or related forms,
the default is NIL.  However, sequences produced by random forms such as
CONCATENATE are vectors.

Strings always are printed using the "..." syntax.  Bit-vectors always
are printed using the #*... syntax.  Other vectors always print using
the #(...) syntax.  Note that in the latter case, any element-type
restriction is lost upon readin, since this form always produces a
vector of type T when it is read.  However, the new vector will be
EQUALP to the old one.  The #(...) syntax observes PRINLEVEL,
PRINLENGTH, and SUPPRESS-ARRAY-PRINTING.  The latter switch, if non-NIL,
causes the array to print in a non-readable form: #<ARRAY...>.

CHAR-SEQUENCEs print out as though they were strings, using the "..."
syntax.  BIT-SEQUENCES print out as BIT-STRINGS, using the #*... syntax.
All other arrays print out using the #nA(...) syntax, where n is the
number of dimensions and the list is actually a list of lists of lists,
nested n levels deep.  The array elements appear at the lowest level.
The #A syntax also observes PRINLEVEL, PRINLENGTH, and
SUPPRESS-ARRAY-PRINTING.  The #A format reads in as a non-displaced
array of element-type T.

Note that when an array is printed and read back in, the new version is
EQUALP to the original, but some information about the original is lost:
whether the original was a vector or not, element type restrictions,
whether the array was displaced, whether there was a fill pointer, and
the identity of any elements beyond the fill-pointer.  This choice was
made to favor ease of interactive use; if the user really wants to
preserve in printed form some complex data structure containing more
complex arrays, he will have to develop his own print format and printer.

********** Moon revision of "simple" proposal **********
Date: Thursday, 30 September 1982  01:59-EDT
From: MOON at SCRC-TENEX

I prefer the "simple switch" to the "RPG memorial" proposal, with one
modification to be found below.  The reason for this preference is that
it makes the "good" name, STRING for example, refer to the general class
of objects, relegating the efficiency decision to a modifier ("simple").
The alternative makes the efficiency issue too visible to the casual user,
in my opinion.  You have to always be thinking "do I only want this to
work for efficient strings, which are called strings, or should it work
for all kinds of strings, which are called arrays of characters?".
Better to say, "well this works for strings, and hmm, is it worth
restricting it to simple-strings to squeeze out maximal efficiency"?

Lest this seem like I am trying to sabotage the efficiency of Lisp
implementations that are stuck with "stock" hardware, consider the
following:

In the simple switch proposal, how is (MAKE-ARRAY 100) different from
(MAKE-ARRAY 100 :SIMPLE T)?  In fact, there is only one difference--it is
an error to use ADJUST-ARRAY-SIZE on the latter array, but not on the
former.  Except for this, simpleness consists, simply, of the absence of
options.  This suggests to me that the :SIMPLE option be flushed, and
instead a :ADJUSTABLE-SIZE option be added (see, I pronounce the colons).
Even on the Lisp machine, where :ADJUSTABLE-SIZE makes no difference, I
think it would be an improvement, merely for documentation purposes.  Now
everything makes sense: if you don't ask for any special features in your
arrays, you get simple ones, which is consistent with the behavior of the
sequence functions returning simple arrays always.  And if some
implementation decides they need the sequence functions to return
non-simple arrays, they can always add additional keywords to them to so
specify.  The only time you need to know about the word "simple" at all is
if you are making type declarations for efficiency, in which case you have
to decide whether to declare something to be a STRING or a SIMPLE-STRING.
And it makes sense that the more restrictive declaration be a longer word.
This also meets RPG's objection, which I think boils down to the fact
that he thought it was stupid to have :SIMPLE T all over his programs.
He was right.

I'm fairly sure that I don't understand the portability issues that KMP
brought up (I don't have a whole lot of time to devote to this).  But I
think that in my proposal STRINGP and SIMPLE-STRINGP are never the same
in any implementation; for instance, in the Lisp machine STRINGP is true
of all strings, while SIMPLE-STRINGP is only true of those that do not
have fill-pointers.  If we want to legislate that the :ADJUSTABLE-SIZE
option is guaranteed to turn off SIMPLE-STRINGP, I expect I can dig up
a bit somewhere to remember the value of the option.  This would in fact
mean that simple-ness is a completely implementation-independent concept,
and the only implementation-dependence is how much (if any) efficiency
you gain by using it, and how much of that efficiency you get for free
and how much you get only if you make declarations.

Perhaps the last sentence isn't obvious to everyone.  On the LM-2 Lisp
machine, a simple string is faster than a non-simple string for many
operations.  This speed-up happens regardless of declarations; it is a
result of a run-time dispatch to either fast microcode or slow microcode.
On the VAX with a dumb compiler and no tuning, a simple string is only
faster if you make declarations.  On the VAX with a dumb compiler but some
obvious tuning of sequence and string primitives to move type checks out of
inner loops (making multiple copies of the inner loop), simple strings are
faster for these operations, but still slow for AREF unless you make a type
declaration.  On the VAX with a medium-smart compiler that does the same
sort of tuning on user functions, simple strings are faster for user
functions, too, if you only declare (OPTIMIZE SPEED) [assuming that the
compiler prefers space over speed by default, which is the right choice in
most implementations], and save space as well as time if you go whole hog
and make a type declaration.  On the 3600 Lisp machine, you have sort of a
combination of the first case and the last case.

I also support the #* syntax for bit vectors, rather than the #" syntax.
It's probably mere temporal accident that the simple switch proposal
uses #" while the RPG memorial proposal uses #*.

To sum up:

A vector is a 1-dimensional array.  It prints as #(foo bar) or #<array...>
depending on the value of a switch.

A string is a vector of characters.  It always prints as "foo".  Unlike
all other arrays, strings self-evaluate and are compared by EQUAL.

A bit-vector is a vector of bits.  It always prints as #*101.  Since as
far as I can tell these are redundant with integers, perhaps like integers
they should self-evaluate and be compared by EQUAL.  I don't care.

A simple-vector, simple-string, or simple-bit-vector is one of the above
with none of the following MAKE-ARRAY (or MAKE-STRING) options specified:

	:FILL-POINTER
	:ADJUSTABLE-SIZE
	:DISPLACED-TO
	:LEADER-LENGTH, :LEADER-LIST (in implementations that offer them)

There are type names and predicates for the three simple array types.  In
some implementations using the type declaration gets you more efficient
code that only works for that simple type, which is why these are in the
language at all.  There are no user-visible distinctions associated with
simpleness other than those implied by the absence of the above MAKE-ARRAY
options.
----------------------------------------------------------------

22.  Shall the following proposal for the OPTIMIZE declaration be adopted?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Wednesday, 15 September 1982  20:51-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>

At the meeting I volunteered to produce a new proposal for the OPTIMIZE
declaration.  Actually, I sent out such a proposal a couple of weeks
ago, but somehow it got lost before reaching SU-AI -- both that machine
and CMUC have been pretty flaky lately.  I did not realize that the rest
of you had not seen this proposal until a couple of days ago.
Naturally, this is the one thing I did not keep a copy of, so here is my
reconstruction.  I should say that this proposal is pretty ugly, but it
is the best that I've been able to come up with.  If anyone out there
can do better, feel free.

Guy originally proposed a format like (DECLARE (OPTIMIZE q1 q2 q3)),
where each of the q's is a quality from the set {SIZE, SPEED, SAFETY}.
(He later suggested to me that COMPILATION-SPEED would be a useful
fourth quality.)  The ordering of the qualities tells the system which
to optimize for.  The obvious problem is that you sometimes want to go
for, say, SPEED above all else, but usually you want some level of
compromise.  There is no way in this scheme to specify how strongly the
system should favor one quality over another.  We don't need a lot of
gradations for most compilers, but the simple ordering is not expressive
enough.

One possibility is to simply reserve the OPTIMIZE declaration for the
various implementations, but not to specify what is done with it.  Then
the implementor could specify in the red pages whatever declaration
scheme his compiler wants to follow.  Unfortunately, this means that
such declarations would be of no use when the code is ported to another
Common Lisp, and users would have no portable way to flag that some
function is an inner loop and should be super-fast, or whatever.  The
proposal below tries to provide a crude but adequate optimization
declaration for portable code, while still making it possible for users
to fine-tune the compiler's actions for particular implementations.

What I propose is (DECLARE (OPTIMIZE (qual1 value1) (qual2 value2) ...),
where the qualities are the four mentioned above and each is paired with
a value from 0 to 3 inclusive.  The ordering of the clauses doesn't
matter, and any quality not specified gets a default value of 1.  The
intent is that {1, 1, 1, 1} would be the compiler's normal default --
whatever set of compromises the implementor believes is appropriate for
his user community.  A setting of 0 for some value is an indication that
the associated quality is unimportant in this context and may be
discrimintaed against freely.  A setting of 2 indicates that the quality
should be favored more than normal, and a setting of 3 means to go all
out to favor that quality.  Only one quality should be raised above 1 at
any one time.

The above specification scheme is crude, but sufficiently expressive for
most needs in portable code.  A compiler implementor will have specific
decisions to make -- whether to suppress inline expansions, whether to
type-check the arguments to CAR and CDR, whether to check for overflow
on arithmetic declared to be FIXNUM, whether to run the peephole
optimizer, etc. -- and it is up to him to decide how to tie these
decisions to the above values so as to match the users expressed wishes.
These decision criteria should be spelled out in that implementation's red
pages.  For example, it might be the case that the peephole optimizer is
not run if COMPILER-SPEED > 1, that type checking for the argument to
CAR and CDR is suppressed if SPEED > SAFETY+1, etc.
----------------------------------------------------------------

23.  Shall it be permitted for macros calls to expand into DECLARE forms
and then be recognized as valid declarations?  For example:
(DEFMACRO CUBOIDS (&REST VARS)
  `(DECLARE (TYPE (ARRAY SHORT-FLONUM 3) ,@VARS)
	    (SPECIAL ,@VARS)
	    (OPTIMIZE SPEED)
	    (INLINE HACK-CUBOIDS)))
(DEFUN CUBOID-EXPERT (A B C D)
  (CUBOIDS A C)
  ...)
This would not allows macros calls *within* a DECLARE form, only allow
macros to expand into a DECLARE form.
	(y) yes   (n) no

24.  Shall there be printer control variables ARRAY-PRINLEVEL and
ARRAY-PRINLENGTH to control printing of arrays?  These would not
limit the printing of strings.
	(y) yes   (n) no

25.  Shall lambda macros, as described below, be incorporated into
the language, and if so, shall they occupy the function name space
or a separate name space?
	(f) function name space   (s) separate name space   (n) no lambda macros
----------------------------------------------------------------
Date: Wednesday, 22 September 1982, 02:27-EDT
From: Howard I. Cannon <HIC at SCRC-TENEX at MIT-MC>

This is the documentation I wrote for lambda-macros as I implemented
them on the Lisp Machine.  Please consider this a proposed definition.

Lambda macros may appear in functions where LAMBDA would have previously
appeared.  When the compiler or interpreter detects a function whose CAR
is a lambda macro, they "expand" the macro in much the same way that
ordinary Lisp macros are expanded -- the lambda macro is called with the
function as its argument, and is expected to return another function as
its value.  Lambda macros may be accessed with the (ε3:lambda-macroε*
ε2nameε*) function specifier.

defspec lambda-macro function-spec lambda-list &body body
Analagously with ε3macroε*, defines a lambda macro to be called
ε2function-specε*. ε2lambda-listε* should consist of one variable, which
will be the function that caused the lambda macro to be called.  The
lambda macro must return a function.  For example:

lisp
(lambda-macro ilisp (x)
  `(lambda (&optional ,@(second x) &rest ignore) . ,(cddr x)))
end←lisp

would define a lambda macro called ε3ilispε* which would cause the
function to accept arguments like a standard Interlisp function -- all
arguments are optional, and extra arguments are ignored.  A typical call
would be:

lisp
(fun-with-functional-arg #'(ilisp (x y z) (list x y z)))
end←lisp

Then, any calls to the functional argument that
ε3fun-with-functional-argε* executes will pass arguments as if the
number of arguments did not matter.
end←defspec

defspec deflambda-macro
ε3deflambda-macroε* is like ε3defmacroε*, but defines a lambda macro
instead of a normal macro.
end←defspec

defspec deflambda-macro-displace
ε3deflambda-macro-displaceε* is like ε3defmacro-displaceε*, but defines
a lambda macro instead of a normal macro.
end←defspec

defspec deffunction function-spec lambda-macro-name lambda-list &body body 
ε3deffunctionε* defines a function with an arbitrary lambda macro
instead of ε3lambdaε*.  It takes arguments like ε3defunε*, expect that
the argument immediatly following the function specifier is the name of
the lambda macro to be used.  ε3deffunctionε* expands the lambda macro
immediatly, so the lambda macro must have been previously defined.

For example:

lisp
(deffunction some-interlisp-like-function ilisp (x y z)
  (list x y z))
end←lisp

would define a function called ε3some-interlisp-like-functionε*, that
would use the lambda macro called ε3ilispε*.  Thus, the function would
do no number of arguments checking.
end←defspec
----------------------------------------------------------------

26.  Shall the floating-point manipulations described below be adopted?
	(y) as described by MOON
	(a) as amended (FLOAT-SIGN changed) by GLS
	(n) do not adopt them
----------------------------------------------------------------
Date: Thursday, 30 September 1982  05:55-EDT
From: MOON at SCRC-TENEX

I am not completely happy with the FLOAT-FRACTION, FLOAT-EXPONENT, and
SCALE-FLOAT functions in the Colander edition.  At the meeting in August I
was assigned to make a proposal.  I am slow.

A minor issue is that the range of FLOAT-FRACTION fails to include zero (of
course it has to), and is inclusive at both ends, which means that there
are two possible return values for some numbers.  I guess that this ugliness
has to stay because some implementations require this freedom for hardware
reasons, and it doesn't make a big difference from a numerical analysis point
of view.  My proposal is to include zero in the range and to add a note about
two possible values for numbers that are an exact power of the base.

A more major issue is that some applications that break down a flonum into
a fraction and an exponent, or assemble a flonum from a fraction and an
exponent, are best served by representing the fraction as a flonum, while
others are best served by representing it as an integer.  An example of
the former is a numerical routine that scales its argument into a certain
range.  An example of the latter is a printing routine that must do exact
integer arithmetic on the fraction.

In the agenda for the August meeting it was also proposed that there be
a function to return the precision of the representation of a given flonum
(presumably in bits); this would be in addition to the "epsilon" constants
described on page 143 of the Colander.

A goal of all this is to make it possible to write portable numeric functions,
such as the trigonometric functions and my debugged version of Steele's
totally accurate floating-point number printer.  These would be portable
to all implementations but perhaps not as efficient as hand-crafted routines
that avoided bignum arithmetic, used special machine instructions, avoided
computing to more precision than the machine really has, etc.

Proposal:

SCALE-FLOAT x e -> y

  y = (* x (expt 2.0 e)) and is a float of the same type as x.
  SCALE-FLOAT is more efficient than exponentiating and multiplying, and
  also cannot overflow or underflow unless the final result (y) cannot
  be represented.

  x is also allowed to be a rational, in which case y is of the default
  type (same as the FLOAT function).

  [x being allowed to be a rational can be removed if anyone objects.  But
   note that this function has to be generic across the different float types
   in any case, so it might as well be generic across all number types.]

UNSCALE-FLOAT y -> x e
  The first value, x, is a float of the same type as y.  The second value, e,
  is an integer such that (= y (* x (expt 2.0 e))).

  The magnitude of x is zero or between 1/b and 1 inclusive, where b is the
  radix of the representation: 2 on most machines, but examples of 8 and
  16, and I think 4, exist.  x has the same sign as y.

  It is an error if y is a rational rather than a float, or if y is an
  infinity.  (Leave infinity out of the Common Lisp manual, though).
  It is not an error if y is zero.

FLOAT-MANTISSA x -> f
FLOAT-EXPONENT x -> e
FLOAT-SIGN x -> s
FLOAT-PRECISION x -> p
  f is a non-negative integer, e is an integer, s is 1 or 0.
  (= x (* (SCALE-FLOAT (FLOAT f x) e) (IF (ZEROP S) 1 -1))) is true.
  It is up to the implementation whether f is the smallest possible integer
  (zeros on the right are removed and e is increased), or f is an integer with
  as many bits as the precision of the representation of x, or perhaps a "few"
  more.  The only thing guaranteed about f is that it is non-negative and
  the above equality is true.

  f is non-negative to avoid problems with minus zero.  s is 1 for minus zero
  even though MINUSP is not true of minus zero (otherwise the FLOAT-SIGN function
  would be redundant).

  p is an integer, the number of bits of precision in x.  This is a constant
  for each flonum representation type (except perhaps for variable-precision
  "bigfloats").

  [I am amenable to converting these four functions into one function that
  returns four values if anyone can come up with a name.  EXPLODE-FLOAT is
  the best so far, and it's not very good, especially since the traditional
  EXPLODE function has been flushed from Common Lisp.  Perhaps DECODE-FLOAT.]

  [I am amenable to adding a function that takes f, e, and s as arguments
   and returns x.  It might be called ENCODE-FLOAT or MAKE-FLOAT.  It ought to
   take either a type argument or an optional fourth argument, the way FLOAT
   takes an optional second argument, which is an example of the type to return.]

FTRUNC x -> fp ip
  The FTRUNC function as it is already defined provides the fraction-part and
  integer-part operations.

These functions exist now in the Lisp machines, with different names and slightly
different semantics in some cases.  They are very easy to write.

Comments?  Suggestions for names?

Date:  4 October 1982 2355-EDT (Monday)
From: Guy.Steele at CMU-10A

I support Moon's proposal, but would like to suggest that FLOAT-SIGN
be modified to
	(FLOAT-SIGN x &optional (y (float 1 x)))
	returns z such that x and z have same sign and (= (abs y) (abs z)).
In this way (FLOAT-SIGN x) returns 1.0 or -1.0 of the same format as x,
and FLOAT-SIGN of two arguments is what the IEEE proposal calls COPYSIGN,
a useful function indeed in numerical code.
--Guy
----------------------------------------------------------------

27.  Shall DEFMACRO, DEFSTRUCT, and other defining forms also be
allowed to take documentation strings as possible and appropriate?
	(y) yes   (n) no

28.  Shall the following proposed revision of OPEN keywords be accepted?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Monday, 4 October 1982, 17:08-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>

OPEN takes a filename as its first argument.  The rest of its arguments
are keyword/value pairs.

WITH-OPEN-STREAM's first subform is a list of a variable (to be bound to
a stream), a filename, and the rest of the elements are keyword/value
pairs.

The keywords are as follows, with their possible values and defaults:

:DIRECTION	:INPUT (the default), :OUTPUT, :APPEND, :OVERWRITE, :PROBE
	:INPUT - The file is expected to exist.  Output operations are not allowed.
	:OUTPUT - The file is expected to not exist.  A new file is created.  Input
			operations are not allowed.
	:APPEND - The file is expected to exist.  Input operations are not allowed.
			New characters are appened to the end of the existing file.
	:OVERWRITE - The file is expected to exist.  All operations are allowed.
			The "file pointer" starts at the beginning of the file.
	:PROBE - The file may or may not exist.  Neither input nor output operations
			are allowed.  Furthermore, it is not necessary to close the stream.

:CHARACTERS	T (the default), NIL, :DEFAULT
	T - Open the file for reading/writing of characters.
	NIL - Open the file for reading/writing of bytes (non-negative integers).
	:DEFAULT - Let the file system decide, based on the file it finds.

:BYTE-SIZE	a fixnum or :DEFAULT (the default)
	a fixnum - Use this byte size.
	:DEFAULT - Let the file system decide, based on the file it finds.

:IF-EXISTS	:ERROR (the default), :NEW-VERSION, :RENAME,
		:RENAME-AND-DELETE, :OVERWRITE, :APPEND, :REPLACE
	Ignored if direction is not :OUTPUT.  This tells what to do if the file
	that you're trying to create already exists.
	:ERROR - Signal an error.
	:NEW-VERSION - Create a file with the same filename except with "latest" version.
	:RENAME - Rename the existing file to something else and proceed.
	:RENAME-AND-DELETE - Rename the existing file and delete (but don't expunge,
		if your system has undeletion) it, and proceed.
	:OVERWRITE - Open for :OVERWRITE instead.  (If your file system doesn't have
		this, use :RENAME-AND-DELETE if you have undeletion and :RENAME otherwise.)
	:APPEND - Open for :APPEND instead.
	:REPLACE - Replace the existing file, deleting it when the stream is closed.

:IF-DOES-NOT-EXIST	:ERROR (the default), :CREATE
	Ignored if direction is neither :APPEND nor :OVERWRITE
	:ERROR - Signal an error.
	:CREATE - Create the file and proceed.


Notes:

I renamed :READ-ALTER to :OVERWRITE; :READ-WRITE might also be good.

The :DEFAULT values are very useful, although some systems cannot figure
out this information.  :CHARACTERS :DEFAULT is especially useful for
LOAD.  Having the byte size come from the file only when the option is
missing, as the latest Common Lisp manual says, is undesirable because
it makes things harder for programs that are passing the value of that
keyword argument as computed from an expression.

Example of OPEN:
     (OPEN "f:>dlw>lispm.init" :DIRECTION :OUTPUT)

Example of WITH-OPEN-FILE:
     (WITH-OPEN-FILE (STREAM "f:>dlw>lispm.init" :DIRECTION :OUTPUT) ...)

OPEN can be kept Maclisp compatible by recognizing whether the second
argument is a list or not.  Lisp Machine Lisp does this for the benefit
of old programs.  The new syntax cannot be mistaken for the old one.

I removed :ECHO because we got rid of MAKE-ECHO-STREAM at the last
meeting.

Other options that the Lisp Machine will probably have, and which might
be candidates for Common Lisp, are: :INHIBIT-LINKS, :DELETED,
:PRESERVE-DATES, and :ESTIMATED-SIZE.
----------------------------------------------------------------
-------

∂05-Oct-82  0533	ZVONA at MIT-MC 	/BALLOT/
Date: Tuesday, 5 October 1982  08:32-EDT
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Guy.STEELE at CMU-20C
Cc:   b.steele at CMU-10A, common-lisp at SU-AI
Subject: /BALLOT/

~xxxxxnxxxxxxxxxxxxxxxxxxxxxx

Explanation:  

Dick Waters' LetS, which he will release imminently, is far superior
to LOOP.  Unlike LOOP, which is basically a hack, it is based on a
strong theory of what loops really are and what their structure is.
Basically it is a compiler which takes code written in terms of
streams and compiles it into efficient iterative code.

I'm not involved in common lisp.  I probably don't get a vote, but
this is one I really care about.
-------

∂05-Oct-82  1002	Guy.Steele at CMU-10A 	Addendum to voting procedure    
Date:  5 October 1982 1257-EDT (Tuesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Addendum to voting procedure

I forgot to provide a way to indicate "no vote" on a question.
Use "-" for this purpose.  So a response might look like:

~ xabyb n-xxb arn-- --ax- xxa-- -x-

Second, I want to emphasize again that this ballot, as with all
previous ballots, is not necessarily a majority-rules vote,
but an attempt to determine for each question whether there is
a general consensus or not.  If there is consensus, I take that
as a mandate to edit the document accordingly; if not, the
question remains open for discussion.
--Guy

∂05-Oct-82  1517	Scott E. Fahlman <Fahlman at Cmu-20c> 	/BALLOT/   
Date: Tuesday, 5 October 1982  18:16-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   steele at CMU-20C
Cc:   common-lisp at SU-AI
Subject: /BALLOT/


~ b n n y y n y y y y y y n y y y y a i y m y y n n a y y
  1 3 1 - 3 * 1 2 - 1 * 2 2 2 1 2 2 * 3 2 2 - 1 1 * 1 2 -  Intensity
  1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8  Issue #

I have included an indication of how much I care about each issue in a
way that I hope will not choke Guy's voting machine.  1 means that I
will happily abide by the will of the majority; 2 means that I have a
definite preference; 3 means that this issue is very important to me; 4
means that this is a non-negotiable issue.  (There are no 4's here.)
- means that there is no other choice presented, and the one that is
presented seems OK.  A * means "see below".  The numbers on the third line
are just index numbers so that I can see what I'm doing.

6: I am in favor of adding the LOOP package as described (once it is
completed) to the language as a portable yellow pages module.  I feel
rather strongly that it is premature to add LOOP to the white pages.

11: Whatever is done about global vars, global constants should be the
same.  I oppose option 3 or any plan to make them look syntactically
different.

18. I now believe that RESTART is more trouble than it is worth.  I am
strongly opposed to any plan, such as option 3, that would add a RESTART
form but make it impossible to use this with the implicit block around a
DEFUN.  If you have to introduce a RESTARTABLE block, you may as
well use PROG/GO.

25: I seem to be unable to locate any explanation of why Lambda macros
are useful enough to be worth the bother.  Looks like needless hair to
me, but I seem to dimly recall some arguments for why they were needed.
I'm not passionately opposed, but every page full of hairy stuff in the
manual hurts us.

∂05-Oct-82  1532	Dave Dyer       <DDYER at USC-ISIB> 	comment on lambda macros    
Date:  5 Oct 1982 1530-PDT
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: comment on lambda macros
To: Fahlman at CMU-20C
cc: common-lisp at SU-AI
In-Reply-To: Your message of Tuesday, 5 October 1982  18:16-EDT


 LAMBDA macros in zetalisp were borrowed from Interlisp to make it
possible to extend lambda-expression syntax to accomodate Interlisp
semantics.  In general, LAMBDA macros allow an arbitrary translation
step before application of a function. Very useful for embedded languages.
There is no hair, just a few simple taps before errors are declared.
-------

∂05-Oct-82  1552	Earl A. Killian <EAK at MIT-MC> 	defun semantics  
Date: 5 October 1982 18:51-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject: defun semantics
To: common-lisp at SU-AI

Does defun add the function name to the lexical environment of
the body?  Should it?

For example, in

(defun revappend (a b)
  (if (null a)
      b
      (revappend (cdr a) (cons (car a) b))))

is the tail recursion implementable as a simple GO, or must the
system consult the function cell of the symbol REVAPPEND?  I vote
for allowing the GO, i.e. adding REVAPPEND to the lexical
function environment, in effect, defining DEFUN in terms of
LABELS instead of LAMBDA.

∂05-Oct-82  1612	Brian G. Milnes <Milnes at CMU-20C> 	/BALLOT/
Date: Tuesday, 5 October 1982  19:11-EDT
From: Brian G. Milnes <Milnes at CMU-20C>
To:   STEELE at CMU-20C
Cc:   b.steele at CMU-10A, common-lisp at SU-AI
Subject: /BALLOT/

 12345678912345678912345678
~ayxyyynyynnyyxyxxiymyysyyx

	

∂05-Oct-82  1625	Earl A. Killian <EAK at MIT-MC> 	arrays 
Date: 5 October 1982 19:24-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject: arrays
To: common-lisp at SU-AI

Suggestion: Now that :TYPE to MAKE-ARRAY is :ELEMENT-TYPE,
shouldn't ARRAY-TYPE be ARRAY-ELEMENT-TYPE?  Or perhaps just
ELEMENT-TYPE, in which case it would work for any sequence?  Not
clear that the concept is very useful for generalized sequences
(e.g. ELEMENT-TYPE of a cons would always be T), though it might
find some use in writing new sequence functions.

Question 1: was ARRAY-RESET-FILL-POINTER eliminated by the decision
at the last meeting to use SETF exclusively?  I.e. is it subsumed
by (SETF (ARRAY-ACTIVE-LENGTH A) L)?

Question 2: I'm not sure what resulted from the displaced array
discussion.  My memory tells me that every proposed use of
displaced arrays was countered with an appropriate access
function.  Has anyone a proposed set of new access functions?
Or are even these deemed unnecessary?

∂05-Oct-82  1927	Alan Bawden <ALAN at MIT-MC> 	ZVONA: ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx    
Date: 5 October 1982 22:18-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  ZVONA: ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx
To: ZVONA at MIT-MC
cc: common-lisp at SU-AI

    Date: Tuesday, 5 October 1982  08:32-EDT
    From: ZVONA

    ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx

    Explanation:  

    Dick Waters' LetS, which he will release imminently, is far superior
    to LOOP.  Unlike LOOP, which is basically a hack, it is based on a
    strong theory of what loops really are and what their structure is.
    Basically it is a compiler which takes code written in terms of
    streams and compiles it into efficient iterative code.

Well I think we should flush DO from Common Lisp because in spite of its
utility, it is not "based on a strong theory of what loops really are".

Seriously, I doubt very much that LetS will totally replace LOOP among the
tools I use any more than LOOP replaced DO.  I am sick to death of knee-jerk
anti-LOOPism and I am beginning to irrationally regard it as a plot to disable
me as a programmer by excommunicating my most useful tools.

∂05-Oct-82  2032	Masinter at PARC-MAXC 	Re: keyword pairs and OPEN 
Date:  5-Oct-82 20:31:36 PDT (Tuesday)
From: Masinter at PARC-MAXC
Subject: Re: keyword pairs and OPEN
In-reply-to: dlw at SCRC-TENEX's message of Monday, 4 October 1982, 17:08-EDT
To: common-lisp at SU-AI

Is the :DIRECTION :PROBE a proper function of "OPEN"? It seems semantically
quite different; e.g., :BYTE-SIZE, :CHARACTERS etc seem pretty meaningless.
Tenex/Tops-20 allows for  "give me name of new file"; is that generally useful?

Interlisp separates out the "direction" (ACCESS method) from the "recognition mode" in its OPENFILE. (The Interlisp VM is the best description of OPENFILE). Thus,
an alternative to consider would have key words:

:ACCESS	 - one of :INPUT, :OUTPUT, :APPEND (or ...)
	no default

:RECOG - one of :OLD, :NEW, :OLD/NEW (or ...)
	default depends on :ACCESS

:TYPE - one of :TEXT or :BINARY or :DEFAULT (or ...)
	(default :TEXT)

:BYTE-SIZE (only meaningful and implies :TYPE :BINARY)

I'd then fold in the :IF-EXISTS and :IF-DOES-NOT-EXIST with different
recognition modes.

What most people then want is some notion of a search-path algorithm on
recognition mode :INPUT. This sometimes takes the form of hacking with
the name which is supplied, which perhaps Common Lisp should avoid.



∂05-Oct-82  2317	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	arrays   
Date: Wednesday, 6 October 1982, 01:55-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: arrays
To: common-lisp at SU-AI
In-reply-to: The message of 5 Oct 82 19:24-EDT from Earl A. Killian <EAK at MIT-MC>

    Date: 5 October 1982 19:24-EDT
    From: Earl A. Killian <EAK at MIT-MC>

    Suggestion: Now that :TYPE to MAKE-ARRAY is :ELEMENT-TYPE,
    shouldn't ARRAY-TYPE be ARRAY-ELEMENT-TYPE?  
Yes, definitely.						 
						 Or perhaps just
    ELEMENT-TYPE, in which case it would work for any sequence?  Not
    clear that the concept is very useful for generalized sequences
    (e.g. ELEMENT-TYPE of a cons would always be T), though it might
    find some use in writing new sequence functions.
Probably this is too random, although I wouldn't mind it.

    Question 1: was ARRAY-RESET-FILL-POINTER eliminated by the decision
    at the last meeting to use SETF exclusively?  I.e. is it subsumed
    by (SETF (ARRAY-ACTIVE-LENGTH A) L)?
(SETF (FILL-POINTER surely.

∂06-Oct-82  0106	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN   
Date: Wednesday, 6 October 1982, 04:03-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Re: keyword pairs and OPEN
To: common-lisp at SU-AI
In-reply-to: The message of 5 Oct 82 23:31-EDT from Masinter at PARC-MAXC

    Date:  5-Oct-82 20:31:36 PDT (Tuesday)
    From: Masinter at PARC-MAXC

    Is the :DIRECTION :PROBE a proper function of "OPEN"? It seems semantically
    quite different; e.g., :BYTE-SIZE, :CHARACTERS etc seem pretty meaningless.
Well, this is a debatable point.  In terms of message passing, a probe stream
has about half the messages that a real-open stream does, and doesn't have any
messages that a real-open stream does not have.  These messages are operations
such as getting and setting attributes of the file.  So you it's reasonable to
think of probing as a subset of opening, or as a separate function.  The Lisp
machine happened to choose the former.
    
    Tenex/Tops-20 allows for  "give me name of new file"; is that generally useful?
Without actually creating it, how could it be?  If someone else does the same
thing they'll get the same name.  If it does actually create it, is this different
in any way from opening in OUTPUT direction?

    Interlisp separates out the "direction" (ACCESS method) from the
    "recognition mode" in its OPENFILE. (The Interlisp VM is the best
    description of OPENFILE). Thus, an alternative to consider would have
    key words:

    :ACCESS	 - one of :INPUT, :OUTPUT, :APPEND (or ...)
	    no default

    :RECOG - one of :OLD, :NEW, :OLD/NEW (or ...)
	    default depends on :ACCESS

This is just the way it works now in the Lisp machine, and it proved to be
totally hard to understand and use.  Having separate keywords for if-exists
and if-does-not-exist was a good idea on Dan's part, in my opinion.

    :TYPE - one of :TEXT or :BINARY or :DEFAULT (or ...)
	    (default :TEXT)

    :BYTE-SIZE (only meaningful and implies :TYPE :BINARY)

    I'd then fold in the :IF-EXISTS and :IF-DOES-NOT-EXIST with different
    recognition modes.

    What most people then want is some notion of a search-path algorithm on
    recognition mode :INPUT. This sometimes takes the form of hacking with
    the name which is supplied, which perhaps Common Lisp should avoid.

If you mean recognition in the sense of filename completion, that CERTAINLY
does not belong as part of OPEN.  It should be a separate function, but
probably Common Lisp is not prepared to standardize things like this yet.
However, I may not have understood your last paragraph.

∂06-Oct-82  0126	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	GLS's change to Moon's floating-point extractors proposal  
Date: Wednesday, 6 October 1982, 04:19-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: GLS's change to Moon's floating-point extractors proposal
To: common-lisp at SU-AI
In-reply-to: The message of 4 Oct 82 23:55-EDT from Guy.Steele at CMU-10A

    Date:  4 October 1982 2355-EDT (Monday)
    From: Guy.Steele at CMU-10A

    I support Moon's proposal, but would like to suggest that FLOAT-SIGN
    be modified to
	    (FLOAT-SIGN x &optional (y (float 1 x)))
	    returns z such that x and z have same sign and (= (abs y) (abs z)).
    In this way (FLOAT-SIGN x) returns 1.0 or -1.0 of the same format as x,
    and FLOAT-SIGN of two arguments is what the IEEE proposal calls COPYSIGN,
    a useful function indeed in numerical code.

This is the SIGNUM function, which already exists on page 125 of the Colander.
If my memory of the past 2 months' discussion is accurate, it was extended
to the 2-argument case; the Colander only allows one argument.

FLOAT-SIGN was intended to be something else, and would return 0 or 1 rather
than 1.0 or -1.0.  Perhaps FLOAT-SIGN is redundant given the existence of
SIGNUM.  There is only one problem with this, which I think I pointed out in
my message: the minus zero in the proposed IEEE standard.  I'm sure that
SIGNUM of this has to be -0.0 rather than -1.0 (although possibly it has
to be +0.0).  And MINUSP of -0.0 has to be NIL.  Furthermore the standard
specially specifies that (= -0.0 0.0) => T.  So if you're writing a portable
floating point number printer, you need some way to know to print a minus
sign for minus zero.  If EQ worked on numbers you could use it.

∂06-Oct-82  0708	Guy.Steele at CMU-10A 	Re: defun semantics   
Date:  6 October 1982 1007-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: Earl A. Killian <EAK at MIT-MC>
Subject: Re: defun semantics
CC: common-lisp at SU-AI
In-Reply-To: Earl A. Killian's message of 5 Oct 82 17:51-EST

Defining DEFUN to make self-recursive calls not go through the function
cell would making TRACE much less useful on recursive functions.
--Guy

∂06-Oct-82  0732	Guy.Steele at CMU-10A 	FLOAT-SIGN and SIGNUM 
Date:  6 October 1982 1029-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: FLOAT-SIGN and SIGNUM

Extending FLOAT-SIGN to two arguments is useful for the same reasons
as extending SIGNUM (though I'm not sure we really voted for the latter).
The handling of -0.0 is the crux, as Moon points out.  I would assume that
	(SIGNUM 0.0) => 0.0		(FLOAT-SIGN 0.0) => 1.0
	(SIGNUM -0.0) => -0.0		(FLOAT-SIGN -0.0) => -1.0
	(SIGNUM 0.0 x) => 0.0		(FLOAT-SIGN 0.0 x) => |x|
	(SIGNUM -0.0 x) => -0.0		(FLOAT-SIGN -0.0 x) => -|x|
which are distinct useful behaviors, I think.
--Guy

∂06-Oct-82  1112	ZVONA at MIT-MC
Date: Wednesday, 6 October 1982  14:00-EDT
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   common-lisp at sail

I wasn't suggesting flushing LOOP, merely postponing its inclusion in
the white pages until people have had time to compare LetS.  I suspect
that almost every LOOP expression can be re-written more perspicuously
with LetS, but this may not be true; in which case both might be
supported, and people could use whichever is appropriate to a problem.
Or it might be decided that since a new iteration macro comes along
every once in a while, none should be set in concrete.

    Well I think we should flush DO from Common Lisp because in spite
    of its utility, it is not "based on a strong theory of what loops
    really are".
Well, if there were something that did more-or-less the same things as
DO, but had a clearer theory of what is going on, wouldn't you
consider flushing DO in favor of it?  At least in your own code?

    Seriously, I doubt very much that LetS will totally replace LOOP
    among the tools I use any more than LOOP replaced DO.  I am sick
    to death of knee-jerk anti-LOOPism and I am beginning to
    irrationally regard it as a plot to disable me as a programmer by
    excommunicating my most useful tools.  

A knee-jerk anti-LOOPist is someone that says "LOOP is a crock" and
doesn't suggest an alternative.  I am not a knee-jerk anti-LOOPist.  I
would use it in preference to DO if that was all that was available.
But I would still rather use something better.  DO&, which I wrote,
had the advantage that the syntax was uniform and modeled on something
understood (DO), whereas LOOP's syntax is higgledy-piggledy and alien
to LISP.  LetS is better because its syntax is exactly that of PURE
LISP EXPRESSIONS.  Examples for flavor:

(defun copylist (list)
  (Rlist (Elist list)))

(defun sum-first-n-integers (n)
  (Rsum (Eint 1 n)))
-------

∂06-Oct-82  1222	Dave Dyer       <DDYER at USC-ISIB> 	votes   
Date:  6 Oct 1982 1222-PDT
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: votes
To: common-lisp at SU-AI


~b n x y x y y y y n n y n x y y y a x x - y y y s - y y 
 0                 1                   2
 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
-------

∂06-Oct-82  1225	Kent M. Pitman <KMP at MIT-MC> 	insults 
Date: 6 October 1982 15:24-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject: insults
To: zvona at MIT-OZ, common-lisp at SU-AI

it seems to me that expressions like "knee-jerk anti-LOOPist" are highly
unprofessional and have no place in this discussion. they only serve to
divide people into two camps and do very little good. in discussions like
these, where people have taken very strong stands on things, one would
sometimes like a person to ber able to to accept others' views and change
"sides" rapidly. if one "side" or the other is marked by having been called
names, it can only serve to weaken the ability of that person to correctly make
the technically right decision because s/he has to worry about a host
of personal issues that never should have been involved: will i be branded
a LOOPist? will the <x> community no longer like me or listen to my ideas?...

ALAN's remark about the "knee-jerk anti-LOOPist" does worse than imply
that the person condemns LOOP without supplying an alternative, it suggests
that some people obejct to LOOP as a reflex action and implicit in that is
that they do not use their higher brain functions in the decision. It is,
in my estimation, possible to "correctly condemn" a primitive or feature 
without being able to propose an adequate alternative. Certainly it has
happened many times in Common-Lisp discussions.

i don't even mind the clear sarcasm/humor of ALAN's paranoia because no
one's likely to be hurt by that; it's not very pointed. but, please,
resist the urge to do name-calling. with the general level of passion the
individuals in this group have on particular issues, we just can't afford
to lose track of that we're working together, not against each other.

thanks,

∂06-Oct-82  1423	Kent M. Pitman <KMP at MIT-MC> 	defun semantics   
Date: 6 October 1982 17:21-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  defun semantics
To: EAK at MIT-MC, Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

Yet another thing to think about is the 
 (DEFUN FACT (X) (COND ... (T ... (FACT ...) ... )))
 (SETF #'FOO #'FACT)
 (SETF #'FACT #'BAR)
phenomenon. My suspicion is that very few people ever want the behavior where
the recursive call to FACT gets BAR's definition. It would be nice if functions
were more easily renamed in this way.

GLS is right that this thwarts TRACE in its current form, but perhaps a 
scheme can be found for making TRACE do the right thing. I have some ideas
which I'll talk to people about off this list and maybe suggest later when
they're better thought out. But if this could be worked out, I think having
definitions closed over their original name is a good idea.

∂06-Oct-82  1503	MOON at SCRC-TENEX 	suggestions on floating point numbers and hash tables  
Date: Wednesday, 6 October 1982  17:43-EDT
From: MOON at SCRC-TENEX
To:   common-lisp at SU-AI
Subject: suggestions on floating point numbers and hash tables
In-reply-to: The message of 5 Oct 1982 0030-EDT from HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

    Date:  5 Oct 1982 0030-EDT
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

    When you see 1.0, it is hard to know what the precision is. We would
    like to make sure that if you write something out and read it back in,
    it is EQUAL to what you started with.  Thus you should consider doing
    one of the following:

      - adopt a convention where you can tell the precision based on the
    	number of digits printed.  E.g. 1.00000 would be single, but
    	1.000000000000000 would be double.
This obnoxes me.

      - always print an exponent marker, or maybe always print it when the
    	it is not the same as READ-DEFAULT-FLOAT-FORMAT.

    (At the moment, we are always supplying an exponent marker when it is
    different from the default.)
Printing an exponent marker if the format is not the default is the right
alternative, I think.  It also happens to be what the Lisp machine does now
(which doesn't matter since we're willing to do anything reasonable).

No matter what you do you can't solve the problem of trying to get the
same precision on a different machine.

    We do not notice any way to write out hash tables.  We suggest that you
    adopt a # syntax for that.  In my opinion, it should be possible to
    write out and read back in as many kinds of user data structures as is
    possible.
I certainly do not want to see hash tables vomited out at me on the terminal.
But I do agree that is reasonable to have a way to put a hash table in a file.
I don't think it is necessary to add a new # syntax; all that is necessary
is a new keyword argument to MAKE-HASH-TABLE that provides the initial
contents (as an alist or something).  #. can then be used to include a hash
table in other data structure being read (i.e. to put one in a place that
is not a form to be evaluated).

    You specify a default packing factor of .8 for hash tables. I wonder
    whether you really want this number to be defined in the manual.
You are absolutely right.  Common Lisp has no business standardizing this.

    Finally, we wonder whether having separate MAKE-xxx-HASH-TABLE functions
    but the same PUT-HASH and GET-HASH for all types is the right way to go.
I have complained about this before.  There should be one function named
MAKE-HASH-TABLE that takes keywords defining the type of hash table you
want, and one set of functions for accessing.  We (the Lisp machine) screwed
up by ever having multiple functions for different kinds of hash tables.

    Although I don't quite know how one would use it, in
    principle it would make sense to put different kinds of items into the
    same hash table using different functions.
Do you really mean this?  I don't see how it can possibly be meaningful.

∂06-Oct-82  1735	Masinter at PARC-MAXC 	Re: /BALLOT/
Date:  6-Oct-82 17:33:19 PDT (Wednesday)
From: Masinter at PARC-MAXC
Subject: Re: /BALLOT/
In-reply-to: STEELE's message of 5 Oct 1982 0041-EDT
To: Steele@cmu-20c
cc: common-lisp@su-ai 

~anyx-xy-yyyy--y-yaiy-nynd-yy
 1234567890123456789012345678

4) :ERROR, :SET-DEFAULT-PATHNAME options to LOAD should be rationalized with
OPEN; the handling here of search paths should logically be handled by passing
on some of the options from LOAD to OPEN rather than having LOAD do special
path-name processing. This is because users who manipulate files want to do
similar hacking, and the mechanism should be common. 

6) I feel strongly that the white pages SHOULD include a LOOP construct.
I care less about which one, but I like most of Moon's proposal better than DO
and what I saw of LetS. I'd get rid of AND and ELSE. I don't understand
if the "COLLECT" lexical scoping includes scoping under macro expansion.

9) this seems right but not quite fully specified, e.g. LAMBDA-MACRO 

25) spec here not consistent with MACROEXPAND proposal

∂06-Oct-82  1828	Scott E. Fahlman <Fahlman at Cmu-20c> 	suggestions on floating point numbers and hash tables   
Date: Wednesday, 6 October 1982  21:27-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: suggestions on floating point numbers and hash tables


I was about to comment on Hedrick's suggestions when Moon popped up and
said exactly what I was going to (except that I was going to be apalled
rather than obnoxed at the first suggestion).  So I second all of Moon's
comments on these items.

∂06-Oct-82  1919	Kent M. Pitman <KMP at MIT-MC> 	/BALLOT/
Date: 6 October 1982 22:18-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  /BALLOT/
To: Guy.Steele at CMU-10A
cc: Common-Lisp at SU-AI

          ~bnyxnnyyx yyyyy-yyci ymxyns-yx
Notes?      * * *  *      *       **  * * (see below)
Sequencing 123456789 0123456789 012345678

(2)  SETF -> SET. I think we should do this, but not at this time.
    
(4)  Load Keywords. I would vote YES except:
     As suggested by someone when it was proposed, any mention of packages
     should be stricken pending the release of a package system specification.
    
(5)  LOOP. As a yellow-pages extension is ok by me. I strongly oppose its
     placement in the white pages.
                 
(9)  MACROEXPAND. I would vote YES except:
     I am uncomfortable with saying that a form returns two
     values and then returning only one (letting the rest default to NIL).
     Does Common-Lisp specify anything on this? In any case, I would ammend
     the (cond ((and (pairp ...) ...) (values (...) t))
               (t form))
     to (cond (...) (t (values form nil))) to make it clear that two values
     are always returned. If this modification is made, I am happy with this
     proposal.

(15) I have no use for this but have no strong objection.

(22) OPTIMIZE. I would vote YES except:
     The use of numbers instead of keywords bothers me. The section saying
     which numbers can be which values and how those values will be interpreted
     seems to FORTRANesque to me. I think these values should be just keywords
     or the tight restrictions on their values should be lifted. The only use
     for numbers would be to allow users a fluid range of possibilities.

(23) DECLARE. I also support allowing multiple declare forms at the top of
     a bind form. ie,
         (LAMBDA (X Y) (DECLARE (SPECIAL X)) (DECLARE (SPECIAL Y))
     for ease in macros. Steele's proposed evaluator did this and it wasn't
     notably expensive.

(26) I haven't thought enough about floating point to comment usefully.

(28) OPEN keywords. I'm postponing judgment on this issue until the 
     currently active CL discussion on this issue subsides.

∂06-Oct-82  2238	Guy.Steele at CMU-10A 	Documentation and error messages
Date:  7 October 1982 0137-EDT (Thursday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Documentation and error messages

I am a bit concerned about a couple of issues relating to English prose
that the LISP spits out to one.  I am primarily concerned that messages
be of an appropriate length and level of detail for the situation.
(No, I am *not* about to propose variables MSGLEVEL and MSGLENGTH!
But something perhaps close to that.)

First, some people have recognized a need for both short and long
forms of documentation for functions, variables, and other things.
For APROPOS applications or a quick reminder, a line or a sentence
is sufficient, and you don't want APROPOS to belch 100 3-paragraph
descriptions at you instead of 100 lines.  On the other hand, for
DESCRIBE and so on, one wants to see a relatively detailed description.

Here is a quicky solution: in DEFUN, for example, let more than one
documentation string appear, in order of increasing detail, thus:
(DEFUN LENGTH (X)
  "Returns the length of the argument as an integer."
  "LENGTH accepts any sequence (a list or a one-dimensional array)
   and returns its length as a non-negative integer (in fact, as a
   fixnum).  If the argument is an array with a fill pointer, LENGTH
   returns the size of the active region of the array, not that of
   the total memory allocated for the array."
  (TYPECASE ...))

This solution is not great.

There is a similar problem with error messages, trying to strike a
balance between conciseness and helpfulness.  It would be better if
it were possible to signal an error with up to three different
messages: a short (one-line) error message, a longer discourse
explaining the nature of the error and possible likely causes,
and a description of how to recover from the error if it is
possible, particularly in the case of correctable errors.  For certain
software that I want to be useable by non-experts, I would be willing
to define a separate function for each possible error, just so that
I would feel free to write lots of helpful information about an
error condition.  Here's an example of what I have in mind:
(DEFUN UNBOUND-VARIABLE-ERROR (VAR)
  (HERROR ("~S unbound variable" VAR)
    ("The special variable ~S is currently unbound (has no value).
      Perhaps the variable ~S is supposed to have a value and does not,
      or perhaps the name of the correct variable was misspelled."
     VAR VAR)
    ("If you return a correction value, it should be the correct symbol
      naming the variable whose value should be used.  If ther name was
      correctly spelled, give that variable a value first and then return
      that name by typing ~:@C.  Otherwise, return the correct name for
      the variable." #\Hyper-Return)))

Maybe I've gone overboard here, but I want it to be possible to
provide a great amount of on-line help to the user so he doesn't
have to scurry to the manual.  On the other hand, the first thing you
see should be short and crisp, to avoid annoying knowledgeable users.

Comments?
--Guy

∂07-Oct-82  1017	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
Date: Thursday, 7 October 1982  13:16-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Documentation and error messages


Despite my earlier opposition to one-line documentation strings, I now
see the need for them.  I agree with Guy that we need short and medium
forms of built-in documentation for functions and short, medium, and
"return value" forms for errors.  These fit nicely into Moon's proposal
for documentation retrieval: in addition to having a DEFUN documentation
accessor, we would also have a SHORT-DEFUN.  (Actually, like many
others, I prefer FUNCTION and VARIABLE to DEFUN and DEFVAR, but that is
a separate issue.)

Guy's proposal for supplying these strings to the error forms sounds OK.
I worry about adding more hair to DEFUN.  Putting the doc string into
DEFUN is cute, and it has had the psychological effect of encouraging
people to use these strings, but it may be time to create a separate
documentation-defining form.  With enough good examples and social
pressure -- nothing gets into the yellow pages unless every user-visible
function and special variable is documented -- we would still get
compliance.

(document foo
  'short-function
"Short documentation for FOO goes here."
  'function
"Long documentation for FOO goes here and just to make this longer
I will include this useless extra clause."
  'algorithm
"Uses the bubbly-quick-foo algorithm, which is O(n log n).  See Knuth,
volume 5.  For small N, you are better off using BAR."
  'bugs
"With an argument of 0, destructively rewinds the disk.")

(defun foo ...)

We probably don't want to go for this many flavors of doc right now, but
it gives us some room to grow in the future.  Of course, for awhile we
would support embedded doc strings in DEFUN as a compatibility measure.
The embedded string would be FUNCTION (or DEFUN) documentation.

-- Scott

∂07-Oct-82  1622	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Documentation and error messages  
Date: Thursday, 7 October 1982, 19:19-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Documentation and error messages
To: common-lisp at SU-AI
In-reply-to: The message of 7 Oct 82 01:37-EDT from Guy.Steele at CMU-10A,
             The message of 7 Oct 82 13:16-EDT from Fahlman at Cmu-20c

    Date:  7 October 1982 0137-EDT (Thursday)
    From: Guy.Steele at CMU-10A

    First, some people have recognized a need for both short and long
    forms of documentation for functions, variables, and other things.

    Here is a quicky solution: in DEFUN, for example, let more than one
    documentation string appear, in order of increasing detail....
    This solution is not great.
No it's not.  But it would be acceptable.  I think I still prefer
special-casing the first line over this solution, even though it means that
the short documentation string really has to be short (to fit on a line).
The extra complexity doesn't seem to buy anything, and isn't enough
complexity to do anything really hairy.

    There is a similar problem with error messages, trying to strike a
    balance between conciseness and helpfulness....
Your suggested schemes for this fit much more nicely into the Lisp machine
"New error system" than into the bare Lisp you're trying to put them into.
Since Common Lisp is not prepared to adopt such a hairy error system right
now, I suggest that this issue be dropped until next year, rather than
trying to standardize on some kludge.  I certainly do not propose that it
be dropped forever.

    Date: Thursday, 7 October 1982  13:16-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    These fit nicely into Moon's proposal
    for documentation retrieval: in addition to having a DEFUN documentation
    accessor, we would also have a SHORT-DEFUN.
No!  No!  No!  Absolutely not.  That word "DEFUN" is telling you how to
interpret the name of the thing whose documentation you are retrieving;
it is the name of a "name space".  It is 100% wrong to multiply the number
of name spaces by the number of kinds of documentation you might want, and
have as many symbols for documentation as we used to have for sequence
functions.  The level of documentation you want should be a separate
argument to the DOCUMENTATION function.

    (Actually, like many
    others, I prefer FUNCTION and VARIABLE to DEFUN and DEFVAR, but that is
    a separate issue.)
In case I haven't stated my case on this before, I will again, and I'll try to
be crystal clear.  I agree with you.  FUNCTION is better than DEFUN, and
VARIABLE is better than DEFVAR.  The problem is that this does not generalize
well to the many other things you would like to document.  Many classes of
named thing that you can define do not have a name for the class, separate
from the name of the defining special form, except perhaps by deleting the
three letters "DEF" from the latter name.  Furthermore if you have names used
only for this, there is a serious problem with remembering abbreviations.  You
probably won't have much trouble remembering whether it's a VARIABLE or a VAR,
and might even be able to remember whether it's a STRUCTURE or a STRUCT, but
when there are 10 or 20 of these, you will not be able to remember two sets of
names for the same thing.  It's even worse when you put in packages.
Also, don't forget that this naming system necessarily has to be extensible to
user-defined classes of things.


This discussion worries me.  The problem is that it looks like we are getting
away from language design per se, and trying to design a standard user
interface.  Certainly you want some standardization there, on the simple
things that everybody understands and agrees on.  But the whole user interface
field can be an impenetrable morass.  There are issues of personal taste and
esthetics.  The ground rules for many user interface issues are dictated
entirely by implementation considerations, such as whether you support only
bitmap terminals, only fast displays, or all kinds of terminals.  Even worse,
they are dictated by what sort of users your system is intended for.  It can
be extremely difficult to come to any sort of agreement on this kind of thing,
because everyone has a different unstated set of assumptions (model in their
head) for what the discussion is about.

In any case I am certain that the Common Lisp working group, or whatever we
are called, is barely able to keep the language design orderly, and certainly
does not have the resources to design a user interface, too.


I feel quite strongly that we need to buckle down and finish the job of
getting a standard language defined, and not get diverted into a lot of
side-issues.  I want to start serious planning of how the Lisp machine system
is going to make the transition to Common Lisp, and there are still an
enormous number of loose ends as well as areas where the language has diverged
from the Colander edition of the manual, but has not yet reached a final
conclusion.  Once we have several actual, working Common Lisp implementations
and the ability to exchange code routinely, we will be in a much better
position to work constructively on user interfaces and other things at that
level.

∂07-Oct-82  1803	MIT VAX/VMS Lisp Implementors <NIL at MIT-ML> 	/BALLOT/
Date: 7 October 1982 21:05-EDT
From: MIT VAX/VMS Lisp Implementors <NIL at MIT-ML>
Subject:  /BALLOT/
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

~ b n y y - y y y y x x y n y y y y a i y m y y y s - y y
  1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8

(10)  I really like only ONE "*" at the beginning of the name.  I got
tired of shifting for two years ago, but conversely couldn't stand to
not have the specialness of the variable not be obvious.

(11)  Whatever we decide for 10.

∂07-Oct-82  1814	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
Date: Thursday, 7 October 1982  21:13-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Cc:   common-lisp at SU-AI
Subject: Documentation and error messages


    ... That word "DEFUN" is telling you how to
    interpret the name of the thing whose documentation you are retrieving;
    it is the name of a "name space".  It is 100% wrong to multiply the number
    of name spaces by the number of kinds of documentation you might want, and
    have as many symbols for documentation as we used to have for sequence
    functions.  The level of documentation you want should be a separate
    argument to the DOCUMENTATION function.

Well, I seem to have misunderstod Moon's proposal on this, but his
position seems rather doctrinaire.  The point, as I see it, is that
simply saying (documentation 'foo) might get you any of several things,
so another argument is required to specify what you really want.  I
don't think we'll end up with 600 of these.

I agree, however, that this whole documentation thing is getting too
hairy, and that for now we probably shouldn't try to put too many
user-environment things into the white pages.  In addition to Moon's
name spaces and this short/long business, we have the whole unresolved
business of reformatting doc strings.  Maybe we should forget the whole
thing.  All that the white pages really need to say is that DEFUN
optionally contains a string that is meant to be documentation, and that
these should not choke your implementation.  Such strings, along with
those from DEFVAR and friends, get printed somehow via the semi-standard
function DESCRIBE, and they may be accessible in other ways.

Maybe in this case less is more.

-- Scott

∂07-Oct-82  1904	BROOKS at MIT-OZ at MIT-MC 	/BALLOT/    
Date:  7 Oct 1982 2203-EDT
From: BROOKS at MIT-OZ at MIT-MC
Subject: /BALLOT/
To: guy.steele at CMU-10A
cc: common-lisp at SU-AI

~ - n y y - n y y y y o y - - y y y a i y r - y - n - y y
  1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8


Note:
On 21 if not "r" then I prefer "m".
-------

∂07-Oct-82  2221	Glenn S. Burke <GSB at MIT-ML> 	[Re: MIT VAX/VMS Lisp Implementors, Ballot]
Date: 8 October 1982 01:23-EDT
From: Glenn S. Burke <GSB at MIT-ML>
Subject: [Re: MIT VAX/VMS Lisp Implementors, Ballot]
To: Common-Lisp at SU-AI

    Date: Thursday, 7 October 1982  21:29-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>
    To:   MIT VAX/VMS Lisp Implementors <NIL at MIT-ML>

    It is nice to know that you speak for the NIL group, but it would also
    be nice to know who is doing the speaking.
----
Oops.  In rapidly decreasing order of significance:  me, George Carrette,
and various other innocent bystanders in the immediate environment who
i flame at on occasion.

∂07-Oct-82  2351	Guy.Steele at CMU-10A 	Documentation and errors, etc.  
Date:  8 October 1982 0251-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Documentation and errors, etc.

Moon is absolutely right that how to handle errors and documentation
in generality is a very difficult aspect of user interface design.
Now that I've got everyone aware of the issues, I propose to retract
my proposal are far as serious discussion of immediate adoption is
concerned.  Les us press on towards the near goal first.
--Guy

∂08-Oct-82  1101	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
Date: Friday, 8 October 1982  14:00-EDT
From: Skef Wholey <Wholey at CMU-20C>
To:   Common-Lisp at SU-AI
Subject: Hash tables => Hashing functions

Since Common Lisp provides three kinds of hash tables (eq, eql, and equal),
shouldn't it provide three kinds of hashing functions?  It currently provides
only SXHASH (i.e. EQUAL-HASH).

∂08-Oct-82  1111	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
Date: Friday, 8 October 1982  14:00-EDT
From: Skef Wholey <Wholey at CMU-20C>
To:   Common-Lisp at SU-AI
Subject: Hash tables => Hashing functions

Since Common Lisp provides three kinds of hash tables (eq, eql, and equal),
shouldn't it provide three kinds of hashing functions?  It currently provides
only SXHASH (i.e. EQUAL-HASH).

∂08-Oct-82  1524	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Hash tables => Hashing functions    
Date: Friday, 8 October 1982, 17:54-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Hash tables => Hashing functions
To: Wholey at CMU-20C, Common-Lisp at SU-AI
In-reply-to: The message of 8 Oct 82 14:00-EDT from Skef Wholey <Wholey at CMU-20C>

No, because it is very hard/expensive to provide a function that hashes
on EQ (and EQL) in a Lisp with a copying GC.  That's why we provide hash
tables: the system can deal with this but the user can't.  For example,
Lisp Machine hash tables all include a little variable that gets compared
against a global how-many-flips-have-happened counter, and if there has
been a flip since last time, the hash table has to be completely rehashed.
The user should not see this counter, especially not as part of the C.L.
definition.

∂08-Oct-82  1526	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
Date: Friday, 8 October 1982, 18:06-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Re: keyword pairs and OPEN
To: Masinter at PARC-MAXC, common-lisp at SU-AI
In-reply-to: The message of 5 Oct 82 23:31-EDT from Masinter at PARC-MAXC

    Date:  5-Oct-82 20:31:36 PDT (Tuesday)
    From: Masinter at PARC-MAXC
    :ACCESS	 - one of :INPUT, :OUTPUT, :APPEND (or ...)
	    no default

    :RECOG - one of :OLD, :NEW, :OLD/NEW (or ...)
	    default depends on :ACCESS

I don't understand this.  Please tell me what each combination means.
For example, what if access is INPUT and recog is NEW?  What if access
is OUTPUT (in the sense of create) and recog is OLD?  It is quite
important that the semantics of OPEN be clearly defined so that every
implementation can be consistent.

The existing definition of the Lisp Machine OPEN function looks rather
similar to what you are proposing; its general complexity and
overgenerality have made it incomprehensible, and so the system has
several completely misimplementations, none of which work right.
I was trying to counter this by keeping things simple and obvious.


∂08-Oct-82  1740	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
Date:  8 Oct 1982 2042-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: keyword pairs and OPEN
To: dlw at SCRC-TENEX at MIT-MC
cc: Masinter at PARC-MAXC, common-lisp at SU-AI
In-Reply-To: Your message of 8-Oct-82 1837-EDT

Here is an attempt to flesh out the meanings of the flags you mentioned.

    :ACCESS
	This flag indicates what kind of I/O you intend to do with the
	file.  Unless otherwise specified, I/O operations will begin
	at the beginning of the file.
	  input - you are only going to read from it.
	  output - you want to start with an empty file, and write new
		data to it.  (Some operating systems allow two modes of
		writing to a file, one of which clears the file beforehand
		and one of which does not.  Typically "output" means that
		you want a file which is clear.  Indeed the alternative
		may be so bizaare that we don't even want to worry about
		it.)
	  write-only - you are only going to write to it, but any existing
		data should not be cleared.  (This is the one that is so
		bizaare you may choose to ignore it.  Probably it would be
		enough to have update mode.)
	  append - like write-only, but if the file already exists,
		writing will start from the end of the existing data.
		(Logically, this is not required, as it is equivalent to
		a write-only open followed by random access to the end
		of file. However a number of operating systems make
		special provisions for append access to files where you
		would not normally be able to open for output and then
		position to the end of file.  Thus it is a useful
		distinction.) 
	  update - you are going to do both input and output.

    :RECOG
	This flag indicates attributes of the file that may help in
	finding it.
	  old - file must exist, the existing version is used
	  new - file must not exist, it is created
	  old-version - file need not exist.  If it does, the existing
		version is used.  If it does not, the file is created.
	  new-version - file need not exist.  If it does, a new version
		is created.  If it does not, the file is created.
	Lest you think I have designed this specifically for Tops-20,
	which allows multiple versions, these distinctions are also
	meaningful on Tops-10, which does not.  On Tops-10, if the file
	exists, old-version would update the existing file and
	new-version would supercede it with a new one.

	Defaults are:
	  input - old
	  output - new-version
	  write-only - old-version
	  append - old-version
	  update - old-version

	Certain combinations are meaningless.  Others may not be allowed
	by the operating system.  Exactly which combinations are allowed
	is implementation-dependent.  However every implementation is
	required to support the following combinations
	  input, old
	  output, new-version
	and all implementations are strongly urged to implement all 5
	default combinations, plus append/old and update/old.

    :RANDOM-ACCESS 
	This flag indicates that the file will be accessed in some
	manner other than sequentially. I don't need it for Tops-20, but
	I think some operating systems may.  In my opinion we should 
	include it if any system of interest requires it.  Does any?

    :IMAGE
	Most runtime systems end up doing various character processing
	such as removing null characters, turning CRLF into LF, removing
	the parity bit, turning control characters into representations
	with ↑, turning two-character CDC "ASCII" into actual ASCII (if
	anyone is going to do a CDC implementation). This turns all of
	that off and give you characters unchanged.  No doubt
	implementors will choose their own extensions to control
	behavior appropriate for the operating system, but this one
	option seems generally useful enough to put in the language.

INPUT, NEW - this is generally meaningless.  Some implementations
would probably create a zero-length file and give immediate end of
file.  Others might call it an error.  (Do we want to try to define
exactly what happens?  Does anyone understand I/O well enough to try
to make a model at that level of detail?)

OUTPUT, OLD - this one supercedes an existing file.  It guarantees
that the file must exist.  It is possible that some implementations
would not allow it, but I would think it would be meaningful for most.

-------

∂08-Oct-82  1800	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
Date:  8 Oct 1982 2042-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: keyword pairs and OPEN
To: dlw at SCRC-TENEX at MIT-MC
cc: Masinter at PARC-MAXC, common-lisp at SU-AI
In-Reply-To: Your message of 8-Oct-82 1837-EDT

Here is an attempt to flesh out the meanings of the flags you mentioned.

    :ACCESS
	This flag indicates what kind of I/O you intend to do with the
	file.  Unless otherwise specified, I/O operations will begin
	at the beginning of the file.
	  input - you are only going to read from it.
	  output - you want to start with an empty file, and write new
		data to it.  (Some operating systems allow two modes of
		writing to a file, one of which clears the file beforehand
		and one of which does not.  Typically "output" means that
		you want a file which is clear.  Indeed the alternative
		may be so bizaare that we don't even want to worry about
		it.)
	  write-only - you are only going to write to it, but any existing
		data should not be cleared.  (This is the one that is so
		bizaare you may choose to ignore it.  Probably it would be
		enough to have update mode.)
	  append - like write-only, but if the file already exists,
		writing will start from the end of the existing data.
		(Logically, this is not required, as it is equivalent to
		a write-only open followed by random access to the end
		of file. However a number of operating systems make
		special provisions for append access to files where you
		would not normally be able to open for output and then
		position to the end of file.  Thus it is a useful
		distinction.) 
	  update - you are going to do both input and output.

    :RECOG
	This flag indicates attributes of the file that may help in
	finding it.
	  old - file must exist, the existing version is used
	  new - file must not exist, it is created
	  old-version - file need not exist.  If it does, the existing
		version is used.  If it does not, the file is created.
	  new-version - file need not exist.  If it does, a new version
		is created.  If it does not, the file is created.
	Lest you think I have designed this specifically for Tops-20,
	which allows multiple versions, these distinctions are also
	meaningful on Tops-10, which does not.  On Tops-10, if the file
	exists, old-version would update the existing file and
	new-version would supercede it with a new one.

	Defaults are:
	  input - old
	  output - new-version
	  write-only - old-version
	  append - old-version
	  update - old-version

	Certain combinations are meaningless.  Others may not be allowed
	by the operating system.  Exactly which combinations are allowed
	is implementation-dependent.  However every implementation is
	required to support the following combinations
	  input, old
	  output, new-version
	and all implementations are strongly urged to implement all 5
	default combinations, plus append/old and update/old.

    :RANDOM-ACCESS 
	This flag indicates that the file will be accessed in some
	manner other than sequentially. I don't need it for Tops-20, but
	I think some operating systems may.  In my opinion we should 
	include it if any system of interest requires it.  Does any?

    :IMAGE
	Most runtime systems end up doing various character processing
	such as removing null characters, turning CRLF into LF, removing
	the parity bit, turning control characters into representations
	with ↑, turning two-character CDC "ASCII" into actual ASCII (if
	anyone is going to do a CDC implementation). This turns all of
	that off and give you characters unchanged.  No doubt
	implementors will choose their own extensions to control
	behavior appropriate for the operating system, but this one
	option seems generally useful enough to put in the language.

INPUT, NEW - this is generally meaningless.  Some implementations
would probably create a zero-length file and give immediate end of
file.  Others might call it an error.  (Do we want to try to define
exactly what happens?  Does anyone understand I/O well enough to try
to make a model at that level of detail?)

OUTPUT, OLD - this one supercedes an existing file.  It guarantees
that the file must exist.  It is possible that some implementations
would not allow it, but I would think it would be meaningful for most.

-------

∂11-Oct-82  1500	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
Date: Monday, 11 October 1982, 17:49-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Re: keyword pairs and OPEN
To: HEDRICK at RUTGERS
Cc: Masinter at PARC-MAXC, common-lisp at SU-AI
In-reply-to: The message of 8 Oct 82 20:42-EDT from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>

Thank you for your summary.  My analysis is that your :RECOG is just the
same thing as my :IF-EXISTS and :IF-DOES-NOT-EXIST except that I like my
names more, and a few minor details are different.  I intentionally
omitted :IMAGE since I could not think of any definition that would be
portable and aid in the writing of portable programs.  Certainly many
implementations will have their own :OPEN options.

You're quite right that we must specify which values of the defined
options are required for all implementations and which are optional.  I
should probably have done this, but I'll leave it to GLS since he knows
more about the restrictions of the VAX, S-1, and Spice implementations
than I do.

∂11-Oct-82  2005	MOON at SCRC-TENEX 	Re: macro expansion 
Date: Monday, 11 October 1982  22:58-EDT
From: MOON at SCRC-TENEX
To:   Common-Lisp at SU-AI
Subject: Re: macro expansion
In-reply-to: The message of 2 Sep 1982 18:09 PDT from JonL at PARC-MAXC

    Date: 2 Sep 1982 18:09 PDT
    From: JonL at PARC-MAXC
    In-reply-to: Moon at SCRC-TENEX's message of Sunday, 29 August 1982, 21:26-EDT

Sorry for the slow response, I am behind on my mail.  There seemed to be a couple
things in this message that shouldn't be left hanging.

      1) Why not have MACROEXPAND return the second value, as obtained
        from MACROEXPAND-1 ?
That would be all right with me, I just overlooked it when writing the sample code.

        It might even be worthwhile for this second return value, when
        non-null, to distinguish between the case of having actually run the
        expansion function and having found the expansion in some "memoization"
        facililty.
I can't see any point to this one.

      2) We saw the need for a function called FIND-MACRO-DEFINITION,
Having this would be fine with me.  I think the committee decided that this
should not be in the portable language, because only MACROEXPAND-1 should
be calling it, and removed this functionality from MACROP or MACRO-P.  I'd
stick with that unless there is a good reason to put it back in.

      3) ocasionally there is 
        a macro which wants to say "don't memoize me at all".
I don't see the use for this, since the macro can't control when the interpreter
or compiler remembers the macro expansion of a form versus when it calls
MACROEXPAND again.  Or was this only an effiency hack, for macros that somehow
knew that memoization took longer than expanding them?

	I'd say that there
        is a lacuna in your proposal in that you don't exhibit code for the case of   
        traditional memoizing by hashtable -- that will show how the macroexpansion
        function is selectively called depending on the hashtable entry.  
I think I don't understand this; perhaps you could elaborate.  If a hash table
entry is absent, you call the expansion function, otherwise you don't.

      4) we often felt the need for an additional argument to the expansion
        function which tells *why* this macro call is being expanded -- e.g.,
        EVAL, or COMPILE, or  FOR-VALUE, or FOR-EFFECTS etc.  I can't
        characterise all such cases, but GSB, KMP, and RWK may have some
        good inputs here.
That would be nice, but perhaps hard to do in general and consistently across
implementations.  Is there a way to leave room for it for the future?  (I wouldn't
like to do this by passing an extra argument which everyone is supposed to ignore!)

    Point 3 brings up another possibililty -- maybe your current definition of
    *MACROEXPAND-HOOK* is an over-generalization.  That is, why not
    have two hooks, one for testing whether or not a "memoization" is present
    for the macro call in question (and returning it if present), and another hook
    of three arguments namely:
          i) a pointer to the original cell (macro call),
         ii) the already-computed expansion form, and
        iii) a symbol to indicate the reason why the macro call was "expanded"
    I realise that iii) will require more discussion, so maybe now is not the time
    to put it into CommonLisp; also the memoization hook would have to return
    a second value to indicate whether a memo was present.
I don't see what advantage is gained by splitting the hook in half.  Don't forget
that Common Lisp provides a variety of built-in table mechanisms, including hash
tables, so the user doesn't have to implement the table lookup himself the way
he might in Maclisp.

    In any case, I'd rather see the default value for these macro hooks be NIL,
    so that one didn't have to understand the complexities of expansions and
    memoizations just to get the default case (that is, unless someone plans to
    allow NIL as a valid function name and . . . )

Surely each implementation provides the default functions as the initial values
of these variables, rather than each implementation being required to test
explicitly for NIL in the variable.  Actually we could leave the implementation
free to do it either way, and guarantee nothing about the initial values except
that they provide a certain behavior.

∂13-Oct-82  1309	STEELE at CMU-20C 	Ballot results  
Date: 13 Oct 1982 1608-EDT
From: STEELE at CMU-20C
Subject: Ballot results
To: common-lisp at SU-AI

?????????????????????????????????????????????????????????????????????????????
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?  %  =================================================================  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  #  /  The October 1982 Common LISP Ballot  /  #  +  $  =  %  ?
?  %  =  $  +  #  /                RESULTS                /  #  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =================================================================  %  ?
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?????????????????????????????????????????????????????????????????????????????

Here are the tabulated votes on the October 1982 Common LISP Ballot.  For
each issue the summary vote shown between "***" is what I take to be a
consensus, with a "?" added if I am a bit uncertain.  I will edit the
manual according to these guidelines unless someone screams loudly and
soon over some issue.  A few of the issues had a very mixed response;
these I have labeled "Controversial" and will take no immediate action on.
--Guy

1.  How shall the case for a floating-point exponent specifier
output by PRINT and FORMAT be determined?
	(a) upper case, for example 3.5E6
	(b) lower case, for example 3.5e6
	(c) a switch
	(d) implementation-dependent

Issue 1: *** B? ***
Hedrick: B	Wholey: -	Fahlman: B	Weinreb: B	Killian: B
Zubkoff: C	Moon: B		van Roggen: D	Masinter: A	RMS: B
Dyer: B		Bawden: -	Feinberg: B	Ginder: B	Burke et al.: B
Brooks: -	Gabriel: A	DECLISP: B	Steele: C	Dill: D
Scherlis: -	Pitman: B	Anderson: B

2.  Shall we change the name SETF to be SET?   (y) yes   (n) no

Issue 2: *** N ***
Hedrick: N	Wholey: N	Fahlman: N	Weinreb: N	Killian: X
Zubkoff: Y	Moon: N		van Roggen: Y	Masinter: N	RMS: N
Dyer: N		Bawden: N	Feinberg: N	Ginder: N	Burke et al.: N
Brooks: N	Gabriel: N	DECLISP: N	Steele: N	Dill: N
Scherlis: Y	Pitman: N	Anderson: N

Killian: I have been convinced that renaming SETF to SET would be
wrong because it would require changing lots of old code.  But,
you seem to have ignored the rest of my suggestion in your
ballot, namely eliminating those horrid "F"s at the end of
several function names (INCF, GETF etc.).  If you don't do this,
then you're being inconsistent by not naming PUSH PUSHF, etc.
The "F" at the end of "SETF" would then be there purely for
compatibility, and could be renamed when another Lisp dialect
is designed, years hence.

Pitman: I think we should do this, but not at this time.

RMS: I very strongly do not want to have to change uses of the
traditional function SET in the Lisp machine system.

Feinberg: A better name than SETF (or SET) should be found.

3.  Shall there be a type specifier QUOTE, such that (QUOTE x) = (MEMBER x)?
Then MEMBER can be eliminated; (MEMBER x y z) = (OR 'x 'y 'z).  Also one can
write such things as (OR INTEGER 'FOO) instead of (OR INTEGER (MEMBER FOO)).
	(y) yes   (n) no

Issue 3: *** Y? ***
Hedrick: X	Wholey: Y	Fahlman: N	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: N	Masinter: Y	RMS: -
Dyer: X		Bawden: Y	Feinberg: Y	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: N	Steele: Y	Dill: Y
Scherlis: Y	Pitman: Y	Anderson: -

4.  Shall MOON's proposal for LOAD keywords, revised as shown below, be used?
	(y) yes   (n) no

Issue 4: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: X	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: X	Anderson: -

Moon: I thought we agreed to make LOAD take a stream as its first argument,
instead of a pathname, and flush the :STREAM keyword.  :ERROR should
control only "file does not exist" errors, not "host down", "directory
does not exist", "illegal character in file name", "no access to file",
and "file cannot be read because of disk error".  Nor should it affect
errors due to evaluation of forms in the file.  So I think it needs a
better name; how about :NONEXISTENT-OK?

Masinter: :ERROR, :SET-DEFAULT-PATHNAME options to LOAD should be
rationalized with OPEN; the handling here of search paths should
logically be handled by passing on some of the options from LOAD to OPEN
rather than having LOAD do special path-name processing. This is because
users who manipulate files want to do similar hacking, and the mechanism
should be common.

Pitman: I would vote YES except: As suggested by someone when it was
proposed, any mention of packages should be stricken pending the release
of a package system specification.

Dill: :PACKAGE & :VERBOSE should be flushed, since they are package system
dependent.

5.  Shall closures over dynamic variables be removed from Common LISP?
	(y) yes   (n) no

Issue 5: *** Y? ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: N	Killian: -
Zubkoff: -	Moon: -		van Roggen: Y	Masinter: -	RMS: -
Dyer: X		Bawden: -	Feinberg: Y	Ginder: Y	Burke et al.: -
Brooks: -	Gabriel: N	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: N	Anderson: -

6.  Shall LOOP, as summarized below, be included in Common LISP?
	(y) yes   (n) no

Issue 6: Controversial
Hedrick: N	Wholey: N	Fahlman: N	Weinreb: Y	Killian: Y
Zubkoff: X	Moon: -		van Roggen: N	Masinter: X	RMS: N
Dyer: Y		Bawden: Y	Feinberg: N	Ginder: N	Burke et al.: Y
Brooks: N	Gabriel: X	DECLISP: Y	Steele: N	Dill: N
Scherlis: N	Pitman: N	Anderson: N

Fahlman: I am in favor of adding the LOOP package as described (once it is
completed) to the language as a portable yellow pages module.  I feel
rather strongly that it is premature to add LOOP to the white pages.

Zubkoff: The LOOP macro should be kept in the yellow pages until we've
had a chance to use it for a while and determine whether or not it is the
"right" thing.

Masinter: I feel strongly that the white pages SHOULD include a LOOP construct.
I care less about which one, but I like most of Moon's proposal better than DO
and what I saw of LetS. I'd get rid of AND and ELSE. I don't understand
if the "COLLECT" lexical scoping includes scoping under macro expansion.

Pitman: As a yellow-pages extension is ok by me. I strongly oppose its
placement in the white pages.

Feinberg: We should carefully examine all iteration construct proposals
before committing to any particular one.  I feel strongly about 
this.  I would very much like to see complete documentation
on Loop and any other loop construct which might be included 
in Common Lisp, especially before we decide to incorporate them
into the white pages.

Gabriel: I believe that a LOOP construct of some sort is needed: I am
constantly bumping into the limitations of MacLisp-style DO.  The
Symbolics people claim that LOOP, as defined in the current proposal, is
well thought-out and indispensible. Not having used it particularly, I
cannot pass judgement on this. I advocate putting LOOP into the hottest
regions of the Yellow Pages, meaning that people should use it immediately
so that any improvements to clarity can be made rapidly. The best possible
LOOP should then be moved to the White Pages.
My prejudice is that LOOP code is very difficult to understand. On the
other hand, closures are difficult for many people to understand, and
perhaps the difficulty is due to unfamiliarity in the LOOP case as it is
in the closure case.
In my current programming I do not define my own iteration construct
(though I have in the past) because I've found that other people (such as
myself at a later date) do not readily understand my code when it contains
idiosyncratic control structures.  If we do not standardize on a LOOP
construct soon we will be faced with the fact of many people defining
their own difficult-to-understand control structures.

7.  Regardless of the outcome of the previous question, shall CYCLE
be retained and be renamed LOOP, with the understanding that statements
of the construct must be non-atomic, and atoms as "statements" are
reserved for extensions, and any such extensions must be compatible
with the basic mening as a pure iteration construct?
	(y) yes   (n) no

Issue 7: *** Y? ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: -	Moon: Y		van Roggen: N	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: N	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: N	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: N

Feinberg: I don't think we should make any commitment at all, even to this
extent.  Loop is too nice a word to give up before we even agree about
installing it into the language.

8.  Shall ARRAY-DIMENSION be changed by exchanging its arguments,
to have the array first and the axis number second, to parallel
other indexing operations?
	(y) yes   (n) no

Issue 8: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: -	RMS: Y
Dyer: Y		Bawden: -	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: -	Pitman: Y	Anderson: Y

9.  Shall MACROEXPAND, as described below, replace the current definition?
	(y) yes   (n) no

Issue 9: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: -	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: -	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: X	Anderson: -

Killian:  This is ok as far as it goes, but I intend to suggest
additions when I find the time.

Masinter: This seems right but not quite fully specified, e.g. LAMBDA-MACRO.

Pitman: I would vote YES except:
I am uncomfortable with saying that a form returns two
values and then returning only one (letting the rest default to NIL).
Does Common-Lisp specify anything on this? In any case, I would ammend
the (cond ((and (pairp ...) ...) (values (...) t))
	  (t form))
to (cond (...) (t (values form nil))) to make it clear that two values
are always returned. If this modification is made, I am happy with this
proposal.

10.  Shall all global system-defined variables have names beginning
and ending with "*", for example *PRINLEVEL* instead of PRINLEVEL
and *READ-DEFAULT-FLOAT-FORMAT* instead of READ←DEFAULT-FLOAT-FORMAT?
	(y) yes   (n) no

Issue 10: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: N
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: X
Dyer: N		Bawden: N	Feinberg: Y	Ginder: Y	Burke et al.: X
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: Y

RMS: I would prefer a character other than *, such as "-".
It is easier to type, and easier to type correctly.

Bawden: I am in favor of variables named *FOO* over variables named FOO only
when that doesn't introduce an incompatibility with existing Lisps.  That is
why I voted NO on 10, because it involved an incompatible change to variables
like PRINLEVEL.  I voted YES for 11 because currently we have no named
constants as far as I know so there is no incompatibility.

Burke et al.: I really like only ONE "*" at the beginning of the name.  I got
tired of shifting for two years ago, but conversely couldn't stand to
not have the specialness of the variable not be obvious.

11.  Same question for named constants (other than T and NIL), such as
*PI* for PI and *MOST-POSITIVE-FIXNUM* for MOST-POSITIVE-FIXNUM.
	(y) yes   (n) no   (o) yes, but use a character other than "*"

Issue 11: Controversial
Hedrick: Y	Wholey: N	Fahlman: Y	Weinreb: Y	Killian: N
Zubkoff: Y	Moon: N		van Roggen: Y	Masinter: Y	RMS: X
Dyer: N		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: X
Brooks: O	Gabriel: Y	DECLISP: Y	Steele: N	Dill: X
Scherlis: -	Pitman: Y	Anderson: Y

Fahlman: Whatever is done about global vars, global constants should be the
same.  I oppose option 3 or any plan to make them look syntactically
different.

Moon: I like to use the stars to mean "someone may bind this" rather than
"don't use this as a local variable name", which is why I voted no on
putting stars around constants.  However, others might disagree with me
and I will defer to the majority.  I do think stars around variable names
are important.

12.  Shall a checking form CHECK-TYPE be introduced as described below?
	(y) yes   (n) no

Issue 12: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: -	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: Y	Anderson: Y

13.  Shall a checking form CHECK-SUBSEQUENCE be introduced as described below?
	(y) yes   (n) no

Issue 13: Controversial
Hedrick: N	Wholey: -	Fahlman: N	Weinreb: -	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: -	RMS: -
Dyer: N		Bawden: -	Feinberg: N	Ginder: Y	Burke et al.: N
Brooks: -	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: N
Scherlis: Y	Pitman: Y	Anderson: Y

Feinberg: It seems like we're taking this type checking stuff a little 
too far.  Let the user write his own type checking code, or
make a yellow pages package called Carefully (or Lint) or
something. 

Dill: There should be a succinct way about talking about the contents
of sequences, but this particular one doesn't have the right functionality.
I prefer a regular-expression notation of some form, but don't have it
well enough worked out to propose one.  Lets leave it out of the language
until someone figures out how to do it well.

14.  Shall the functions LINE-OUT and STRING-OUT, eliminated in November,
be reinstated?
	(y) yes   (n) no

Issue 14: *** Y ***
Hedrick: N	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: -	Moon: -		van Roggen: Y	Masinter: -	RMS: -
Dyer: X		Bawden: -	Feinberg: Y	Ginder: -	Burke et al.: Y
Brooks: -	Gabriel: -	DECLISP: Y	Steele: Y	Dill: X
Scherlis: -	Pitman: Y	Anderson: -

15.  Shall the REDUCE function be added as described below?
	(y) yes   (n) no

Issue 15: *** Y ***
Hedrick: N	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: -	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: -	Anderson: N

Moon: Should the name be REDUCE, or something else?  Hearn aside, the name
doesn't instantly convey to me what it does.  I haven't come up with an
alternative suggestion, however.

Pitman: I have no use for this but have no strong objection.

16.  Shall the Bawden/Moon solution to the "invisible block" problem
be accepted?  The solution is to define (RETURN x) to mean precisely
(RETURN-FROM NIL x), and to specify that essentially all standard
iterators produce blocks named NIL.  A block with a name other than
NIL cannot capture a RETURN, only a RETURN-FROM with a matching name.
	(y) yes   (n) no

Issue 16: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: -	RMS: N
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: -

RMS: I am strongly opposed to anything that would require me to find
all the named PROGs in the Lisp machine system which have simple
RETURNs that return from them.  This would make a lot of extra work
for me.  Please don't impose this on me.

Dill: It seems to me that it ought to be possible to exploit lexical
scoping to solve problems like this in a more general way.  If this is
possible, then this proposeal is redundant.

17.  Shall the TAGBODY construct be incorporated?  This expresses just
the behavior of the GO aspect of a PROG.  Any atoms in the body
are not evaluated, but serve as tags that may be specified to GO.
Tags have lexical scope and dynamic extent.  TAGBODY always returns NIL.
	(y) yes   (n) no

Issue 17: *** Y ***
Hedrick: N	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: X
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: N
Scherlis: -	Pitman: Y	Anderson: Y

RMS: Why must GOBODY [sic] always return NIL just because PROG does?
It is just as easy to make GOBODY return the value of the last form in
it.  We can consider a PROG to expand into a GOBODY followed by a NIL.

Feinberg: A better name than TAGBODY should be found.  

18.  What shall be done about RESTART?  The following alternatives seem to
be the most popular:
	(a) Have no RESTART form.
	(b) RESTART takes the name of a block.  What happens when you say
	    (RESTART NIL) must be clarified for most iteration constructs.
	(c) There is a new binding form called, say, RESTARTABLE.
	    Within (RESTARTABLE FOO . body), (RESTART FOO) acts as a jump
	    to the top of the body of the enclosing, matching RESTARTABLE form.
	    RESTART tags have lexical scope and dynamic extent.

Issue 18: *** A ***
Hedrick: A	Wholey: A	Fahlman: A	Weinreb: A	Killian: A
Zubkoff: A	Moon: A		van Roggen: A	Masinter: A	RMS: C
Dyer: A		Bawden: A	Feinberg: A	Ginder: A	Burke et al.: A
Brooks: A	Gabriel: B	DECLISP: A	Steele: C	Dill: X
Scherlis: -	Pitman: C	Anderson: A

Fahlman: I now believe that RESTART is more trouble than it is worth.  I am
strongly opposed to any plan, such as option 3, that would add a RESTART
form but make it impossible to use this with the implicit block around a
DEFUN.  If you have to introduce a RESTARTABLE block, you may as
well use PROG/GO.

19.  Shall there be a built-in identity function, and if so, what shall it
be called?
	(c) CR   (i) IDENTITY   (n) no such function

Issue 19: *** I ***
Hedrick: I	Wholey: I	Fahlman: I	Weinreb: I	Killian: -
Zubkoff: I	Moon: I		van Roggen: I	Masinter: I	RMS: I
Dyer: X		Bawden: I	Feinberg: I	Ginder: I	Burke et al.: I
Brooks: I	Gabriel: -	DECLISP: I	Steele: I	Dill: X
Scherlis: I	Pitman: I	Anderson: -

RMS: The canonical identity function is now called PROG1, but the name
IDENTITY is ok by me.

20.  Shall the #*... bit-string syntax replace #"..."?  That is, shall what
was before written #"10010" now be written #*10010 ?
	(y) yes   (n) no

Issue 20: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: X		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: N	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: Y	Anderson: Y

21.  Which of the two outstanding array proposals (below) shall be adopted?
	(s) the "simple" proposal
	(r) the "RPG memorial" proposal
	(m) the "simple" proposal as amended by Moon

Issue 21: *** M? ***
Hedrick: M	Wholey: -	Fahlman: M	Weinreb: M	Killian: M
Zubkoff: M	Moon: M		van Roggen: M	Masinter: -	RMS: M
Dyer: -		Bawden: M	Feinberg: M	Ginder: M	Burke et al.: M
Brooks: R	Gabriel: X	DECLISP: M	Steele: M	Dill: M
Scherlis: M	Pitman: M	Anderson: M

Brooks: if not "r" then I prefer "m".

Gabriel: I prefer the "RPG memorial", but I do not feel so strong
about this that I would sink the Common Lisp effort over it.

22.  Shall the following proposal for the OPTIMIZE declaration be adopted?
	(y) yes   (n) no

Issue 22: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: N
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: N	RMS: -
Dyer: Y		Bawden: -	Feinberg: N	Ginder: Y	Burke et al.: Y
Brooks: -	Gabriel: Y	DECLISP: Y	Steele: -	Dill: X
Scherlis: N	Pitman: X	Anderson: X

Pitman: I would vote YES except:
The use of numbers instead of keywords bothers me. The section saying
which numbers can be which values and how those values will be interpreted
seems to FORTRANesque to me. I think these values should be just keywords
or the tight restrictions on their values should be lifted. The only use
for numbers would be to allow users a fluid range of possibilities.

Feinberg: Keywords instead of numbers would be nicer.  How about
:dont-care, :low, :medium, :high?

Dill: I don't think that we need an optimize declaration in common lisp.
It's not necessary for portability, and intensely dependent on compiler
implementations.  If we must have one, I strongly favor the Fahlman proposal
over proposals that would have symbolic specifications.

23.  Shall it be permitted for macros calls to expand into DECLARE forms
and then be recognized as valid declarations?
This would not allows macros calls *within* a DECLARE form, only allow
macros to expand into a DECLARE form.
	(y) yes   (n) no

Issue 23: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: Y

Pitman: I also support allowing multiple declare forms at the top of
a bind form. ie,
   (LAMBDA (X Y) (DECLARE (SPECIAL X)) (DECLARE (SPECIAL Y))
for ease in macros. Steele's proposed evaluator did this and it wasn't
notably expensive.

24.  Shall there be printer control variables ARRAY-PRINLEVEL and
ARRAY-PRINLENGTH to control printing of arrays?  These would not
limit the printing of strings.
	(y) yes   (n) no

Issue 24:  Controversial
Hedrick: N	Wholey: Y	Fahlman: N	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: N	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: -	Gabriel: N	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: N	Anderson: Y

25.  Shall lambda macros, as described below, be incorporated into
the language, and if so, shall they occupy the function name space
or a separate name space?
	(f) function name space   (s) separate name space   (n) no lambda macros

Issue 25: Controversial
Hedrick: N	Wholey: -	Fahlman: N	Weinreb: Y	Killian: F
Zubkoff: -	Moon: S		van Roggen: S	Masinter: D	RMS: S
Dyer: S		Bawden: S	Feinberg: N	Ginder: -	Burke et al.: S
Brooks: N	Gabriel: F	DECLISP: S	Steele: N	Dill: N
Scherlis: -	Pitman: S	Anderson: N

Fahlman: I seem to be unable to locate any explanation of why Lambda macros
are useful enough to be worth the bother.  Looks like needless hair to
me, but I seem to dimly recall some arguments for why they were needed.
I'm not passionately opposed, but every page full of hairy stuff in the
manual hurts us.

Masinter: Spec here not consistent with MACROEXPAND proposal.

Feinberg: Once again, hair that I don't think needs to be standardized on.
I think most users would never need this, and perhaps a better 
way to do this can be thought of.

26.  Shall the floating-point manipulations described below be adopted?
	(y) as described by MOON
	(a) as amended (FLOAT-SIGN changed) by GLS
	(n) do not adopt them

Issue 26: *** A ***
Hedrick: A	Wholey: A	Fahlman: A	Weinreb: A	Killian: A
Zubkoff: A	Moon: Y		van Roggen: A	Masinter: -	RMS: -
Dyer: -		Bawden: -	Feinberg: -	Ginder: A	Burke et al.: -
Brooks: -	Gabriel: A	DECLISP: A	Steele: A	Dill: X
Scherlis: -	Pitman: -	Anderson: Y

Killian: Since TRUNC was renamed TRUNCATE at the last meeting, the
FTRUNC in this proposal would have to become FTRUNCATE.

27.  Shall DEFMACRO, DEFSTRUCT, and other defining forms also be
allowed to take documentation strings as possible and appropriate?
	(y) yes   (n) no

Issue 27: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: Y
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: Y

28.  Shall the following proposed revision of OPEN keywords be accepted?
	(y) yes   (n) no

Issue 28: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: -	Pitman: X	Anderson: Y

DECLISP: Either READ-ALTER, READ-WRITE OR UPDATE should replace the :OVERWRITE
keyword for :DIRECTION.  Overwrite suggests that an existing file will be
destroyed by having new data written into the same space.
-------

∂14-Oct-82  2110	Guy.Steele at CMU-10A 	Here is a good idea, I think    
Date: 15 October 1982 0010-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Here is a good idea, I think

Presumably (EVENP x y)  <=>  (ZEROP (MOD x y)) ?

- - - - Begin forwarded message - - - -
Mail-From: ARPANET host PARC-MAXC received by CMU-10A at 14-Oct-82 20:51:44-EDT
Date: 14-Oct-82 17:52:08 PDT (Thursday)
From: Masinter at PARC-MAXC
Subject: optional argument for EVENP?
To: Guy.Steele@CMU-10A
cc: , Masinter.PA

We've found a need in our system for two-argument EVENP, 

(EVENP n &optional divisor)
	divisor defaults to 2. Predicate returns true if n is an integral multiple
	of divisor.

(ODDP n &optional divisor) is merely (NOT (EVENP n divisor)).

This seems to be a logical extension of MOD.
- - - - End forwarded message - - - -

∂14-Oct-82  2139	Scott E. Fahlman <Fahlman at Cmu-20c> 	Here is a good idea, I think   
Date: Friday, 15 October 1982  00:36-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Here is a good idea, I think


Terrible idea!  Actually, I have no objection to having this function
around, except that is one more built-in function, but you can't be
serious about wanting to call it EVENP/ODDP?  You really want to have
code around containing (evenp 51 17) => T ???   I've been looking at
even numbers for most of my life, and 51 is not one, whatever that other
silly argument says.  Pythagoras would turn over in his triangle if he
saw this.

If this has to happen, call it ZEROP-MOD or some such.  Better yet, make
the users type (zerop (mod ...)).

-- Scott

∂14-Oct-82  2144	Guy.Steele at CMU-10A 	Here is a terrible idea, I think
Date: 15 October 1982 0040-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Here is a terrible idea, I think

One advantage of making the user type (ZEROP (MOD ...)) is that
it makes clear that he is doing that and not (ZEROP (REMAINDER ...)),
which might also be a distinct useful operation.
--Sigh,
  Guy

∂14-Oct-82  2210	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
Date: 15 October 1982 01:02-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Here is a good idea, I think
To: common-lisp at SU-AI

    Date: 15 October 1982 0010-EDT (Friday)
    From: Guy.Steele at CMU-10A
    Re:   Here is a good idea, I think

    Presumably (EVENP x y)  <=>  (ZEROP (MOD x y)) ?

My mathematical training makes me think it more natural to define:

    (ZEROP x y) <=> (ZEROP (MOD x y))

So that you can think of the second argument to ZEROP as specifing the ring
that you are considering the first argument a member of.  In fact, if it
wasn't about 20 years too late, I might suggest

    (PLUS x y m) <=> (MOD (PLUS x y) m)

and so forth for all the other arithmetic functions.  There are some real
benefits to be gained from knowing the modulus before you start to compute
some functions (EXPT for example).

Or do we already have a meaning for the second argument to ZEROP?

∂14-Oct-82  2222	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
Date: 15 October 1982 01:02-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Here is a good idea, I think
To: common-lisp at SU-AI

    Date: 15 October 1982 0010-EDT (Friday)
    From: Guy.Steele at CMU-10A
    Re:   Here is a good idea, I think

    Presumably (EVENP x y)  <=>  (ZEROP (MOD x y)) ?

My mathematical training makes me think it more natural to define:

    (ZEROP x y) <=> (ZEROP (MOD x y))

So that you can think of the second argument to ZEROP as specifing the ring
that you are considering the first argument a member of.  In fact, if it
wasn't about 20 years too late, I might suggest

    (PLUS x y m) <=> (MOD (PLUS x y) m)

and so forth for all the other arithmetic functions.  There are some real
benefits to be gained from knowing the modulus before you start to compute
some functions (EXPT for example).

Or do we already have a meaning for the second argument to ZEROP?

∂14-Oct-82  2356	HEDRICK at RUTGERS 	A bunch of lousy ideas   
Date: 15 Oct 1982 0218-EDT
From: HEDRICK at RUTGERS
To: common-lisp at SU-AI
Subject: A bunch of lousy ideas
Message-ID: <"MS10(2107)+GLXLIB1(1130)" 11863919900.50.19.85746 at RUTGERS>

There is already enough of extending functions by adding extra
arguments.  ROUND that does division if you give it an extra argument,
etc.  I know this all sounds clever, and it even looks harmless when you
first see it, since the old function does continue to work.  But I think
it is a lousy idea to make ROUND do division, to make SIGN do whatever
it is that we agreed it would do, and to make EVENP do mod.  This sounds
too much like the classic kludges of the following sort:

(IO-OP FOO-FLAG [COUNT])
  if FOO-FLAG is true, this prints its argument
  if FOO-FLAG is false, it rewinds the nearest magtape the 
	number of frames specified by the argument COUNT
    except if COUNT is non-numeric it is the name of the tape
	drive, and the number of frames to be rewound will be
	found in the global variable *FRAMES*

I think we are better off having a one to one mapping between conceptual
functions and names.
   --------

∂15-Oct-82  0011	HEDRICK at RUTGERS 	A bunch of lousy ideas   
Date: 15 Oct 1982 0218-EDT
From: HEDRICK at RUTGERS
To: common-lisp at SU-AI
Subject: A bunch of lousy ideas
Message-ID: <"MS10(2107)+GLXLIB1(1130)" 11863919900.50.19.85746 at RUTGERS>

There is already enough of extending functions by adding extra
arguments.  ROUND that does division if you give it an extra argument,
etc.  I know this all sounds clever, and it even looks harmless when you
first see it, since the old function does continue to work.  But I think
it is a lousy idea to make ROUND do division, to make SIGN do whatever
it is that we agreed it would do, and to make EVENP do mod.  This sounds
too much like the classic kludges of the following sort:

(IO-OP FOO-FLAG [COUNT])
  if FOO-FLAG is true, this prints its argument
  if FOO-FLAG is false, it rewinds the nearest magtape the 
	number of frames specified by the argument COUNT
    except if COUNT is non-numeric it is the name of the tape
	drive, and the number of frames to be rewound will be
	found in the global variable *FRAMES*

I think we are better off having a one to one mapping between conceptual
functions and names.
   --------

∂15-Oct-82  0110	Kent M. Pitman <KMP at MIT-MC> 	conservatism in extensions  
Date: 15 October 1982 04:10-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject: conservatism in extensions
To: hedrick at RUTGERS
cc: common-lisp at SU-AI

i agree. we should be very skeptical of extending things when there is wide
variety of opinion on the direction that extension should go. certainly at
this phase, extensions of this class are not advisable at all. we can always
later add such functionality in an upward-compatible way; it will be harder
to go back on wrong decisions. right now, we need to get any hard issues
ironed out that are needed to get initial implementations up and running.
once people have played with implementations for a while and we get back
feedback about actual use, then is the time to extend an operation...

∂15-Oct-82  0152	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Here is a tired quux, I think
Date: Friday, 15 October 1982, 04:50-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Here is a tired quux, I think
To: Guy.Steele at CMU-10A
Cc: common-lisp at SU-AI
In-reply-to: The message of 15 Oct 82 00:40-EDT from Guy.Steele at CMU-10A

    Date: 15 October 1982 0040-EDT (Friday)
    From: Guy.Steele at CMU-10A
    To: common-lisp at SU-AI
    Subject: Here is a terrible idea, I think

    One advantage of making the user type (ZEROP (MOD ...)) is that
    it makes clear that he is doing that and not (ZEROP (REMAINDER ...)),
    which might also be a distinct useful operation.

Did you really just say that?

∂15-Oct-82  1214	The Great Quux at CMU-10A 	Conservatism in extensions  
Date: 15 October 1982 1513-EDT (Friday)
From: The Great Quux at CMU-10A
To: common-lisp at SU-AI
Subject: Conservatism in extensions
Sender: Guy.Steele at CMU-10A
Reply-To: Guy.Steele at CMU-10A

Perhaps we need a predicate GARBAGEP that takes a string.  For example,
	(GARBAGEP "I think GCD should accept complex numbers...") => T.
--Quux

∂15-Oct-82  1233	Guy.Steele at CMU-10A 	Tried Quux vindicated 
Date: 15 October 1982 1516-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Tried Quux vindicated

Hmm, I see... while REMAINDER and MOD are different in general, they
agree on what is zero.  But in the presence of IEEE floating-point
arithmetic, perhaps (MOD -6.0 3.0) => 0.0 and (REMAINDER -6.0 3.0) => -0.0,
so I think I just barely wiggle out of that one.  It's a pretty
flimsy argument.
(Yes, I was very tired.)

∂16-Oct-82  0001	Alan Bawden <ALAN at MIT-MC> 	Overconservatism in extensions
Date: 16 October 1982 03:01-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Overconservatism in extensions
To: Common-Lisp at SU-AI

    Date: 15 October 1982 1513-EDT (Friday)
    From: The Great Quux at CMU-10A
    Sender: Guy.Steele at CMU-10A

    Perhaps we need a predicate GARBAGEP that takes a string.  For example,
    	(GARBAGEP "I think GCD should accept complex numbers...") => T.

NO!  This is not a garbage string!  GCD should certainly work on complex
integers.  It is completely consistent to extend GCD in this manner, and I
certainly expected that we would.  It's not even hard.

Or is there some more subtle joke here that I don't understand?  You'll
pardon my confusion, but it seems equally plausible that this is a joke
that I don't appreciate, or that Steele didn't think too hard about an
example of a braindamaged idea.

∂16-Oct-82  1055	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
Date: 16 October 1982 1351-EDT (Saturday)
From: The Great Quux at CMU-10A
To: Alan Bawden <ALAN at MIT-MC>
Subject: Re: Overconservatism in extensions
CC: common-lisp at SU-AI
Sender: Guy.Steele at CMU-10A
Reply-To: Guy.Steele at CMU-10A
In-Reply-To: Alan Bawden's message of 16 Oct 82 02:01-EST

Okay, how about:
  (GARBAGEP "(GARBAGEP \"I think GCD should accept complex numbers...\") => T")
	=> T
?  Now is everybody happy?
--Quux

∂16-Oct-82  1111	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
Date: 16 October 1982 1351-EDT (Saturday)
From: The Great Quux at CMU-10A
To: Alan Bawden <ALAN at MIT-MC>
Subject: Re: Overconservatism in extensions
CC: common-lisp at SU-AI
Sender: Guy.Steele at CMU-10A
Reply-To: Guy.Steele at CMU-10A
In-Reply-To: Alan Bawden's message of 16 Oct 82 02:01-EST

Okay, how about:
  (GARBAGEP "(GARBAGEP \"I think GCD should accept complex numbers...\") => T")
	=> T
?  Now is everybody happy?
--Quux

∂17-Oct-82  1255	Guy.Steele at CMU-10A 	What can I say?  
Date: 17 October 1982 1553-EDT (Sunday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: What can I say?


- - - - Begin forwarded message - - - -
Mail-From: ARPANET host MIT-MC received by CMU-10A at 16-Oct-82 23:47:31-EDT
Date: Saturday, 16 October 1982  23:44-EDT
From: MOON at SCRC-TENEX
To:   Guy.Steele at CMU-10A
Subject: Re: Overconservatism in extensions
In-reply-to: The message of 16 Oct 1982 1351-EDT () from The Great Quux at CMU-10A

I presume your latest message was a typo for

	#1= (GARBAGEP #1#)

right?
- - - - End forwarded message - - - -

∂17-Oct-82  2120	Guy.Steele at CMU-10A 	STRING-OUT, LINE-OUT and READLINE    
Date: 18 October 1982 0019-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: STRING-OUT, LINE-OUT and READLINE

How would people feel about renaming these to WRITE-STRING, WRITE-LINE,
and READ-LINE?  This is in line with other renamings such as WRITE-CHAR.
--Guy

∂17-Oct-82  2303	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	STRING-OUT -> WRITE-STRING, etc.  
Date: Monday, 18 October 1982, 02:01-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: STRING-OUT -> WRITE-STRING, etc.
To: Guy.Steele at CMU-10A
Cc: common-lisp at SU-AI
In-reply-to: The message of 18 Oct 82 00:19-EDT from Guy.Steele at CMU-10A

We certainly must do this, or forfeit any claim to consistency.  I guess
it just got left off the ballot accidentally, since it was put in at the
last minute at the most recent meeting.  I was probably against it, too.

∂18-Oct-82  1458	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	STRING-OUT, LINE-OUT and READLINE   
Date: Monday, 18 October 1982, 16:20-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: STRING-OUT, LINE-OUT and READLINE
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-reply-to: The message of 18 Oct 82 00:19-EDT from Guy.Steele at CMU-10A

Yes, they should be renamed as you say.

∂19-Oct-82  1211	George J. Carrette <GJC at MIT-ML> 
Date: 19 October 1982 15:14-EDT
From: George J. Carrette <GJC at MIT-ML>
To: common-lisp at SU-AI

I was wondering..., could AREF and ASET be defined to work on hashtables?
Right now we have at least three conventions defined for referencing an
object via a key or index. We have "properties" working on symbols and
conveniently defined for lists, then arrays, and now hashtables. (Am I
leaving out anything? Alists?) Needing all of these for historical reasons 
or otherwise is ok, but it sure would be nice to have ONE fully generic way of
accessing a "table," especially since other languages make it a point of
providing such a thing.

-gjc

∂20-Oct-82  1612	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
Date: 20 October 1982 19:07-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject:  Proposed evaluator for Common LISP
To: STEELE at CMU-20C
cc: common-lisp at SU-AI

Common Lisp has not yet, to my knowledge, addressed the problem
of debugging.  With lexical scoping, it is no longer possible to
simply reference variables from a read-eval-print debugging loop,
the standard el cheapo lisp debugger, unless something more is
going on than your proposed evaluator is letting on.  Has this
been thought about yet?  If so, what is being proposed?  It would
be nice if sufficient functionality were provided that *simple*
portable debuggers could be written.

∂20-Oct-82  1700	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Proposed evaluator for Common LISP
Date: 20 Oct 1982 1959-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: Proposed evaluator for Common LISP
To: EAK at MIT-MC
cc: STEELE at CMU-20C, common-lisp at SU-AI
In-Reply-To: Your message of 20-Oct-82 1907-EDT

Given proper functions to access scopes up the stack, it is just as easy
to do a debugger for a lexical language as a dynamic language.  We know
this from personal experience, having done a lexically-bound UCI Lisp.
Certainly some adaptation had to be done, but the results were just as
good, and the code wasn't really much worse.
-------

∂20-Oct-82  1743	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
Date: 20 October 1982 20:40-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject:  Proposed evaluator for Common LISP
To: HEDRICK at RUTGERS
cc: common-lisp at SU-AI

I wasn't asking whether it was doable, but whether anyone was
working on the Common Lisp design for debugging with lexical
scoping.  If you're familiar with an existing winning design,
perhaps you should just submit it as a proposal.

∂27-Oct-82  0010	Guy.Steele at CMU-10A 	Macros and TAGBODY tags    
Date: 27 October 1982 0308-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Macros and TAGBODY tags

Shall it be permissible for a macro call to expand into a PROG tag?
(This question arises because macro calls may now expand into declarations.)
I am inclined to say no.

∂27-Oct-82  0012	Guy.Steele at CMU-10A 	SCALE-FLOAT and friends    
Date: 27 October 1982 0310-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: SCALE-FLOAT and friends

It was my brain-damage that caused the specification of FLOAT-FRACTION
as returning a number between 1/b (inclusive) and 1 (inclusive).
The latter word obviously should have been "exclusive".  Were both
bounds inclusive, I would have mentioned the qualifier only once.
I will make appropriate amends.
--Guy

∂27-Oct-82  0119	MOON at SCRC-TENEX 	SCALE-FLOAT and friends  
Date: Wednesday, 27 October 1982  04:15-EDT
From: MOON at SCRC-TENEX
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: SCALE-FLOAT and friends
In-reply-to: The message of 27 Oct 1982 0310-EDT () from Guy.Steele at CMU-10A

    Date: 27 October 1982 0310-EDT (Wednesday)
    From: Guy.Steele at CMU-10A
    To: common-lisp at SU-AI
    Subject: SCALE-FLOAT and friends

    It was my brain-damage that caused the specification of FLOAT-FRACTION
    as returning a number between 1/b (inclusive) and 1 (inclusive).
    The latter word obviously should have been "exclusive".  Were both
    bounds inclusive, I would have mentioned the qualifier only once.
    I will make appropriate amends.

I think you're wrong here.  In some floating-point formats, 2's-complement
for instance, the magnitude of the fraction can take on both endpoint
values.  Better to leave it inclusive than to require an implementation
to put in special hair to avoid returning 1.

∂27-Oct-82  0138	MOON at SCRC-TENEX 	Macros and TAGBODY tags  
Date: Wednesday, 27 October 1982  04:18-EDT
From: MOON at SCRC-TENEX
to:   common-lisp at SU-AI
Subject: Macros and TAGBODY tags
In-reply-to: The message of 27 Oct 1982 0308-EDT () from Guy.Steele at CMU-10A

    Date: 27 October 1982 0308-EDT (Wednesday)
    From: Guy.Steele at CMU-10A

    Shall it be permissible for a macro call to expand into a PROG tag?
Absolutely not.

∂27-Oct-82  0141	Kent M. Pitman <KMP at MIT-MC> 	No. Don't let macros expand into prog tags.
Date: 27 October 1982 04:35-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject: No. Don't let macros expand into prog tags.
To: Guy.Steele at CMU-10A
cc: COMMON-LISP at SU-AI

No. Macros shouldn't be able to expand to prog tags. An example hopefully 
suffices:

(defmacro do-something-returning-*foo* (&rest ignore) ;dummy definition
 ; just return *foo* for now until we figure out how to implement the something
 '*foo*)

(defun huh? ()
  (prog ()
    (do-something-returning-*foo*) ;supposedly for side-effect
    ...))

this PROG should not be able to be said to have a *FOO* tag. There are probably
many macros that expand into symbols and macro writers should not have to take
the odd context of a prog body expansion into account.

note that this is not contradictory with the idea of letting macros expand
into declare forms because we allow macros to expand only into declare forms
or normal code, but never a mixture. so it's in the semantics of the macro
already that it will be used in a declare position or it won't. macro writers
will not be "surprised" by the context `declare-macros' expand in. the user
will know he has such a macro and will use it right. 

this could be better worded but i'm tired. i hope what i'm saying is 
sufficiently obvious that clarification won't be needed.
-kmp

ps macros expanding into prog tags would also thwart people who wanted to
   implement interpreted go by just doing memq in the relevant prog bodies.

∂27-Oct-82  0704	Scott E. Fahlman <Fahlman at Cmu-20c> 	Macros and TAGBODY tags   
Date: Wednesday, 27 October 1982  10:03-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Macros and TAGBODY tags


Only if it expands into the whole TAGBODY.
-- Scott

∂04-Nov-82  1413	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Destructuring   
Date: Thursday, 4 November 1982, 10:59-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Destructuring
To: common-lisp at su-ai

Did Common Lisp ever make any desicions regarding destructuring?  In
particular, do any forms do any destructuring at all, and, if so, do
they use the list-directed or evaluation-directed kind?

∂06-Nov-82  1314	Scott E. Fahlman <Fahlman at Cmu-20c> 	Destructuring   
Date: Saturday, 6 November 1982  16:12-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Cc:   common-lisp at SU-AI
Subject: Destructuring


I believe that there are currently no destructuring operations in the
white pages, though implementations are free to add these as
non-standard extensions (or to retain what they already have, if it is
consistent with the current white pages).  I think that the opposition
to destructuring in existing forms such as LAMBDA and LET was (and is)
both strong and deep-rooted.  Most of the opponents would go along with
adding a few new forms that do destructuring (DLET or whatever), but
these never got added.  Suggestions along these lines might make it into
next year's edition of the white pages, but it's too late for the current
go-round, I think -- it would take us awhile to converge on exactly what
destructuring should be used where.

-- Scott

∂08-Nov-82  1424	Guy.Steele at CMU-10A 	Mini-ballot 
Date:  8 November 1982 1649-EST (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Mini-ballot

Here are a few questions that I would like to have answers back
on *** no later than Wednesday evening, November 10 ***.

(1) On the question of function-specs (for things like
like being able to DEFUN a function directly onto a property):
Shall we adopt:
	(a) LISP Machine's style of function specs
		Example:  (DEFUN (:PROPERTY FOO BAR) ...)
	(b) SETF-style function specs
		Example:  (DEFUN (GET 'FOO 'BAR) ...)
	(c) No function specs
?

(2) This is a repetition of issue 11 on the October ballot.
On issue 10 we agreed that global variables shall by convention
have names that begin and end with an asterisk (for example,
*prinlevel*).  Issue 11 was the same question for constants,
and the results were less conclusive, with myself, Moon, Wholey,
and Dyer being the prime opposition to using asterisks.

There is a question as to whether the asterisks are meant to
mean "this is global" or "this is bindable".  Fahlman points
out that when referring to a global object he doesn't want to have
to remember whether it is bindable or not.  My main objection
to surrounding names of constants with asterisks is that T and NIL
would obviously have to be exceptions to the rule, and secondarily
that I prefer to make the distinction between variables and
constants in a visual manner.

Anyway, I'd like to get further feedback on this.
--Guy

∂08-Nov-82  1524	MOON at SCRC-TENEX 	Mini-ballot    
Date: Monday, 8 November 1982  18:10-EST
From: MOON at SCRC-TENEX
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Mini-ballot
In-reply-to: The message of 8 Nov 1982 1649-EST () from Guy.Steele at CMU-10A

(1)  (a) is the right thing.  (c) is okay for now if we can't get agreement.
(b) is wrong-headed and unacceptable.

(2)  I do not feel strongly that constants should not have asterisks,
but I would prefer that they don't so that there is a visual distinction
between constants and variables.  Sometimes it is hard to decide what it
is a constant and what it is a variable, but the Common-Lisp defined
constants such as PI would be better without asterisks.

We could consider a prefix convention for the system-dependent constants
such as MOST-POSITIVE-SINGLE-FLOAT.  I would prefer a package prefix such
as SYS: over the Lisp machine's % or NIL's *: for these.  No prefix would
also be okay.

∂08-Nov-82  1659	Skef Wholey <Wholey at CMU-20C> 	Mini-ballot 
Date: Monday, 8 November 1982  19:17-EST
From: Skef Wholey <Wholey at CMU-20C>
To:   Guy.Steele at CMU-10A
CC:   Common-Lisp at SU-AI
Subject: Mini-ballot

  (A) for #1, the Lisp Machine function specs look OK to me.

  I am attracted to the use of *'s because they emphasize the important events
of binding and refering to dynamic variables.  This emphasis would be lost if
system constants were named in a like manner.  The convention is one that is
certainly worth imitating in user code, as a matter of style.  Constants should
not be named with the * convention for the reason that their values ARE
constant -- no one is likely to clobber them.  Surrounding a name with *'s
makes it possible to determine at a glance whether someone could be clobbering
a variable of yours, or whether you could be tweaking something you shouldn't.

--Skef

∂08-Nov-82  1703	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Mini-ballot   
Date:  8 Nov 1982 1958-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: Mini-ballot
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 1649-EST

1) I think I want to vote 3.  I would prefer a separate function,
e.g. (DEFUN-PROP FOO BAR ...), if this is something we really want to
support.  However you ought to consider whether this can be done in
a system-independent fashion.  Presumably you don't define the way
DEFUN is implemented.  Thus you may use EXPR properties or function
definition cells.  So if I specify (:PROPERTY FOO BAR), what is the
value?  A LAMBDA form?  Or possibly something to indicate whether it
is EXPR or MACRO, e.g. (EXPR LAMBDA ...)?  Unless you want to define
the internal form of a function definition (which I would strongly
oppose), the value is likely to be installation dependent.  If so,
then you had better define what it can be used for.  Do you gurantee
that we can always do (APPLY (GET 'FOO 'BAR) args)?  (Not very good
if the property is (EXPR LAMBDA ...))  It is one thing to hide the
implementation of DEFUN.  But it is not good to have a property whose
exact form is undefined.  Thus I recommend against considering this
feature to be part of the white pages.

2) I vote for using a different special character for constants. I think
somebody proposed # #.  I consider it good programming practice to use a
special character to begin all specials, even ones that the user
defines, just so it is immediately obvious to anyone reading the code.  
In addition to that general consideration, it is helpful to emphasize
that this is a system variable.  At a minimum it prevents the user
from choosing the same name himself... 
-------

∂08-Nov-82  1711	Eric Benson <BENSON at UTAH-20> 	Re: Mini-ballot  
Date:  8 Nov 1982 1810-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: Mini-ballot
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 1449-MST

(1) It should not be necessary to extend DEFUN in this manner.

(SETF (GET 'FOO 'BAR) #'(LAMBDA ...))

should do exactly what you want.  Is there a problem with this?
-------

∂08-Nov-82  1744	Earl A. Killian <EAK at MIT-MC> 	Mini-ballot 
Date: 8 November 1982 20:43-EST
From: Earl A. Killian <EAK at MIT-MC>
Subject:  Mini-ballot
To: MOON at SCRC-TENEX
cc: common-lisp at SU-AI

    Date: Monday, 8 November 1982  18:10-EST
    From: MOON at SCRC-TENEX

    (1)  (a) is the right thing.  (c) is okay for now if we can't get agreement.
    (b) is wrong-headed and unacceptable.


This isn't very helpful without an explanation.  It may be that
adding a new mechanism for something (a) instead of using an old
one (b) is right, but since no one has given any motivation for
doing so, I am unsure what's right about it.

∂08-Nov-82  1743	ZVONA at MIT-MC 	Mini-ballot  
Date: Monday, 8 November 1982  20:39-EST
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Eric Benson <BENSON at UTAH-20>
Cc:   common-lisp at SU-AI, Guy.Steele at CMU-10A
Subject: Mini-ballot
In-reply-to: The message of 8 Nov 1982  20:10-EST from Eric Benson <BENSON at UTAH-20>

    Date: Monday, 8 November 1982  20:10-EST
    From: Eric Benson <BENSON at UTAH-20>
    To:   Guy.Steele at CMU-10A, common-lisp at SU-AI
    Re:   Mini-ballot

    (1) It should not be necessary to extend DEFUN in this manner.

    (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))

    should do exactly what you want.  Is there a problem with this?

You might as well say that DEFUN should be flushed in favor of 

(SETF (FSYMEVAL 'FOO) #'(LAMBDA ...))

I like the SETF proposal 1(b).  It decreases the amount of syntactic
hair in the language and SETF seems to do exactly what is needed.

Since all my friends dislike it, I must be missing something.

∂08-Nov-82  1756	Scott E. Fahlman <Fahlman at Cmu-20c> 	Mini-ballot
Date: Monday, 8 November 1982  20:56-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Mini-ballot


 (1) (b) is the right thing.  (c) is okay for now if we can't get agreement.
     (a) Still looks needlessly complex to me, though I could swallow it
     with a few simplifications and the elimination of the locative
     pointer business.  (MOON) is wrong-headed and unacceptable.

 (2) To me, the purpose of the asterisks is to flag those variables that
     are "property of Lisp" so that the user doesn't accidentally
     blunder into them.  I don't need to be reminded which things it
     makes sense to bind, once I see that the variable is part of the
     Lisp system, since that is obvious from the name of the variable.
     I could live with the opposite decision, to have no stars on Lisp
     constants, but would really hate to see them sprout additional
     syntax.

∂08-Nov-82  1803	Kent M. Pitman <KMP at MIT-MC>
Date: 8 November 1982 20:53-EST
From: Kent M. Pitman <KMP at MIT-MC>
To: Benson at UTAH-20
cc: Common-Lisp at SU-AI

In most current Lisp implementations, one cannot write
 (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))
unless he doesn't mind #'(LAMBDA ...) not being compiled. Toplevel
non-definitional forms are not compiled in Maclisp or LispM, for example.
Hence, without the existence of (DEFUN (:PROPERTY FOO BAR) ...), one
would have to write
   (DEFUN something ...)
   (SETF (GET 'FOO 'BAR) #'something)
which is a bit tedious.

I don't know if Common-Lisp has taken a stand on whether toplevel LAMBDAs
like this one get compiled. Discussion came up about it before. It's related
to the (PROGN 'COMPILE ...) issue and should probably be defined. I'm 
personally in favor of avoiding a (PROGN 'COMPILE ...) primitive
and compiling all toplevel forms. In such case, the SETF you show would be
technically correct, but it lacks the declarative appeal of being integrated
into a DEFUN.

The question, I guess, comes down to whether you think of what you're
doing as defining a function with a complex name or creating an
anonymous function and putting it in a complex place. I think there is
need for both and the two issues should be kept separate.

∂08-Nov-82  1846	MOON at SCRC-TENEX 	asterisks around variables    
Date: Monday, 8 November 1982  21:40-EST
From: MOON at SCRC-TENEX
To:   Scott E. Fahlman <Fahlman at Cmu-20c>
Cc:   common-lisp at SU-AI
Subject: asterisks around variables
In-reply-to: The message of 8 Nov 1982  20:56-EST from Scott E. Fahlman <Fahlman at Cmu-20c>

    Date: Monday, 8 November 1982  20:56-EST
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

     (2) To me, the purpose of the asterisks is to flag those variables that
         are "property of Lisp" so that the user doesn't accidentally
         blunder into them.

Hmm, that's an interesting and novel idea.  We handle that by having DEFVAR
complain if you define the same variable in more than one file, and by
using packages to decrease the likelihood of that.  The asterisks are not
there to distinguish the system's variables from the user's variables.
My philosophy is "the fewer magic distinctions between the system and the
user the better; anything the system can do the user should be able to
understand and to change."

∂08-Nov-82  1850	MOON at SCRC-TENEX 	function specs 
Date: Monday, 8 November 1982  21:16-EST
From: MOON at SCRC-TENEX
To:   HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 8 Nov 1982 1958-EST from HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

The issues you raise in your message, about system dependence of the
representation of functions, are PRECISELY the reason why there should
be function specs in the language, so that the user need not be aware
of the representation of functions.

Surely the :PROPERTY function spec must mean none other than "if you
do a GET, you will get something you can APPLY and FUNCALL."

∂08-Nov-82  1859	MOON at SCRC-TENEX 	function specs 
Date: Monday, 8 November 1982  21:16-EST
From: MOON at SCRC-TENEX
To:   HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 8 Nov 1982 1958-EST from HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

The issues you raise in your message, about system dependence of the
representation of functions, are PRECISELY the reason why there should
be function specs in the language, so that the user need not be aware
of the representation of functions.

Surely the :PROPERTY function spec must mean none other than "if you
do a GET, you will get something you can APPLY and FUNCALL."

∂08-Nov-82  2005	Scott E. Fahlman <Fahlman at Cmu-20c> 	Revised Mini-Ballot  
Date: Monday, 8 November 1982  23:05-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Revised Mini-Ballot


I find KMP's arguments against option B to be fairly convincing.  It
does not bother me much to have symbols be a special case, but the
business about quoting is serious.  I also believe that the function
specs should be statically analyzable, so we would have to constrain the
SETF forms to be compile-time constant, and that is pretty ugly.  There
is also the problem, mentioned by someone earlier, that the SETF form
makes the user see a level of implementation detail that the
function-spec proposal hides, namely where the function object really
goes.

C has two disadvantages: first, it does not provide for the common case
of wanting to store a compiled function under a property; second, it
will give rise to all sorts of incompatible ad hoc solutions.

So that leaves A.  Things like (defun (:property foo bar) ...) actually
look pretty good to me -- the intent is clear -- and it makes sense for
trace and friends to accept these forms.  I still resist the notion that
these are names, but that is just an issue of how they are explained,
not what the mechanism is.  I guess it also makes sense to make this
facility extensible, and for that we need something like the set of
machinery that Moon proposes.  (This extension stuff should be
documented in such a way that our canonical naive user understands that
he can safely ignore it.)  Of the pre-defined types in the Chine Nual,
we need only :PROPERTY and maybe :INTERNAL.  :LOCATION is clearly out
and :WITHIN and :METHOD should be extensions defined by non-white-pages
packages.

So, if it is kept as simple as possible and explained properly, I guess
I am now prepared to believe that A is best way to go.  (Moon is still
wrong-headed and unacceptable, however -- that HAS to be the wrong
head!)

On the issue of asterisks for constants, I have decided that I really
don't care at all, as long as the issue is settled quickly and
decisively.  I give Guy my proxy to choose between stars and no stars.
I would not like to see a new character convention introduced just for
constants, though.

-- Scott

∂08-Nov-82  2051	Glenn S. Burke <GSB at MIT-ML> 	Mini-ballot  
Date: 8 November 1982 23:49-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: Mini-ballot
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI


(1) A.

(2) Mostly i just want a decision made on this.  My feelings are,
approximately in decreasing order of strength:
    Specials should be textually distinguishable from non-specials;  this
significantly helps the case of a user blundering into a system variable
(or worse, constant) just by using it as a LOCAL variable;  this problem
is much more common than "redefining" it with DEFVAR.
    Those which are constants should be textually distinguishable
from those which are parameters.  I've gotten rather accustomed to the
"*" package of NIL in this regard.  Using SYS: simply limits the scope
of naming conflicts (as above) to those things which inherit from SYS
by default (depending on how such things work of course).  I could
see SYS:*MOST-POSITIVE-SINGLE-FLOAT* though, for something (parameter
or constant) which is system-dependent.
    Lastly, i feel rather badly about breaking the Maclisp system
parameters like BASE, IBASE, *NOPOINT, PRINLEVEL, etc.  It was only
the possibility that these would break anyway which has kept me from
dyking out SI:STANDARD-INPUT-RADIX and SI:STANDARD-OUTPUT-RADIX from NIL
and reinstalling IBASE and BASE.

∂08-Nov-82  2308	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: function specs
Date:  9 Nov 1982 0152-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: function specs
To: MOON at SCRC-TENEX at MIT-MC
cc: common-lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 2121-EST

I am perfectly willing to go with options A or B for DEFUN.  They seem
equally undesireable syntax.  However I would like to have someone define
what the construct for MACRO's, FEXPR's (if Common Lisp has such
things), and any other odd things that DEFUN can generate.  If it is not
possible to do that, then I think we would be better off using (PUTPROP
'FOO 'BAR '#(LAMBDA ...  Furthermore, I would like to request that the
this definition include a specification of the actual data structure to
be used for interpreted functions.  There are two good reasons for this:
  - One good thing about Lisp is supposed to be that programs can
	manipulate code, it seems bad to have functional objects (except
	for compiled code and possibly FUNARG's) be system-dependent.
	(The traditional representation is, of course, LAMBDA
	expressions.)  
  - It is one thing to hide the representation used by (DEFUN FOO, since
	the user can't directly access function definitions (unless he
	happens to know that EXPR properties are used in his
	implementation).  However by definition (DEFUN (:PROPERTY FOO BAR) ..
	is creating a user-visible data structure.  It would be a good
	practice to define what that data structure is.  Clearly in
	some cases (compiled code) it is not reasonable to do so, but
	for interpreted code I claim it is.

I think that in meeting this request you will find it necessary to
define either an MLAMBDA (a lambda for macro's) or a syntax like either
(LAMBDA (%MACRO L)... or (MACRO LAMBDA (L) ....  and the equivalent for
FEXPR's, etc. (if they exist).

This is the reason why I expessed some scepticism about the construct
initially.  

-------

∂09-Nov-82  0000	Guy.Steele at CMU-10A 	Remarks on mini-ballot
Date:  9 November 1982 0245-EST (Tuesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Remarks on mini-ballot

So far, the vote looks like it favors Lisp-Machine-style function specs
if any, and no asterisks around names of constants.

If it will set anyone's mind at rest about constants, the compiler can
detect accidental attempts to bind a constant locally and warn you, but
obviously can't do that for variables that are meant to be bound.  Thus,
from a robustness point of view, it is important to flag variables
visually, but less so to flag constants.

As for runction specs, I find persuasive the remark that if
	(DEFUN (GET FOO BAR) ...)  => (SETF (GET FOO BAR) ...)
then
	(DEFUN FOO ...)  => (SETF FOO ...)
but the latter isn't right.  I formerly favored SETF-style function
specs, but now see how wrong-headed I was.

However, the analogy above also indicates to me that function specs
like (:PROPERTY FOO BAR) really are a kind of generalized name for
a function.  If so, orthogonality demands that they be permissible
in a lot of places where currently I believe they are not in Lisp Machine
LISP:
(a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
(b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args).
(c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)
--Guy

∂09-Nov-82  0055	David A. Moon <Moon at SCRC-POINTER at MIT-MC> 	Remarks on mini-ballot
Date: Tuesday, 9 November 1982, 03:51-EST
From: David A. Moon <Moon at SCRC-POINTER at MIT-MC>
Subject: Remarks on mini-ballot
To: Guy.Steele at CMU-10A
Cc: common-lisp at SU-AI
In-reply-to: The message of 9 Nov 82 02:45-EST from Guy.Steele at CMU-10A

    Date:  9 November 1982 0245-EST (Tuesday)
    From: Guy.Steele at CMU-10A

    However, the analogy above also indicates to me that function specs
    like (:PROPERTY FOO BAR) really are a kind of generalized name for
    a function.  If so, orthogonality demands that they be permissible
    in a lot of places where currently I believe they are not in Lisp Machine
    LISP:
    (a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
It is.  I don't remember there ever being a time when it wasn't, although
I might be forgetting.
    (b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args).
    (c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)
These two aren't, on the theory that the name for a thing is not the thing.
I won't try to argue that this theory is right, but that's the way it is
right at the moment.  The lack of (c) actually required introducing a new
special form, MACROCALL, which is kind of like FUNCALL except that it works
for macros.  Of course if you think about it more precisely, and with proper
understanding of Lisp semantics, this means that MACROCALL is nothing whatever
like FUNCALL!  It's a macro that gets the macro definition of its first subform
and uses it to macro-expand the form.

∂09-Nov-82  0132	Guy.Steele at CMU-10A 	Re: Remarks on mini-ballot 
Date:  9 November 1982 0433-EST (Tuesday)
From: Guy.Steele at CMU-10A
To: David A. Moon <Moon@SCRC-POINTER at MIT-MC>
Subject: Re: Remarks on mini-ballot
CC: common-lisp at SU-AI
In-Reply-To: David A. Moon's message of 9 Nov 82 03:51-EST

I might believe that (APPLY '(:PROPERTY FOO BAR) args) shouldn't work,
on the basis of your argument that the name of the thing is not the same
as the thing (true enough), except that in LMLISP and in Common LISP
APPLY is willing to accept the name of the thing in lieu of the thing
(for example, (APPLY 'FOO args) instead of (APPLY #'FOO args)).
However, if you believe in the thing-name distinction, then it is
even more important that ((:PROPERTY FOO BAR) 3 5 :START 7) work
as a function call!  It has the name of the function first, and then
the argument forms.  It is entirely analogous to (FOO 3 5 :START 7).

∂09-Nov-82  0444	Scott E. Fahlman <Fahlman at Cmu-20c> 	Remarks on mini-ballot    
Date: Tuesday, 9 November 1982  07:44-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI, David A. Moon <Moon at SCRC-POINTER at MIT-MC>
Subject: Remarks on mini-ballot


I am really getting scared.  Allowing ((:property foo bar) ...) seems to
me to open up all sorts of evil and hairy possibilities.  I can't name
them right now, but I think they're out there and we should all think
hard before swallowing this.  If this turns out to be an error, it may
be too late to correct it by the time we realize the problem, since
we're going to press fairly soon.  Consistency is OK in its place, but
we shouldn't let it push us around.

-- Scott

∂09-Nov-82  0752	ZVONA at MIT-MC 	function specs    
Date: Tuesday, 9 November 1982  10:49-EST
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 9 Nov 1982 0245-EST () from Guy.Steele at CMU-10A

    However, the analogy above also indicates to me that function specs
    like (:PROPERTY FOO BAR) really are a kind of generalized name for
    a function.  If so, orthogonality demands that they be permissible
    in a lot of places where currently I believe they are not in Lisp Machine
    LISP:
    (a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
    (b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args)
    (c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)

Empirical evidence:

I've seen naive users trying to put function specs in places like these,
and losing, and wondering what they did wrong.

∂09-Nov-82  0803	ZVONA at MIT-MC 	function specs    
Date: Tuesday, 9 November 1982  10:49-EST
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 9 Nov 1982 0245-EST () from Guy.Steele at CMU-10A

    However, the analogy above also indicates to me that function specs
    like (:PROPERTY FOO BAR) really are a kind of generalized name for
    a function.  If so, orthogonality demands that they be permissible
    in a lot of places where currently I believe they are not in Lisp Machine
    LISP:
    (a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
    (b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args)
    (c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)

Empirical evidence:

I've seen naive users trying to put function specs in places like these,
and losing, and wondering what they did wrong.

∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC>
Date: 8 November 1982 20:53-EST
From: Kent M. Pitman <KMP at MIT-MC>
To: Benson at UTAH-20
cc: Common-Lisp at SU-AI

In most current Lisp implementations, one cannot write
 (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))
unless he doesn't mind #'(LAMBDA ...) not being compiled. Toplevel
non-definitional forms are not compiled in Maclisp or LispM, for example.
Hence, without the existence of (DEFUN (:PROPERTY FOO BAR) ...), one
would have to write
   (DEFUN something ...)
   (SETF (GET 'FOO 'BAR) #'something)
which is a bit tedious.

I don't know if Common-Lisp has taken a stand on whether toplevel LAMBDAs
like this one get compiled. Discussion came up about it before. It's related
to the (PROGN 'COMPILE ...) issue and should probably be defined. I'm 
personally in favor of avoiding a (PROGN 'COMPILE ...) primitive
and compiling all toplevel forms. In such case, the SETF you show would be
technically correct, but it lacks the declarative appeal of being integrated
into a DEFUN.

The question, I guess, comes down to whether you think of what you're
doing as defining a function with a complex name or creating an
anonymous function and putting it in a complex place. I think there is
need for both and the two issues should be kept separate.

∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC> 	Mini-ballot  
Date: 8 November 1982 20:54-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  Mini-ballot
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

(1) My experience with LispM function specs leads me to believe that 
    something along these lines is worthwhile. I waver between saying "yes"
    to (c) because I am not firm on the details and it might be better to
    wait and (a) because I know it's a valuable tool and I've seen what 
    happens when you don't have it. With regard to (b), I object rather 
    strongly on the following counts:

     * I would prefer that they be statically analyzable. I can figure out
       at code analysis time (eg, compile time or at the time I'm reading 
       someone else's code) what (DEFUN (GET 'FOO 'BAR) ...) means. And have
       a pretty good idea of what the code is trying to say. But if the
       person does (DEFUN (GET FOO BAR) ...), I can analyze this code only
       formally and have no good feeling for what it's going to do. 
       I think definitional forms should try to stay simple and the programmer
       should write (SETF (GET FOO BAR) #'(LAMBDA ...)) in the few cases 
       where he needs it.

       I would be uncomfortable with special-casing (ie, requiring) QUOTE
       in this kind of form, so restricting things to the (GET 'FOO 'BAR)
       case will not make me feel better.

     * If (DEFUN (GET 'FOO 'BAR) (X) X) means (SETF (GET 'FOO 'BAR)
						    #'(LAMBDA (X) X))
       then (DEFUN F (X) X) should mean (SETF F #'(LAMBDA (X) X)) and
       not (SETF #'F #'(LAMBDA (X) ...)). This incompatibility bothers me.

    I'd like to see a concrete proposal for exactly what LispM style stuff
    we'd put in before I vote for (a) over (c), however.

    A more conservative alternative is to go the Maclisp route and say that
    the useful case of DEFUN'ing properties can be done by
	(DEFUN (sym prop) bvl . body)
    and not go for either the function spec or the SETF approach for now
    until more thinking has been done. This syntax would be fairly easily
    upgraded later if people were encouraged to never use a sym which was
    on the keyword package in such a DEFUN so that later upgrading if desired
    could be done in an upward compatible fashion.
    This is preferable in my mind to HEDRICK's (DEFUN-PROP ...) proposal 
    because it is not as verbose and it is upward compatible in a way that
    doesn't introduce arbitrarily many new operators.

(2) I guess I buy the argument that constants oughtn't have *'s around them.
    Knowing by looking at a thing whether it's intended to be bound is 
    certainly a useful property.

∂09-Nov-82  1603	Eric Benson <BENSON at UTAH-20> 	#'(LAMBDA ...) ==> CODE    
Date:  9 Nov 1982 1700-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: #'(LAMBDA ...) ==> CODE
To: KMP at MIT-MC
cc: Common-Lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 1853-MST

I believe any occurence of (FUNCTION (LAMBDA ...)) in a file at the top
level should be compiled when the file is compiled.  In fact any
occurences which are created by macroexpansion at the top level should
be compiled as well.  Are these to be called "subrs" or "code objects"
or what?
-------

∂09-Nov-82  1755	David.Dill at CMU-10A (L170DD60) 	mini-ballot
Date:  9 November 1982 2055-EST (Tuesday)
From: David.Dill at CMU-10A (L170DD60)
To: common-lisp at su-ai
Subject: mini-ballot
Message-Id: <09Nov82 205523 DD60@CMU-10A>

1. I am not convinced that the usefulness of SETF-like defun syntax
for putting the things where you want them, or for debugging, justifies
the extra hair and ugliness.  A case could be made that it's sociable
to name your functions if you want it to be easy to debug code that calls
them.  In common lisp, you can even have named lambda expressions
without doing a DEFUN.

2. Since the special declarations generated by DEFVAR are pervasive, it
is relatively easy to bind a special accidentally, thinking that it's a
local variable.  The best solution to this sort of problem, and a lot
of others, would be to distinguish syntactically special bindings and
references from lexical ones.  Otherwise, a special/lexical naming
convention seems like the best thing (e.g. if the variable starts with
an "S", it's special).



∂09-Nov-82  1933	Guy.Steele at CMU-10A 	Named lambdas    
Date:  9 November 1982 2233-EST (Tuesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Named lambdas

In response to DILL's message: actually, NAMED-LAMBDA is not
presently in Common LISP, though Spice LISP does support it.
Should NAMED-LAMBDA be in Common LISP?
--Guy

∂09-Nov-82  2120	Guy.Steele at CMU-10A 	Quick query about CONSTANTP
Date: 10 November 1982 0006-EST (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Quick query about CONSTANTP

Sometimes it is useful to know whether a symbol is a constant
(for example, T, NIL, PI, MOST-POSITIVE-FIXNUM, :DIRECTORY, and so on).
How about a function CONSTANTP for this purpose?  (In particular,
the evaluator needs it for error-checking.)  It could be implemented
as a property-list chek, though for speed it would be nice if an
implementation could dig up a bit in the symbol itself.  This bit
would be set by DEFCONSTANT and when interning in the keyword package.
--Guy

∂09-Nov-82  2234	STEELE at CMU-20C 	New proposed evaluators   
Date: 10 Nov 1982 0133-EST
From: STEELE at CMU-20C
Subject: New proposed evaluators
To: common-lisp at SU-AI

There follow improved and corrected versions of the proposed model
evaluators for Common LISP.  Improvements include renaming of
the variable EVALHOOK to *EVALHOOK*, allowing macro calls to
expand into declarations, improved interaction of error handling
and lexical environments (many thanks to KMP), increased use of
speial variables in the second version, and many bug fixes.
---------------------------------------------------------------
;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a GO to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn venv fenv benv genv)
  (let ((*evalhook* hookfn)) (%eval exp venv fenv benv genv)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

;;; *EVAL looks useless here, but does more complex things
;;; in alternative implementations of this evaluator.

(defun *eval (exp venv fenv benv genv)
  (%eval exp venv fenv benv genv))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.

(defun %eval (exp venv fenv benv genv)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp venv fenv benv genv))
      (typecase exp
	;; A symbol is first looked up in the lexical variable environment.
	(symbol (let ((slot (assq exp venv)))
		  (cond ((and slot (not (null (cdr slot))))
			 (cadr slot))
			((boundp exp) (symbol-value exp))
			(t (cerror :unbound-variable
				   "The symbol ~S has no value"
				   exp)))))
	;; Numbers, strings, bit-vectors, and characters self-evaluate.
	((or number string bit-vector character) exp)
	;; Conses require elaborate treatment based on the car.
	(cons (typecase (car exp)
		;; A symbol is first looked up in the lexical function environment.
		;; This lookup is cheap if the environment is empty, a common case.
		(symbol
		 (let ((fn (car exp)))
		   (loop (let ((slot (assq fn fenv)))
			   (unless (null slot)
			     (return (case (cadr slot)
				       (macro (%eval (%macroexpand
						      (cddr slot)
						      (if (eq fn (car exp))
							  exp
							  (cons fn (cdr exp))))))
				       (function (%apply (cddr slot)
							 (%evlis (cdr exp) venv fenv benv genv)
							 venv fenv benv genv))
				       (t <implementation-error>)))))
			 ;; If not in lexical function environment,
			 ;;  try the definition cell of the symbol.
			 (when (fboundp fn)
			   (return (cond ((special-form-p fn)
					  (%invoke-special-form
					   fn (cdr exp) venv fenv benv genv))
					 ((macro-p fn)
					  (%eval (%macroexpand
						  (get-macro-function (symbol-function fn))
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))
						 venv fenv benv genv))
					 (t (%apply (symbol-function fn)
						    (%evlis (cdr exp) venv fenv benv genv)
						    venv fenv benv genv)))))
			 (setq fn
			       (cerror :undefined-function
				       "The symbol ~S has no function definition"
				       fn))
			 (unless (symbolp fn)
			   (return (%apply fn
					   (%evlis (cdr exp) venv fenv benv genv)
					   venv fenv benv genv))))))
		;; A cons in function position must be a lambda-expression.
		;; Note that the construction of a lexical closure is avoided here.
		(cons (%apply (car exp)
			      (%evlis (cdr exp) venv fenv benv genv)
			      venv fenv benv genv))
		(t (%eval (cerror :invalid-form
				  "Cannot evaluate the form ~S: function position has invalid type ~S"
				  exp (type-of (car exp)))
			  venv fenv benv genv))))
	(t (%eval (cerror :invalid-form
			  "Cannot evaluate the form ~S: invalid type ~S"
			  exp (type-of exp))
		  venv fenv benv genv)))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms venv fenv benv genv)
  (mapcar #'(lambda (form) (%eval form venv fenv benv genv)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body venv fenv benv genv)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b) venv fenv benv genv))
	(%eval (car b) venv fenv benv genv))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (%apply fn
	  (cond ((null args*) firstarg)
		((null (cdr args*)) (cons firstarg (car args*)))
		(t (do ((x args* (cdr x))
			(z (cddr args*) (cdr z)))
		       ((null z)
			(rplacd x (cadr x))
			(cons firstarg (car args*))))))
	  nil nil nil nil))
!
;;; %APPLY does the real work of applying a function to a list of arguments.
;;; The environment is passed in because it leads to more natural error
;;; recovery.

(defun %apply (fn args venv fenv benv genv)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (%lambda-apply (interpreted-lexical-closure-function fn)
		    args
		    (interpreted-lexical-closure-venv fn)
		    (interpreted-lexical-closure-fenv fn)
		    (interpreted-lexical-closure-benv fn)
		    (interpreted-lexical-closure-genv fn)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args venv fenv benv genv))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args venv fenv benv genv)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args venv fenv benv genv)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args venv fenv benv genv))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %BIND-VAR).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args venv fenv benv genv)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (%lambda-apply-1 lexp args venv fenv benv genv)))
    (if (and (consp lexp) (eq (car lexp) 'lambda))
	(%lambda-apply newfn newargs venv fenv benv genv)
	(%apply newfn newargs venv fenv benv genv))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (lexp oldargs reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   lexp reason)
   oldargs))

;;; (%BIND-VAR VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %bind-var (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar specials) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(push (if specp (list ,xvar) (list ,xvar ,xvalue)) venv)
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defun %lambda-apply-1 (lexp args venv fenv benv genv)
  (cond ((or (not (consp lexp))
	     (not (eq (car lexp) 'lambda))
	     (atom (cdr lexp))
	     (not (listp (cadr lexp))))
	 (%bad-lambda-exp lexp args "improper lambda-expression"))
	(t (do ((body (cddr lexp) (cdr body))
		(specials '()))
	       ((or (endp body) (not (consp (car body))))
		(%bind-required lexp args (cadr lexp) fenv benv genv venv args specials nil body))
	     (let ((form (macroexpand (car body))))
	       (cond ((or (not (consp form))
			  (not (eq (car form) 'declare)))
		      (return (%bind-required lexp args (cadr lexp) fenv benv genv venv args specials form body)))
		     (t (dolist (decl (cdar form))
			  (when (eq (car decl) 'special)
			    (setq specials
				  (if (null specials)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) specials))))))))))))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp lexp oldargs "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional lexp oldargs varlist venv fenv benv genv args specials form body))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%varbind (car varlist) (car args)
		      (%bind-required lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	(t (%try-rest lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest lexp oldargs varlist venv fenv benv genv args specials form body)
			(%process-optional lexp oldargs varlist venv fenv benv
					   genv args specials form body varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional lexp oldargs varlist venv fenv benv
				       genv args specials form body
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (lexp oldargs varlist venv fenv benv genv args specials form body var init varp)
  (let ((value (if (null args) (%eval init venv fenv benv genv) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body))
	  (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%try-key lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp lexp oldargs "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn form body venv fenv benv genv))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
		   (t (%bad-lambda-exp lexp oldargs "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&key)
	 (%bind-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body nil))
	(t (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (lexp oldargs varlist venv fenv benv genv args specials form body keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords lexp args keys)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords lexp args keys)
			       (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))
			      ((endp (cdr varlist))
			       (%lambda-evprogn form body venv fenv benv genv))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
			      (t (%bad-lambda-exp lexp oldargs "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key lexp oldargs varlist venv fenv benv
				      genv args specials form body keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key lexp oldargs varlist venv fenv benv
				  genv args specials form body keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keyword arguments.

(defun %check-for-bad-keywords (lexp args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      lexp (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
		       form body keys kwd var init varp
		       (%eval init venv fenv benv genv) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
			      form body keys kwd var init varp
			      (cadr a) t)))))

(defun %process-key-1 (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))
	(%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
	(t (%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((endp varlist)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword")
			(%process-aux lexp oldargs varlist venv fenv benv
				      genv specials form body varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux lexp oldargs varlist venv fenv benv
				       genv specials form body
				       (car varspec)
				       (cadr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (lexp oldargs varlist venv fenv benv genv specials form body var init)
  (%varbind var (and init (%eval init venv fenv benv genv))
    (%bind-aux lexp oldargs varlist venv fenv benv genv specials form body)))

(defun %lambda-evprogn (form body venv fenv benv genv)
  (unless (null form) (%eval form venv fenv benv genv))
  (%evprogn body venv fenv benv genv))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) (venv fenv benv genv) obj)

(defspec function (fn) (venv fenv benv genv)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv venv
							:fenv fenv
							:benv benv
							:genv genv)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt) (venv fenv benv genv)
  (if (%eval pred venv fenv benv genv)
      (%eval con venv fenv benv genv)
      (%eval alt venv fenv benv genv)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body) (venv fenv benv genv)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (%evprogn body venv fenv (cons slot benv) genv))
		    (rplacd slot 'invalid))))

(defspec return (form) (venv fenv benv genv)
  (let ((slot (assq nil benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))

(defspec return-from (name form) (venv fenv benv genv)
  (let ((slot (assq name benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (not (eq (caar b) 'declare)))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body) (venv fenv benv genv)
  (do ((b body (cdr b))
       (marker (list nil)))
      ((endp p)
       (block exit
	 (unwind-protect
	  (loop (setq body
		      (catch marker
			(do ((b body (cdr b)))
			    ((endp b) (return-from exit nil))
			  (unless (atom (car b))
			    (%eval (car b) venv fenv benv genv))))))
	  (rplaca marker 'invalid))))
    (when (atom (car b))
      (push (list* (car b) marker (cdr b)) genv))))

(defspec go (tag) (venv fenv benv genv)
  (let ((slot (assq tag genv)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
---------------------------------------------------------------
;;; This version uses some special variables to avoid passing stuff around.

;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; In this implementation, the four environment parts are normally
;;; kept in four special variables %VENV%, %FENV%, %BENV%, and %GENV%.
;;; (These are internal to the implementation, and are not meant to
;;; be user-accessible.)

(defvar %venv% nil)
(defvar %fenv% nil)
(defvar %benv% nil)
(defvar %genv% nil)

;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a go to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn %venv% %fenv% %benv% %genv%)
  (let ((*evalhook* hookfn))
	(%eval exp)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

(defun *eval (exp %venv% %fenv% %benv% %genv%)
  (%eval exp))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.  It evaluates EXP in
;;; the current lexical environment, assumed to be in %VENV%, etc.

(defun %eval (exp)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp %venv% %fenv% %benv% %genv%))
      (typecase exp
	;; A symbol is first looked up in the lexical variable environment.
	(symbol (let ((slot (assq exp %venv%)))
		  (cond ((and slot (not (null (cdr slot))))
			 (cadr slot))
			((boundp exp) (symbol-value exp))
			(t (cerror :unbound-variable
				   "The symbol ~S has no value"
				   exp)))))
	;; Numbers, strings, bit-vectors, and characters self-evaluate.
	((or number string bit-vector character) exp)
	;; Conses require elaborate treatment based on the car.
	(cons (typecase (car exp)
		;; A symbol is first looked up in the lexical function environment.
		;; This lookup is cheap if the environment is empty, a common case.
		(symbol
		 (let ((fn (car exp)))
		   (loop (let ((slot (assq fn %fenv%)))
			   (unless (null slot)
			     (return (case (cadr slot)
				       (macro (%eval (%macroexpand
						      (cddr slot)
						      (if (eq fn (car exp))
							  exp
							  (cons fn (cdr exp))))))
				       (function (%apply (cddr slot)
							 (%evlis (cdr exp))))
				       (t <implementation-error>)))))
			 ;; If not in lexical function environment,
			 ;;  try the definition cell of the symbol.
			 (when (fboundp fn)
			   (return (cond ((special-form-p fn)
					  (%invoke-special-form fn (cdr exp)))
					 ((macro-p fn)
					  (%eval (%macroexpand
						  (get-macro-function (symbol-function fn))
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))))
					 (t (%apply (symbol-function fn)
						    (%evlis (cdr exp)))))))
			 (setq fn
			       (cerror :undefined-function
				       "The symbol ~S has no function definition"
				       fn))
			 (unless (symbolp fn)
			   (return (%apply fn (%evlis (cdr exp))))))))
		;; A cons in function position must be a lambda-expression.
		;; Note that the construction of a lexical closure is avoided here.
		(cons (apply (car exp) (%evlis (cdr exp))))
		(t (%eval (cerror :invalid-form
				  "Cannot evaluate the form ~S: function position has invalid type ~S"
				  exp (type-of (car exp)))))))
	(t (%eval (cerror :invalid-form
			  "Cannot evaluate the form ~S: invalid type ~S"
			  exp (type-of exp)))))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms)
  (mapcar #'(lambda (form) (%eval form)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b)))
	(%eval (car b)))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (let ((%venv% nil) (%fenv% nil) (%benv% nil) (%genv% nil))
    (%apply fn
	    (cond ((null args*) firstarg)
		  ((null (cdr args*)) (cons firstarg (car args*)))
		  (t (do ((x args* (cdr x))
			  (z (cddr args*) (cdr z)))
			 ((null z)
			  (rplacd x (cadr x))
			  (cons firstarg (car args*)))))))))
!
;;; %APPLY does the real work of applying a function to a list of arguments.

(defun %apply (fn args)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (let ((%venv% (interpreted-lexical-closure-venv fn))
	   (%fenv% (interpreted-lexical-closure-fenv fn))
	   (%benv% (interpreted-lexical-closure-benv fn))
	   (%genv% (interpreted-lexical-closure-genv fn)))
       (%lambda-apply (interpreted-lexical-closure-function fn) args)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %varbind).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (let ((%venv% %venv%))
			     (%lambda-apply-1 lexp args))))
    (if (and (consp lexp) (eq (car lexp) 'lambda))
	(%lambda-apply newfn newargs)
	(%apply newfn newargs))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

(defvar %lexp%)
(defvar %oldargs%)

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   %lexp% reason)
   %oldargs%))

;;; (%varbind VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %varbind (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar %specials%) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(push (if specp (list ,xvar) (list ,xvar ,xvalue)) venv)
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defvar %specials%)
(defvar %form%)
(defvar %body%)

(defun %lambda-apply-1 (%lexp% %oldargs%)
  (cond ((or (not (consp %lexp%))
	     (not (eq (car %lexp%) 'lambda))
	     (atom (cdr %lexp%))
	     (not (listp (cadr %lexp%))))
	 (%bad-lambda-exp "improper lambda-expression"))
	(t (do ((%body% (cddr %lexp%) (cdr %body%))
		(%specials% '()))
	       ((or (endp %body%)
		    (not (listp (car %body%))))
		(let ((%form% nil))
		  (%bind-required (cadr %lexp%) %oldargs%)))
	     (let ((%form% (macroexpand (car %body%))))
	       (cond ((or (not (consp %form%))
			  (not (eq (car %form%) 'declare)))
		      (return (%bind-required (cadr %lexp%) %oldargs%)))
		     (t (dolist (decl (cdr %form%))
			  (when (eq (car decl) 'special)
			    (setq %specials%
				  (if (null %specials%)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) %specials%))))))))))))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional varlist args))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	  (t (%varbind (car varlist) (car args)
			(%bind-required (cdr varlist) (cdr args))))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (varlist args)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional (cdr varlist) args))
	(t (%try-rest varlist args))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest varlist args)
			(%process-optional varlist args varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional varlist args
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (varlist args var init varp)
  (let ((value (if (null args) (%eval init) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional (cdr varlist) (cdr args)))
	  (%bind-optional (cdr varlist) (cdr args))))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (varlist args)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest (cdr varlist) args))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	(t (%try-key varlist args))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (varlist args)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn%))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key (cdr varlist) args))
		   (t (%bad-lambda-exp "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (varlist args)
  (cond ((eq (car varlist) '&key)
	 (%bind-key (cdr varlist) args nil))
	(t (%try-aux varlist))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (varlist args keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords args keys)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords args keys)
			       (%try-aux varlist))
			      ((endp (cdr varlist))
			       (%lambda-evprogn%))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux (cdr varlist)))
			      (t (%bad-lambda-exp "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key varlist args keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key varlist args keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keywords.

(defun %check-for-bad-keywords (args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      %lexp% (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (varlist args keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 varlist args keys kwd var init varp (%eval init) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 varlist args keys kwd var init varp (cadr a) t)))))

(defun %process-key-1 (varlist args keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key varlist args (cons kwd keys)))
	(%bind-key varlist args (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (varlist)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux (cdr varlist)))
	(t (%bad-lambda-exp "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (varlist)
  (cond ((endp varlist)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp "unknown or misplaced lambda-list keyword")
			(%process-aux varlist varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux varlist (car varspec) (cadr varspec)))
		   (t (%bad-lambda-exp "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (varlist var init)
    (%varbind var (and init (%eval init))
       (%bind-aux varlist)))

(defun %lambda-evprogn ()
  (unless (null %form%) (%eval %form%))
  (%evprogn %body%))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) obj)

(defspec function (fn)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv %venv%
							:fenv %fenv%
							:benv %benv%
							:genv %genv%)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt)
  (if (%eval pred) (%eval con) (%eval alt)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (let ((%benv% (cons slot %benv%)))
			(%evprogn body)))
		    (rplaca (cdr slot) 'invalid))))

(defspec return (form)
  (let ((slot (assq nil %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))

(defspec return-from (name form)
  (let ((slot (assq name %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (not (eq (caar b) 'declare)))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body)
  (let ((%genv% %genv%))
    (do ((b body (cdr b))
	 (marker (list nil)))
	((endp p)
	 (block exit
	   (unwind-protect
	    (loop (setq body
			(catch marker
			  (do ((b body (cdr b)))
			      ((endp b) (return-from exit nil))
			    (unless (atom (car b))
			      (%eval (car b)))))))
	    (rplaca marker 'invalid))))
      (when (atom (car b))
	(push (list* (car b) marker (cdr b)) %genv%)))))

(defspec go (tag)
  (let ((slot (assq tag %genv%)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
-------

∂10-Nov-82  0037	JONL at PARC-MAXC 	Re: Quick query about CONSTANTP
Date: 10 NOV 1982 0037-PST
From: JONL at PARC-MAXC
Subject: Re: Quick query about CONSTANTP
To:   Guy.Steele at CMU-10A, common-lisp at SU-AI
cc:   JONL

In response to the message sent  10 November 1982 0006-EST (Wednesday) from Guy.Steele@CMU-10A

Interlisp-D has the (currently undocumented, but "upcoming")
function CONSTANTEXPRESSIONP; it works not only for symbols,
but for other forms such as (QUOTE FOO) and (CONSTANT (LIST 1 2))
-- the latter being somewhat like '#.(LIST 1 2) except that the
evaluation is performed at eval/compile time rather than readtime.
Ultimately CONSTANTEXPRESSIONP should even work of forms like
(COND ((EQ PI PI) 3) (T 4)), but its current status is more limited.

Just exactly how CONSTANTP, or CONSTANTEXPRESSIONP if you care to
follow the Interlisp pattern, is implemented for symbols is
probably not all that important.  But your suggestion of a bit
in the symbol header brings back memories of LISP1.5 which
had certain property names treated specially by the equivalent
of PUTPROP -- namely a word of bits that could be turned on
or off.  If efficiency is important in matters like these
(i.e., system properties whose values are always true or false),
them maybe it's not such a bad idea to have these  property
bits again.  But that's *if* ...

∂10-Nov-82  0526	Scott E. Fahlman <Fahlman at Cmu-20c> 	Quick query about CONSTANTP    
Date: Wednesday, 10 November 1982  08:27-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Quick query about CONSTANTP


I've got no problem with Constantp, or even with a requirement that
resetting a constant in the evaluator signals a correctable error.  I
don't want to do this check in compiled code right now.

-- Scott

∂10-Nov-82  0530	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Wednesday, 10 November 1982  08:30-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Named lambdas


NAMED-LAMBDA looks like a total crock to me, but we use it anyway.  It
is by far the simplest way for us to keep around the name (or I guess
the function spec) of a lambda for use by the debugger.  I guess this
could be done with a hash-table or something, but that is gruesome.
Our plan was to just use this internally in evaluated DEFUN, but maybe
it would be better to inform the users of this.

-- Scott

∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
Date: Wednesday, 10 November 1982, 10:46-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Named lambdas
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-reply-to: The message of 9 Nov 82 22:33-EST from Guy.Steele at CMU-10A

Yes, we should have NAMED-LAMBDA.  It is invaluable for debugging if you
ever use interpreted code.

CONSTANTP is OK with me; I have no strong feelings about it.

∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: Mini-ballot 
Date: Wednesday, 10 November 1982, 10:44-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Re: Mini-ballot
To: common-lisp at SU-AI
In-reply-to: The message of 8 Nov 82 19:58-EST from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>,
             The message of 8 Nov 82 20:10-EST from Eric Benson <BENSON at UTAH-20>,
             The message of 9 Nov 82 01:52-EST from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>,
             The message of 9 Nov 82 04:33-EST from Guy.Steele at CMU-10A,
             The message of 9 Nov 82 07:44-EST from Scott E. Fahlman <Fahlman at Cmu-20c>

    Date:  8 Nov 1982 1810-MST
    From: Eric Benson <BENSON at UTAH-20>
    (1) It should not be necessary to extend DEFUN in this manner.
    (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))
    should do exactly what you want.  Is there a problem with this?
Several.  Among others, a "definition" special form is parsable; on the Lispm
it records the source file name and checks for invalid redefinitions, etc.
I won't bother to go one since this seems to have been decided in the
right direction.

    Date:  8 Nov 1982 1958-EST
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
							 Do you gurantee
    that we can always do (APPLY (GET 'FOO 'BAR) args)?
We do guarantee that if you get a function object by calling the appropriate
function (the Lispm calls it FDEFINITION) on the function spec, then you
can apply what you got, but that doesn't mean we have to make any statements
about what you got.

    Date:  9 Nov 1982 0152-EST
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
				  However I would like to have someone define
    what the construct for MACRO's, FEXPR's (if Common Lisp has such
    things), and any other odd things that DEFUN can generate.  If it is not
    possible to do that, then I think we would be better off using (PUTPROP
    'FOO 'BAR '#(LAMBDA ...  
Pardon me, but this doesn't make any sense.  The function spec FOO refers
to the function "cell" of FOO, whether it holds a macro or a function or
whatever.  (defmacro (:property foo bar) xxx) would mean to put onto
foo's bar property the same object that (defmacro baz xxx) would have put
into foo's function "cell".  There aren't any alternative constructs for
macros.

			     Furthermore, I would like to request that the
    this definition include a specification of the actual data structure to
    be used for interpreted functions.  
Gee, I thought that defining the format of functions was exactly what you
didn't want to do.  However, FDEFINITION of a defined function-spec is
guaranteed to return a function, suitable for APPLY and FUNCALL; it
is NOT allowed to return (expr lambda ...) or anything like that.
So I think function specs are actually the way to solve the problems that
you are bringing up.

    Date:  9 November 1982 0433-EST (Tuesday)
    From: Guy.Steele at CMU-10A

    I might believe that (APPLY '(:PROPERTY FOO BAR) args) shouldn't work,

In the Lisp Machine, symbols are a special case:  it is defined that all
symbols are functions, and when applied, they apply their definition.
However, it is not defined that all function specs in general are
functions and do the analogous thing just the way symbols do.  Actually,
we could make this change if we wanted, simply by saying that it's
illegal to have a function spec that looks like (LAMBDA ...).  I'm not
convinced that this would be a good idea, though.

    However, if you believe in the thing-name distinction, then it is
    even more important that ((:PROPERTY FOO BAR) 3 5 :START 7) work
This is exactly what I argued, about a year or two ago.  It's the general
"normal evaluation"/"functional evaluation" distinction.  If #'(:property a b)
works then, by analogy, ((:property a b) ...) ought to work.  However:

    Date: Tuesday, 9 November 1982  07:44-EST
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    I am really getting scared.  Allowing ((:property foo bar) ...) seems to
    me to open up all sorts of evil and hairy possibilities.
This is what everybody else told me, including Moon.  My feeling on the
matter is that we did, frankly, leave a semantic asymmetry in the by
leaving it in its current state.  Zvona's argument that the users expect
((:property a b) ...) to work is an important one: this is an instance
of a fundamental principle of user-interface, which makes sense applied
to language design too.  I still feel that ((:property a b) ...) really
ought to work, but I have already accepted Fahlman's argument and am
slightly scared myself.  Note that I don't know what Moon thinks about
this; I haven't discused it with him in some time.

As for the asterisks issue, I abstain (I don't think I have anything
useful to contribute and you guys seem to have the issue under control).

∂11-Nov-82  0725	Masinter at PARC-MAXC 	Named lambdas    
Date: 11-Nov-82  7:26:02 PST (Thursday)
From: Masinter at PARC-MAXC
Subject: Named lambdas
To: common-lisp at SU-AI

I can nowhere find a description of NAMED-LAMBDA and its semantics.
I've made a guess, but it doesn't map very well into extant common-lisp
structures; e.g., who can see the name? I assume from the discussion
about debuggers that the name is dynamic in scope rather than lexical.

∂11-Nov-82  0750	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Thursday, 11 November 1982  10:47-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Named lambdas


Named-Lambda was invented by the Lisp Machine folk (I think).  The
syntax is

(NAMED-LAMBDA name arglist . body)

This works in all respects like a lambda, with the name being ignored.
The name is there solely for debugging.  The reason this exists is that
interpreted DEFUN can now put the named-lambda form in the function slot
of a symbol, with the name indicating the name of the function as seen
by DEFUN.  (I guess now this is a function-spec.)  No attempt is made to
keep this up to date if the form is passed around to other places.  At
various times in the interpreter, only the lambda or named-lambda form
is on the stack, and if it is a named-lambda, the debugger can say
something intelligent about what the function is.  In some
implementations, at least, it is very hard to recover the name of the
function in any other way -- it does not appear on the stack in any
meaningful form.  Assorted other code-browsing functions may also find
the name useful.

Since the name is just commentary, and doesn't really do anything, I
don't think that the scoping issues apply.  I'm not really sure whether
lambdas created inside a LABELS or some such would be named -- this
would be used so rarely that I don't really care.  The point is to do
something useful for the normal case of a DEFUN.

-- Scott

∂11-Nov-82  0824	Masinter at PARC-MAXC 	Re: Named lambdas
Date: 11-Nov-82  8:21:52 PST (Thursday)
From: Masinter at PARC-MAXC
Subject: Re: Named lambdas
In-reply-to: Fahlman's message of Thursday, 11 November 1982  10:47-EST
To: Scott E. Fahlman <Fahlman at Cmu-20c>
cc: Masinter, common-lisp at SU-AI

My reading of what you say is that, as far as the semantics of what is
accessible from common-lisp functions, the name in NAMED-LAMBDA is just 
commentary? You say how NAMED-LAMBDA is used, but not what it means.

I don't quite understand about interpreted DEFUNs. Do you mean

(DEFUN FOO (NAMED-LAMBDA FUM (A B C) --))

that the debugger will show FUM on the stack? There's nothing so far in common
lisp which had led me to believe that if you said

(DEFUN FOO (A B C) --) 

that the debugger COULDN'T tell that you were inside FOO; I don't believe
such enforced brain-damage should be in the spec for Common-Lisp.

Also: does NAMED-LAMBDA have a different meaning for compiled & interpreted code?
I.e., they get thrown away when you interpret?



∂11-Nov-82  0857	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Thursday, 11 November 1982  11:54-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Named lambdas


Yes, the name in named-lambda is just machine-readable commentary -- the
evaluator just ignores it.

(defun foo (a b c) ...)

puts

(NAMED-LAMBDA FOO (A B C) ...)

into the symbol-function slot of the symbol FOO, instead of the more
traditional

(LAMBDA (A B C) ...)

When the DEFUN gets compiled, the name is hidden in the compiled
function object, so similar debugging information is available.  In the
Spice Lisp implementation, at least, the LAMBDA form is on the stack,
but not the calling form, so it would be awkward (not impossible) to
recover the function name for debugging; the NAMED-LAMBDA hack solves
the problem.  This is something of a kludge, and I have no strong
opinion about whether it should be in the white pages or whether we
should just quietly do our dirty hacking behind the scenes.  The only
problem is that users might see named-lambdas on the stack and wonder
what is up, so they at least have to be documented in the red pages of
implementations that use this trick.

-- Scott

∂11-Nov-82  0943	Eric Benson <BENSON at UTAH-20> 	Re: Quick query about CONSTANTP 
Date: 11 Nov 1982 1042-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: Quick query about CONSTANTP
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-Reply-To: Your message of 9-Nov-82 2206-MST

Uh-oh, CONSTANTP is defined in Standard Lisp already and means
(AND (NOT (CONSP X)) (NOT (SYMBOLP X))).  If you put this in, please
call it something (slightly) different, e.g. CONSTANT-P.  By the way,
I do think this is a useful idea.  I think it's important not to leave
too much undefined in the standard.  For example, it would be very nice
if a function (not special form) were defined for defining macros, and
there should be some way to find out how many multiple values are
returned by a function without having to make a list of them.
-------

∂11-Nov-82  1253	Guy.Steele at CMU-CS-A 	Benson's remarks on CONSTANTP  
Date: 11 November 1982 1549-EST (Thursday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Benson's remarks on CONSTANTP
In-Reply-To: Eric Benson's message of 11 Nov 82 12:42-EST

I must say that when I hear the functio name CONSTANTP my first
thought is "Oh, that tells you whether or not something self-evaluates";
clearly Standard LISP has given that name its natural definition.
What I have proposes is probably better called CONSTANT-SYMBOL-P.
--Guy

∂11-Nov-82  1348	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
Date:     11 November 1982 1302-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  primitives
To:       Common-Lisp at SU-AI

I am somewhat concerned about the lack of primitives in Common-Lisp.
Usually the Common Lisp language design has been oriented toward
high-level features.  This is good, but it is not sufficient.  For
example, DEFCONSTANT was defined at a high-level; people thought about
what they wanted to write in their source programs and specified that as
the behavoir of DEFCONSTANT.  What bothers me is that no facilities were
provided so that the user could write DEFCONSTANT (or more likely, a
variant thereof) himself.  In this example, there is no function that
examines or sets a symbols constantness.  A recent proposal has asked
for CONSTANTP; if (SETF (CONSTANTP 'X) ...) also works, then I would be
satisfied in this case.

I think that are a number of other cases like this one.  We should take
a close look at the next language manual sent to us and try to identify
those high-level parts of the language that should be suplemented by
low-level primitives.  A good way to locate these is to look for
facilities that work only for unevaluated arguments (such as
DEFCONSTANT) or exist at only one of several levels of abstraction (such
as the compiler).

Some more examples:

- A lower-level interface to the compiler should exist.  How about
  something that takes a lambda expression and some other things (e.g. a
  name for debugging) and returns a compiled code object.

- I think DEFUN/DEFMACRO/DEFTYPE should be definable by the user in
  terms of functions with evaluated arguments.  They should be part of a
  Common Lisp library, and not implementation dependent.
  The recent suggestion to expand
  (DEFUN F ARGS BODY)
  into
  (SETF (SYMBOL-FUNCTION-VALUE 'F) #'(LAMBDA ARGS BODY))
  is simplistic, but this is not a fatal flaw.  There should be a
  function (ie. something that evaluates its arguments) like the LISPM's
  FDEFINE or FSET-CAREFULLY or whatever that sets a function cell with
  all the hair of remembering source files and giving warnings and
  whatever other objections were given against the simple SETF.

- Dynamic binding.  PROGV comes close to being a primitive, but is
  cumbersome and only works for the value cell of symbols.

∂11-Nov-82  1349	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
Date:     11 November 1982 1302-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  primitives
To:       Common-Lisp at SU-AI

I am somewhat concerned about the lack of primitives in Common-Lisp.
Usually the Common Lisp language design has been oriented toward
high-level features.  This is good, but it is not sufficient.  For
example, DEFCONSTANT was defined at a high-level; people thought about
what they wanted to write in their source programs and specified that as
the behavoir of DEFCONSTANT.  What bothers me is that no facilities were
provided so that the user could write DEFCONSTANT (or more likely, a
variant thereof) himself.  In this example, there is no function that
examines or sets a symbols constantness.  A recent proposal has asked
for CONSTANTP; if (SETF (CONSTANTP 'X) ...) also works, then I would be
satisfied in this case.

I think that are a number of other cases like this one.  We should take
a close look at the next language manual sent to us and try to identify
those high-level parts of the language that should be suplemented by
low-level primitives.  A good way to locate these is to look for
facilities that work only for unevaluated arguments (such as
DEFCONSTANT) or exist at only one of several levels of abstraction (such
as the compiler).

Some more examples:

- A lower-level interface to the compiler should exist.  How about
  something that takes a lambda expression and some other things (e.g. a
  name for debugging) and returns a compiled code object.

- I think DEFUN/DEFMACRO/DEFTYPE should be definable by the user in
  terms of functions with evaluated arguments.  They should be part of a
  Common Lisp library, and not implementation dependent.
  The recent suggestion to expand
  (DEFUN F ARGS BODY)
  into
  (SETF (SYMBOL-FUNCTION-VALUE 'F) #'(LAMBDA ARGS BODY))
  is simplistic, but this is not a fatal flaw.  There should be a
  function (ie. something that evaluates its arguments) like the LISPM's
  FDEFINE or FSET-CAREFULLY or whatever that sets a function cell with
  all the hair of remembering source files and giving warnings and
  whatever other objections were given against the simple SETF.

- Dynamic binding.  PROGV comes close to being a primitive, but is
  cumbersome and only works for the value cell of symbols.

∂12-Nov-82  0003	MOON at SCRC-TENEX 	Named lambdas  
Date: Friday, 12 November 1982  01:47-EST
From: MOON at SCRC-TENEX
To:   Scott E. Fahlman <Fahlman at Cmu-20c>
Cc:   common-lisp at SU-AI, Masinter at PARC-MAXC
Subject: Named lambdas
In-reply-to: The message of 11 Nov 1982  10:47-EST from Scott E. Fahlman <Fahlman at Cmu-20c>

Lambdas created by a LABELS would be named, with :INTERNAL function-specs.

Also note that in the Lisp machine the format got expanded to
(NAMED-LAMBDA (name . other-data) (args...) body...).  If Common Lisp
standardizes on NAMED-LAMBDA it should perhaps only have this format.
Other-data is used for dozens of things.

∂12-Nov-82  0100	MOON at SCRC-TENEX 	primitives, and dynamic binding    
Date: Friday, 12 November 1982  02:31-EST
From: MOON at SCRC-TENEX
To:   Earl A. Killian <Killian at MIT-MULTICS>
Cc:   Common-Lisp at SU-AI
Subject: primitives, and dynamic binding
In-reply-to: The message of 11 Nov 1982 1302-pst from Earl A. Killian            <Killian at MIT-MULTICS>

    Date:     11 November 1982 1302-pst
    From:     Earl A. Killian            <Killian at MIT-MULTICS>

    I am somewhat concerned about the lack of primitives in Common-Lisp.

I agree with you.  There is a problem, though, which is that if you specify
too many primitives you put a lot of constraints on the implementation.  This
doesn't apply to all of the specific points you brought up in your message,
though.

I think at this point the best thing would be to recognize that we are
specifying the first version of Common Lisp, and contrary to what it says
about stability in the front of the manual, there is going to be a fairly
large update in 6 months to a year.  It might be easier to put in the missing
primitives then.  Of course the danger of this is that each implementation
will have its own slightly incompatible primitives already by then.  But this
isn't really different from the situation we started with, with multiple
incompatible dialects.  If people are willing to be flexible we can adjust
our primitives to meet a common standard, or argue when techniques used in
a particular implementation rule out adherence to the proposed standard.

I do think it is important for the long-term success of the language that
as few of the underlying primitives as possible be concealed from the user.

    - Dynamic binding.  PROGV comes close to being a primitive, but is
      cumbersome and only works for the value cell of symbols.

This is a good case in point.  I would agree with you that there should be a
true binding primitive (although note that it would require adding locatives
to the language), however this would put fairly strong restrictions on
possible implementation techniques.  In fact the Common Lisp implementation
proposed for -your very own- machine can -only- bind the value cells of
symbols, because it uses deep binding, because it is a multi-processor with
a von Neumann memory.

∂12-Nov-82  0608	Kent M. Pitman <KMP at MIT-MC> 	primitives   
Date: 12 November 1982 09:08-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  primitives
To: Moon at SCRC-TENEX
cc: Common-Lisp at SU-AI

    Date: Friday, 12 November 1982  02:31-EST
    From: MOON at SCRC-TENEX

    ... there is going to be a fairly large update in 6 months to a year.  It
    might be easier to put in the missing primitives then.  Of course the
    danger of this is that each implementation will have its own slightly
    incompatible primitives already by then...

Agreed. But users take what comes if they rely on such things as are not
in the language spec even if they are in an implementation. I think we 
should certainly be willing to discuss proposals for standardizing on
primitives, but there is no reason we have to rush to any decisions. We 
should keep in mind that it's always easier to add new primitives than to
remove ones we decide should never have been... 

∂12-Nov-82  0932	Eric Benson <BENSON at UTAH-20> 	Re: primitives   
Date: 12 Nov 1982 1030-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: primitives
To: Killian at MIT-MULTICS, Common-Lisp at SU-AI
In-Reply-To: Your message of 11-Nov-82 1402-MST

Amen.  That's what I was getting at in my last message.  The number of
primitives that can't be written in the language itself can and should
be very small.  Now that controversies over user-level features seem
to be dying down, let's fill in the gaps.
-------

∂12-Nov-82  1000	Earl A. Killian            <Killian at MIT-MULTICS> 	NAMED-LAMBDA
Date:     12 November 1982 0931-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  NAMED-LAMBDA
To:       common-lisp at SU-AI

This is ok with me, but I would like to clarify some things about it.

Fahlman has said twice that you put (NAMED-LAMBDA name args . body) in
the function cell of symbols.  That may be true on the LispM or PERQ,
but on a conventional architecture I'd never put anything but a compiled
function pointer in the function cell in order to keep function calling
fast. Instead, I'd have interpreted DEFUN create a tiny compiled transfer
function to an EVAL entrypoint with the lambda expression as an
argument.  And actually it wouldn't be DEFUN that did this: the compiled
transfer function would be the result of evaluating a LAMBDA or
NAMED-LAMBDA.  This is actually a good argument against allowing
(APPLY '(LAMBDA ...) ...) since that implies that
(SETF (SYMBOL-FUNCTION-VALUE 'F) '(LAMBDA ...)) will work.  I'd be very
upset if Common-Lisp tried to force that on an implementation.  For
efficiency on a conventional architecure, I'd also make all functions be
closures, i.e. have a lexical environment, even if it is ().  That's
another reason not to put lambda forms into function cells.

Thus, on conventional machines, users would almost never see
NAMED-LAMBDAs.  The name for debugging would be presumably be retreived
from this compiled transfer function.  The only use of NAMED-LAMBDA is
as a way for DEFUN to communicate the name to whatever creates the
transfer code.

∂12-Nov-82  1025	Earl A. Killian            <Killian at MIT-MULTICS> 	#,
Date:     12 November 1982 1021-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  #,
To:       common-lisp at SU-AI

Shouldn't #, be a reader abbreviations for some form just like ' is?
Otherwise, how do you have a macro that uses the load-time-eval facility
for constructed code?

∂12-Nov-82  1231	MOON at SCRC-TENEX 	NAMED-LAMBDA and function cells    
Date: Friday, 12 November 1982  15:23-EST
From: MOON at SCRC-TENEX
To:   Earl A. Killian <Killian at MIT-MULTICS>
Cc:   common-lisp at SU-AI
Subject: NAMED-LAMBDA and function cells
In-reply-to: The message of 12 Nov 1982 0931-pst from Earl A. Killian            <Killian at MIT-MULTICS>

    Date:     12 November 1982 0931-pst
    From:     Earl A. Killian            <Killian at MIT-MULTICS>

    This is actually a good argument against allowing
    (APPLY '(LAMBDA ...) ...)

Now there's a significant break with the past!

The rest of your message is a result of confusing two different meanings for
the term "function cell."  One is an internal object of the implementation,
the part of a symbol through which calls to a function named by that symbol
indirect.  The other is that conceptual piece of storage manipulated by the
FDEFINE and FDEFINITION primitives, or (at a lower level) SYMBOL-FUNCTION-VALUE
and its SETF.  These happen to be the same in the Lisp machine, and I guess
in the PERQ, but there is no reason for them to be the same.  The former is
implementation-dependent and its goal is to make function calling efficient.
The latter is Common-Lisp-defined and its goal is to allow portable programs
to manipulate function definitions.  What the machine sees must be efficient;
what the user sees must be portable.  (Read "ought" for "must" if you like).

∂12-Nov-82  1327	Eric Benson <BENSON at UTAH-20> 	Re: NAMED-LAMBDA and function cells  
Date: 12 Nov 1982 1426-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: NAMED-LAMBDA and function cells
To: MOON at SCRC-TENEX at MIT-MC, Killian at MIT-MULTICS
cc: common-lisp at SU-AI
In-Reply-To: Your message of 12-Nov-82 1341-MST

If you like, this is another wart which has been retained in Common Lisp,
like (SYMBOLP ()).  I think most of us would agree that the Scheme
approach is much more sensible, since it eliminates the "name vs. use"
problem, as in (:PROPERTY FOO BAR), etc.  Like the () vs. NIL, this has
2 effects: confusing semantics and difficulty or inefficiency of
implementation.  Too bad, but that's the price of compatibility with the
past.

P.S. Brian Smith's thesis should be required reading (at least browsing)
for all of us.  I know we can't change Lisp too radically, but we should
be conscious of the kludges we are perpetuating.
-------

∂12-Nov-82  2157	STEELE at CMU-20C 	Revised evaluators   
Date: 13 Nov 1982 0054-EST
From: STEELE at CMU-20C
Subject: Revised evaluators
To: common-lisp at SU-AI

The enclosed two revised evaluators include changes for the following
bugs noted by Bawden:
(1) EVALHOOK was incorrectly hooking on the given form; it should only
hook on subforms.  To this end %EVAL was split into two parts %EVAL
and %EVAL1.
(2) Two ocurrences of LEXP in%LAMBDA-APPLY-1 should have been NEWFN.
(3) The PROG macro was failing to call MACROEXPAND when looking for
declarations.

Also, %VARBIND and %LAMBDA-APPLY-1 were changed, and a new function
%ADD-SPECIALS introduced, to fix a bug in the handling of SPECIAL
declarations.  One wants
	(DEFUN BLAG (X)
	  (DECLARE (SPECIAL *BARF*))
	  ...)
to cause *BARF* to be special in the body of BLAG even though BLAG does
not bind *BARF*.  The new evaluators should fix this problem.
--Guy
-------------------------------------------------------------
;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a GO to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn venv fenv benv genv)
  (let ((*evalhook* hookfn)) (%eval1 exp venv fenv benv genv)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

;;; *EVAL looks useless here, but does more complex things
;;; in alternative implementations of this evaluator.

(defun *eval (exp venv fenv benv genv)
  (%eval exp venv fenv benv genv))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.  It is split into two
;;; parts, with the main part called %EVAL1, for the benefit of EVALHOOK.

(defun %eval (exp venv fenv benv genv)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp venv fenv benv genv))
      (t (%eval1 exp venv fenv benv genv))))

(defun %eval1 (exp venv fenv benv genv)
  (typecase exp
    ;; A symbol is first looked up in the lexical variable environment.
    (symbol (let ((slot (assq exp venv)))
	      (cond ((and slot (not (null (cdr slot))))
		     (cadr slot))
		    ((boundp exp) (symbol-value exp))
		    (t (cerror :unbound-variable
			       "The symbol ~S has no value"
			       exp)))))
    ;; Numbers, strings, bit-vectors, and characters self-evaluate.
    ((or number string bit-vector character) exp)
    ;; Conses require elaborate treatment based on the car.
    (cons (typecase (car exp)
	    ;; A symbol is first looked up in the lexical function environment.
	    ;; This lookup is cheap if the environment is empty, a common case.
	    (symbol
	     (let ((fn (car exp)))
	       (loop (let ((slot (assq fn fenv)))
		       (unless (null slot)
			 (return (case (cadr slot)
				   (macro (%eval (%macroexpand
						  (cddr slot)
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))))
				   (function (%apply (cddr slot)
						     (%evlis (cdr exp) venv fenv benv genv)
						     venv fenv benv genv))
				   (t <implementation-error>)))))
		     ;; If not in lexical function environment,
		     ;;  try the definition cell of the symbol.
		     (when (fboundp fn)
		       (return (cond ((special-form-p fn)
				      (%invoke-special-form
				       fn (cdr exp) venv fenv benv genv))
				     ((macro-p fn)
				      (%eval (%macroexpand
					      (get-macro-function (symbol-function fn))
					      (if (eq fn (car exp))
						  exp
						  (cons fn (cdr exp))))
					     venv fenv benv genv))
				     (t (%apply (symbol-function fn)
						(%evlis (cdr exp) venv fenv benv genv)
						venv fenv benv genv)))))
		     (setq fn
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
		     (unless (symbolp fn)
		       (return (%apply fn
				       (%evlis (cdr exp) venv fenv benv genv)
				       venv fenv benv genv))))))
	    ;; A cons in function position must be a lambda-expression.
	    ;; Note that the construction of a lexical closure is avoided here.
	    (cons (%apply (car exp)
			  (%evlis (cdr exp) venv fenv benv genv)
			  venv fenv benv genv))
	    (t (%eval (cerror :invalid-form
			      "Cannot evaluate the form ~S: function position has invalid type ~S"
			      exp (type-of (car exp)))
		      venv fenv benv genv))))
    (t (%eval (cerror :invalid-form
		      "Cannot evaluate the form ~S: invalid type ~S"
		      exp (type-of exp))
	      venv fenv benv genv))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms venv fenv benv genv)
  (mapcar #'(lambda (form) (%eval form venv fenv benv genv)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body venv fenv benv genv)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b) venv fenv benv genv))
	(%eval (car b) venv fenv benv genv))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (%apply fn
	  (cond ((null args*) firstarg)
		((null (cdr args*)) (cons firstarg (car args*)))
		(t (do ((x args* (cdr x))
			(z (cddr args*) (cdr z)))
		       ((null z)
			(rplacd x (cadr x))
			(cons firstarg (car args*))))))
	  nil nil nil nil))
!
;;; %APPLY does the real work of applying a function to a list of arguments.
;;; The environment is passed in because it leads to more natural error
;;; recovery.

(defun %apply (fn args venv fenv benv genv)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (%lambda-apply (interpreted-lexical-closure-function fn)
		    args
		    (interpreted-lexical-closure-venv fn)
		    (interpreted-lexical-closure-fenv fn)
		    (interpreted-lexical-closure-benv fn)
		    (interpreted-lexical-closure-genv fn)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args venv fenv benv genv))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args venv fenv benv genv)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args venv fenv benv genv)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args venv fenv benv genv))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %varbind).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args venv fenv benv genv)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (%lambda-apply-1 lexp args venv fenv benv genv)))
    (if (and (consp newfn) (eq (car newfn) 'lambda))
	(%lambda-apply newfn newargs venv fenv benv genv)
	(%apply newfn newargs venv fenv benv genv))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (lexp oldargs reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   lexp reason)
   oldargs))

;;; (%varbind VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %varbind (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar specials) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(unless specp (push (list ,xvar ,xvalue) venv))
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defun %lambda-apply-1 (lexp args venv fenv benv genv)
  (cond ((or (not (consp lexp))
	     (not (eq (car lexp) 'lambda))
	     (atom (cdr lexp))
	     (not (listp (cadr lexp))))
	 (%bad-lambda-exp lexp args "improper lambda-expression"))
	(t (do ((body (cddr lexp) (cdr body))
		(specials '()))
	       ((or (endp body) (not (consp (car body))))
		(%bind-required lexp args (cadr lexp)
				(%add-specials venv specials)
				fenv benv genv args specials nil body))
	     (let ((form (macroexpand (car body))))
	       (cond ((or (not (consp form))
			  (not (eq (car form) 'declare)))
		      (return (%bind-required lexp args (cadr lexp)
					      (%add-specials venv specials)
					      fenv benv genv args specials form body)))
		     (t (dolist (decl (cdar form))
			  (when (eq (car decl) 'special)
			    (setq specials
				  (if (null specials)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) specials))))))))))))

;;; %ADD-SPECIALS adds entries to VENV to account for SPECIAL declarations.

(defun %add-specials (venv specials)
  (do ((s specials (cdr s))
       (v venv (cons (list (car s)) v)))
      ((endp s) v)))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp lexp oldargs "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional lexp oldargs varlist venv fenv benv genv args specials form body))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%varbind (car varlist) (car args)
		      (%bind-required lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	(t (%try-rest lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest lexp oldargs varlist venv fenv benv genv args specials form body)
			(%process-optional lexp oldargs varlist venv fenv benv
					   genv args specials form body varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional lexp oldargs varlist venv fenv benv
				       genv args specials form body
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (lexp oldargs varlist venv fenv benv genv args specials form body var init varp)
  (let ((value (if (null args) (%eval init venv fenv benv genv) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body))
	  (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%try-key lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp lexp oldargs "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn form body venv fenv benv genv))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
		   (t (%bad-lambda-exp lexp oldargs "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&key)
	 (%bind-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body nil))
	(t (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (lexp oldargs varlist venv fenv benv genv args specials form body keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords lexp args keys)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords lexp args keys)
			       (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))
			      ((endp (cdr varlist))
			       (%lambda-evprogn form body venv fenv benv genv))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
			      (t (%bad-lambda-exp lexp oldargs "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key lexp oldargs varlist venv fenv benv
				      genv args specials form body keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key lexp oldargs varlist venv fenv benv
				  genv args specials form body keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keyword arguments.

(defun %check-for-bad-keywords (lexp args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      lexp (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
		       form body keys kwd var init varp
		       (%eval init venv fenv benv genv) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
			      form body keys kwd var init varp
			      (cadr a) t)))))

(defun %process-key-1 (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))
	(%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
	(t (%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((endp varlist)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword")
			(%process-aux lexp oldargs varlist venv fenv benv
				      genv specials form body varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux lexp oldargs varlist venv fenv benv
				       genv specials form body
				       (car varspec)
				       (cadr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (lexp oldargs varlist venv fenv benv genv specials form body var init)
  (%varbind var (and init (%eval init venv fenv benv genv))
    (%bind-aux lexp oldargs varlist venv fenv benv genv specials form body)))

(defun %lambda-evprogn (form body venv fenv benv genv)
  (unless (null form) (%eval form venv fenv benv genv))
  (%evprogn body venv fenv benv genv))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) (venv fenv benv genv) obj)

(defspec function (fn) (venv fenv benv genv)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv venv
							:fenv fenv
							:benv benv
							:genv genv)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt) (venv fenv benv genv)
  (if (%eval pred venv fenv benv genv)
      (%eval con venv fenv benv genv)
      (%eval alt venv fenv benv genv)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body) (venv fenv benv genv)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (%evprogn body venv fenv (cons slot benv) genv))
		    (rplacd slot 'invalid))))

(defspec return (form) (venv fenv benv genv)
  (let ((slot (assq nil benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))

(defspec return-from (name form) (venv fenv benv genv)
  (let ((slot (assq name benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (let ((x (macroexpand (car b))))
	     (or (atom x) (not (eq (car x) 'declare)))))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body) (venv fenv benv genv)
  (do ((b body (cdr b))
       (marker (list nil)))
      ((endp p)
       (block exit
	 (unwind-protect
	  (loop (setq body
		      (catch marker
			(do ((b body (cdr b)))
			    ((endp b) (return-from exit nil))
			  (unless (atom (car b))
			    (%eval (car b) venv fenv benv genv))))))
	  (rplaca marker 'invalid))))
    (when (atom (car b))
      (push (list* (car b) marker (cdr b)) genv))))

(defspec go (tag) (venv fenv benv genv)
  (let ((slot (assq tag genv)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
-------------------------------------------------------------
;;; This version uses some special variables to avoid passing stuff around.

;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; In this implementation, the four environment parts are normally
;;; kept in four special variables %VENV%, %FENV%, %BENV%, and %GENV%.
;;; (These are internal to the implementation, and are not meant to
;;; be user-accessible.)

(defvar %venv% nil)
(defvar %fenv% nil)
(defvar %benv% nil)
(defvar %genv% nil)

;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a go to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn %venv% %fenv% %benv% %genv%)
  (let ((*evalhook* hookfn))
	(%eval1 exp)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

(defun *eval (exp %venv% %fenv% %benv% %genv%)
  (%eval exp))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.  It is split into two
;;; parts, with the main part called %EVAL1, for the benefit of EVALHOOK.
;;; It evaluates EXP in the current lexical environment, assumed to be
;;; in %VENV%, %FENV%, %BENV%, and %GENV%.

(defun %eval (exp)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp %venv% %fenv% %benv% %genv%))
      (t (%eval1 exp))))

(defun %eval1 (exp)
  (typecase exp
    ;; A symbol is first looked up in the lexical variable environment.
    (symbol (let ((slot (assq exp %venv%)))
	      (cond ((and slot (not (null (cdr slot))))
		     (cadr slot))
		    ((boundp exp) (symbol-value exp))
		    (t (cerror :unbound-variable
			       "The symbol ~S has no value"
			       exp)))))
    ;; Numbers, strings, bit-vectors, and characters self-evaluate.
    ((or number string bit-vector character) exp)
    ;; Conses require elaborate treatment based on the car.
    (cons (typecase (car exp)
	    ;; A symbol is first looked up in the lexical function environment.
	    ;; This lookup is cheap if the environment is empty, a common case.
	    (symbol
	     (let ((fn (car exp)))
	       (loop (let ((slot (assq fn %fenv%)))
		       (unless (null slot)
			 (return (case (cadr slot)
				   (macro (%eval (%macroexpand
						  (cddr slot)
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))))
				   (function (%apply (cddr slot)
						     (%evlis (cdr exp))))
				   (t <implementation-error>)))))
		     ;; If not in lexical function environment,
		     ;;  try the definition cell of the symbol.
		     (when (fboundp fn)
		       (return (cond ((special-form-p fn)
				      (%invoke-special-form fn (cdr exp)))
				     ((macro-p fn)
				      (%eval (%macroexpand
					      (get-macro-function (symbol-function fn))
					      (if (eq fn (car exp))
						  exp
						  (cons fn (cdr exp))))))
				     (t (%apply (symbol-function fn)
						(%evlis (cdr exp)))))))
		     (setq fn
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
		     (unless (symbolp fn)
		       (return (%apply fn (%evlis (cdr exp))))))))
	    ;; A cons in function position must be a lambda-expression.
	    ;; Note that the construction of a lexical closure is avoided here.
	    (cons (apply (car exp) (%evlis (cdr exp))))
	    (t (%eval (cerror :invalid-form
			      "Cannot evaluate the form ~S: function position has invalid type ~S"
			      exp (type-of (car exp)))))))
    (t (%eval (cerror :invalid-form
		      "Cannot evaluate the form ~S: invalid type ~S"
		      exp (type-of exp))))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms)
  (mapcar #'(lambda (form) (%eval form)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b)))
	(%eval (car b)))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (let ((%venv% nil) (%fenv% nil) (%benv% nil) (%genv% nil))
    (%apply fn
	    (cond ((null args*) firstarg)
		  ((null (cdr args*)) (cons firstarg (car args*)))
		  (t (do ((x args* (cdr x))
			  (z (cddr args*) (cdr z)))
			 ((null z)
			  (rplacd x (cadr x))
			  (cons firstarg (car args*)))))))))
!
;;; %APPLY does the real work of applying a function to a list of arguments.

(defun %apply (fn args)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (let ((%venv% (interpreted-lexical-closure-venv fn))
	   (%fenv% (interpreted-lexical-closure-fenv fn))
	   (%benv% (interpreted-lexical-closure-benv fn))
	   (%genv% (interpreted-lexical-closure-genv fn)))
       (%lambda-apply (interpreted-lexical-closure-function fn) args)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %varbind).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (let ((%venv% %venv%))
			     (%lambda-apply-1 lexp args))))
    (if (and (consp newfn) (eq (car newfn) 'lambda))
	(%lambda-apply newfn newargs)
	(%apply newfn newargs))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

(defvar %lexp%)
(defvar %oldargs%)

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   %lexp% reason)
   %oldargs%))

;;; (%varbind VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %varbind (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar %specials%) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(unless specp (push (list ,xvar ,xvalue) venv))
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defvar %specials%)
(defvar %form%)
(defvar %body%)

(defun %lambda-apply-1 (%lexp% %oldargs%)
  (cond ((or (not (consp %lexp%))
	     (not (eq (car %lexp%) 'lambda))
	     (atom (cdr %lexp%))
	     (not (listp (cadr %lexp%))))
	 (%bad-lambda-exp "improper lambda-expression"))
	(t (do ((%body% (cddr %lexp%) (cdr %body%))
		(%specials% '()))
	       ((or (endp %body%)
		    (not (listp (car %body%))))
		(let ((%form% nil))
		  (%add-specials)
		  (%bind-required (cadr %lexp%) %oldargs%)))
	     (let ((%form% (macroexpand (car %body%))))
	       (cond ((or (not (consp %form%))
			  (not (eq (car %form%) 'declare)))
		      (%add-specials)
		      (return (%bind-required (cadr %lexp%) %oldargs%)))
		     (t (dolist (decl (cdr %form%))
			  (when (eq (car decl) 'special)
			    (setq %specials%
				  (if (null %specials%)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) %specials%))))))))))))

;;; %ADD-SPECIALS adds entries to VENV to account for SPECIAL declarations.

(defun %add-specials ()
  (dolist (s %specials%)
    (push (list s) %venv%)))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional varlist args))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	  (t (%varbind (car varlist) (car args)
			(%bind-required (cdr varlist) (cdr args))))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (varlist args)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional (cdr varlist) args))
	(t (%try-rest varlist args))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest varlist args)
			(%process-optional varlist args varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional varlist args
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (varlist args var init varp)
  (let ((value (if (null args) (%eval init) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional (cdr varlist) (cdr args)))
	  (%bind-optional (cdr varlist) (cdr args))))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (varlist args)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest (cdr varlist) args))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	(t (%try-key varlist args))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (varlist args)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn%))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key (cdr varlist) args))
		   (t (%bad-lambda-exp "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (varlist args)
  (cond ((eq (car varlist) '&key)
	 (%bind-key (cdr varlist) args nil))
	(t (%try-aux varlist))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (varlist args keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords args keys)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords args keys)
			       (%try-aux varlist))
			      ((endp (cdr varlist))
			       (%lambda-evprogn%))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux (cdr varlist)))
			      (t (%bad-lambda-exp "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key varlist args keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key varlist args keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keywords.

(defun %check-for-bad-keywords (args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      %lexp% (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (varlist args keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 varlist args keys kwd var init varp (%eval init) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 varlist args keys kwd var init varp (cadr a) t)))))

(defun %process-key-1 (varlist args keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key varlist args (cons kwd keys)))
	(%bind-key varlist args (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (varlist)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux (cdr varlist)))
	(t (%bad-lambda-exp "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (varlist)
  (cond ((endp varlist)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp "unknown or misplaced lambda-list keyword")
			(%process-aux varlist varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux varlist (car varspec) (cadr varspec)))
		   (t (%bad-lambda-exp "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (varlist var init)
    (%varbind var (and init (%eval init))
       (%bind-aux varlist)))

(defun %lambda-evprogn ()
  (unless (null %form%) (%eval %form%))
  (%evprogn %body%))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) obj)

(defspec function (fn)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv %venv%
							:fenv %fenv%
							:benv %benv%
							:genv %genv%)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt)
  (if (%eval pred) (%eval con) (%eval alt)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (let ((%benv% (cons slot %benv%)))
			(%evprogn body)))
		    (rplaca (cdr slot) 'invalid))))

(defspec return (form)
  (let ((slot (assq nil %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))

(defspec return-from (name form)
  (let ((slot (assq name %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (let ((x (macroexpand (car b))))
	     (or (atom x) (not (eq (car x) 'declare)))))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body)
  (let ((%genv% %genv%))
    (do ((b body (cdr b))
	 (marker (list nil)))
	((endp p)
	 (block exit
	   (unwind-protect
	    (loop (setq body
			(catch marker
			  (do ((b body (cdr b)))
			      ((endp b) (return-from exit nil))
			    (unless (atom (car b))
			      (%eval (car b)))))))
	    (rplaca marker 'invalid))))
      (when (atom (car b))
	(push (list* (car b) marker (cdr b)) %genv%)))))

(defspec go (tag)
  (let ((slot (assq tag %genv%)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
-------

∂13-Nov-82  0118	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	#,  
Date: Saturday, 13 November 1982, 04:16-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: #,
To: Earl A. Killian <Killian at MIT-MULTICS>
Cc: common-lisp at SU-AI
In-reply-to: The message of 12 Nov 82 13:21-EST from Earl A. Killian <Killian at MIT-MULTICS>

    Date:     12 November 1982 1021-pst
    From:     Earl A. Killian            <Killian at MIT-MULTICS>

    Shouldn't #, be a reader abbreviations for some form just like ' is?
    Otherwise, how do you have a macro that uses the load-time-eval facility
    for constructed code?

We use (CONS COMPILER:EVAL-AT-LOAD-TIME-MARKER form) for this.  There is
absolutely nothing special or good about the name (other than that it is
better than calling it SQUID).  Speaking of primitives, Common Lisp also
prevents the user from writing the #, macro himself by not providing a way
to tell whether you are reading normally, or reading forms to be compiled
into a file that will later be loaded into another environment.

∂13-Nov-82  0232	Kent M. Pitman <KMP at MIT-MC> 	#, 
Date: 13 November 1982 05:32-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  #,
To: Killian at MIT-MULTICS
cc: common-lisp at SU-AI

jmc - Of your message of 0232, 13 Nov., copying common-lisp, only the header
made it.
∂13-Nov-82  1044	JONL at PARC-MAXC 	Re: Named lambdas    
Date: 13 NOV 1982 1040-PST
From: JONL at PARC-MAXC
Subject: Re: Named lambdas
To:   Fahlman at CMU-20C, Masinter
cc:   common-lisp at SU-AI, JONL

In response to the message sent  Thursday, 11 November 1982  11:54-EST from Fahlman@Cmu-20c

I thought so.  Why not eliminate another proliferation of mindless
primitives, NAMED-LAMBDA, and just have DEFUN etc insert
a "commentary" in a local declaration.  For example,
    (DEFUN FOO (X) (LIST X))
becomes something like
    (SI:DEFEXPR 'FOO '(LAMBDA (X) (DECLARE (NAME FOO)) (LIST X)))

This "DECLARE" syntax is Interlisp's and MacLisp's, but no
objection to this way of nameing should be entertained on
the basis of local declaration syntax.

∂13-Nov-82  1128	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Saturday, 13 November 1982  14:27-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   JONL at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Named lambdas
In-reply-to: The message of 13 Nov 1982  13:40-EST from JONL at PARC-MAXC


The SI:DEFEXPR business confused me for awhile, but your basic
suggestion of hiding the name of the function in a declaration looks
good.  This would eliminate any need for NAMED-LAMBDA.  It might be
worthwhile to create a standard declaration form ("NAME" or
"FUNCTION-NAME" looks OK to me) to hold this sort of thing and explain
what it's for.  We already have the machinery to ignore declarations, so
this should add minimal new hair to any implementation.

-- Scott

∂13-Nov-82  1147	JONL at PARC-MAXC 	Re: Named lambdas    
Date: 13 NOV 1982 1148-PST
From: JONL at PARC-MAXC
Subject: Re: Named lambdas
To:   Fahlman at CMU-20C
cc:   common-lisp at SU-AI, JONL

In response to your message sent  Saturday, 13 November 1982  14:27-EST

Sorry for not making it more clear -- SI:DEFEXPR was just a
meta-name intended to imply it's action.

∂13-Nov-82  1516	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: Named lambdas  
Date: Saturday, 13 November 1982, 18:11-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Re: Named lambdas
To: Common-Lisp at SU-AI
In-reply-to: The message of 13 Nov 82 13:40-EST from JONL at PARC-MAXC

    Date: 13 NOV 1982 1040-PST
    From: JONL at PARC-MAXC

    Why not eliminate another proliferation of mindless
    primitives, NAMED-LAMBDA, and just have DEFUN etc insert
    a "commentary" in a local declaration.

This is a good idea, provided that there is a primitive defined to
extract the name buried in the declaration buried in the lambda.  It's
called SYS:FUNCTION-NAME in the Lisp machine; no really strong reason
why it isn't global.

If the Lisp machine LOCAL-DECLARATIONS mechanism were adopted, this would
also answer the other request for a way for macros to find out what function
they were inside, since they would do (CADR (ASSQ 'NAME LOCAL-DECLARATIONS)),
mutatis mutandis.

∂13-Nov-82  1950	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	implementing multiple values 
Date: Saturday, 13 November 1982, 22:42-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: implementing multiple values
To: Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>
Cc: common-lisp at SU-AI
In-reply-to: The message of 13 Nov 82 21:17-EST from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>

    Date: 13 Nov 1982 2117-EST
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

    E.g. consider the following example from Maclisp:
    (multiple-value-list (progn (values 'a 'b 'c) nil)) --> (nil b c)

Certainly the only sane and rational definition is that returning one
value by traditional Lisp and returning one value by using VALUES with
one argument must do the same thing.  The Maclisp implementation of
multiple values is broken; this is because it was kludged into an existing
implementation as a set of macros.

    It seems fairly clear that this should return either (nil) or (a b c).

The former.

    Probably the last two definitions are going to require that every
    value computation will interact with the m.v. mechanism, an overhead
    I would like to avoid.

Certainly.  But there is no run-time overhead, there is only the overhead of
making the interpreter and the compiler understand multiple values, rather
than kludging them in on top.

    (defun foo nil (values a b c))
    (defun bar nil (foo))
    (defun baz nil (multiple-value-list (bar]

(foo) and (bar) return the same 3 values, (baz) returns a list of them.

    (defun baz nil (multiple-value-list
		     (cond ((moon-phase) (foo))
			   (t  (trunc 5 2]

(baz) returns a different number of values depending on the predicate.

    (defun bar nil (cond ((moon-phase) (foo))
			 (t (trunc 5 2]
    (defun baz nil (multiple-value-list (bar]

This is the same as the previous example.

    (defun baz nil (multiple-value-list (progn (foo]

progn makes no difference.

    (defun baz nil (multiple-value-list (progn (foo) nil]

This returns a list of one element, NIL, of course.

You left out the only case that isn't obvious, namely

    (prog1 (foo) (bleagh))

I believe the current c.l. definition is that this returns one value, a,
and multiple-value-prog1 also exists and returns three values.


Maybe it would be instructive to look at how the Lisp machines (both of
them) implement multiple values.  Although these are machines specially
microcoded for Lisp, there is nothing microcode-dependent about this.
There is no extra overhead when multiple values are not being used.

When a function is called by a multiple value receiving form, a bit is
set somewhere in the stack frame.  This bit is in a place that gets
cleared for free when a function is called expecting only one value.
When a function is called tail-recursively, another bit is set.  When a
single value is returned from a function, these bits can be ignored.
When multiple values are returned, the microcode for that (and it could
just as well be a run-time support routine) follows back through
tail-recursive calls until it reaches the guy who is going to receive
the values, then checks his bit to see whether he wants multiple values.
If so, all the values are returned; if not, only the first value is
returned.

In practice there are some complexities about just where the values sit
while the stack is being unwound.  But these don't affect the semantics,
depend on implementation details, and in fact differ between the "A" and
"L" varieties of Lisp machines.  On a machine with enough general registers,
such as the pdp-10 or the VAX, you would probably put the values there.

Function-calling takes care of all cases of multiple values.  In the
interpreter, the function is always EVAL.  In compiled code, if the <form>
argument to MULTIPLE-VALUE or MULTIPLE-VALUE-BIND does not compile into
a function call, the compiler expands out the multiple value passing.
Thus (MULTIPLE-VALUE-BIND (A B C) (VALUES D E F) body) is just LET.

∂13-Nov-82  2158	Kim.fateman@Berkeley 	multiple-value return  
Date: 13-Nov-82 21:33:35-PST (Sat)
From: Kim.fateman@Berkeley
Subject: multiple-value return
Message-Id: <8210140532.2906@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A02900; 13-Nov-82 21:32:36-PST (Sat)
To: common-lisp@su-ai

It seems to me that the costs associated with doing this right can be
absorbed as Moon suggests, in microcode, but I am not convinced that the
costs can be easily borne in conventional machines.  Ordinarily a receiver
of a value will not know whether it must extract the first item in a multiple
value, or just use the non-multiple-value as given, unless some check
is performed.

What is the point of all this?  I see two points:  one: a minor convenience
for functions like divide (returning quotient and remainder), and its ilk
[its ilk growing extremely rapidly when hackers realize they can do this
free]; two: an important feature of a lisp where conses must be avoided.
Lisp Machines, esp. without garbage collectors, presumably benefit from the
avoidance of conses.  Lisps which must serve as system programming
languages (instead of using, say, C, which deals with call-by-reference
by the obvious kind of mechanism), is another possibility.

Let us turn the table a bit.  I believe that if conses/gc were really cheap,
there would be much less benefit to m-v-r.
e.g. divide could just return (quotient . remainder), other objects could
be cons'd up  (or put in vectors ...).  Now on conventional computers,
conses and gcs may not actually be so cheap, but if m-v-r is expensive,
perhaps conses WOULD be more acceptable? 

The constant overhead looking
for m-v-r in, for example, macsyma, which does not, at the moment, 
use m-v-r even once, would be distasteful. 

If m-v-r is free, of course, I suppose that's fine.  If it is not free,
perhaps it should be flushed from Common Lisp.

∂13-Nov-82  2207	Kim.fateman@Berkeley 	multiple-value return  
Date: 13-Nov-82 21:33:35-PST (Sat)
From: Kim.fateman@Berkeley
Subject: multiple-value return
Message-Id: <8210140532.2906@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A02900; 13-Nov-82 21:32:36-PST (Sat)
To: common-lisp@su-ai

It seems to me that the costs associated with doing this right can be
absorbed as Moon suggests, in microcode, but I am not convinced that the
costs can be easily borne in conventional machines.  Ordinarily a receiver
of a value will not know whether it must extract the first item in a multiple
value, or just use the non-multiple-value as given, unless some check
is performed.

What is the point of all this?  I see two points:  one: a minor convenience
for functions like divide (returning quotient and remainder), and its ilk
[its ilk growing extremely rapidly when hackers realize they can do this
free]; two: an important feature of a lisp where conses must be avoided.
Lisp Machines, esp. without garbage collectors, presumably benefit from the
avoidance of conses.  Lisps which must serve as system programming
languages (instead of using, say, C, which deals with call-by-reference
by the obvious kind of mechanism), is another possibility.

Let us turn the table a bit.  I believe that if conses/gc were really cheap,
there would be much less benefit to m-v-r.
e.g. divide could just return (quotient . remainder), other objects could
be cons'd up  (or put in vectors ...).  Now on conventional computers,
conses and gcs may not actually be so cheap, but if m-v-r is expensive,
perhaps conses WOULD be more acceptable? 

The constant overhead looking
for m-v-r in, for example, macsyma, which does not, at the moment, 
use m-v-r even once, would be distasteful. 

If m-v-r is free, of course, I suppose that's fine.  If it is not free,
perhaps it should be flushed from Common Lisp.

∂13-Nov-82  2355	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	multiple-value return   
Date: Sunday, 14 November 1982, 02:52-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: multiple-value return
To: Kim.fateman at UCB-C70
Cc: common-lisp at su-ai
In-reply-to: <8210140532.2906@UCBVAX.BERKELEY.ARPA>

    Date: 13-Nov-82 21:33:35-PST (Sat)
    From: Kim.fateman@Berkeley

    It seems to me that the costs associated with doing this right can be
    absorbed as Moon suggests, in microcode, but I am not convinced that the
    costs can be easily borne in conventional machines.  Ordinarily a receiver
    of a value will not know whether it must extract the first item in a multiple
    value, or just use the non-multiple-value as given, unless some check
    is performed.

Too bad you didn't read my message, which said not that costs can be absorbed
in microcode, but that there is absolutely nothing about the Lisp machine
implementation of multiple values that is dependent on having microcode
(unlike other Lisp machine features, invisible pointers for instance).

    I believe that if conses/gc were really cheap,
    there would be much less benefit to m-v-r.
    e.g. divide could just return (quotient . remainder), other objects could
    be cons'd up  (or put in vectors ...)

You certainly provided a fine argument for having multiple values here.  Compare
the last sentence in your first paragraph.  If divide returns two values, and you
only want one, you don't have to extract the first item in a multiple value, you
simply accept the first value and ignore the rest.  But if divide returns a cons
of the quotient and the remainder, and you only want the quotient you do have to
pay the overhead of extracting the quotient from that cons.  Not only is there
run-time overhead, there is conceptual overhead since now the packaging of the
multiple values is visible to the user.

Of course divide isn't a good example, because it surely open-codes and hence
generates different code depending on the number of values you ask for.

    The constant overhead looking
    for m-v-r in, for example, macsyma, which does not, at the moment, 
    use m-v-r even once, would be distasteful. 

The constant overhead is zero in any reasonable implementation of multiple
values.

∂14-Nov-82  0927	Martin.Griss <Griss at UTAH-20> 	Re: multiple-value return  
Date: 14 Nov 1982 1025-MST
From: Martin.Griss <Griss at UTAH-20>
Subject: Re: multiple-value return
To: Kim.fateman at UCB-C70
cc: Griss at UTAH-20, common-lisp at SU-AI
In-Reply-To: Your message of 13-Nov-82 2233-MST

I agree totally with Fateman; it seems these features are always added to support
some <1% code (if at all), that result in  alot of compiler hair just to
make the cost tolerable
-------

∂14-Nov-82  1012	Kim.fateman@Berkeley 	Re:  multiple-value return  
Date: 14-Nov-82 09:42:03-PST (Sun)
From: Kim.fateman@Berkeley
Subject: Re:  multiple-value return
Message-Id: <8210141741.18720@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A18697; 14-Nov-82 09:41:16-PST (Sun)
To: Moon@SCRC-TENEX@MIT-MC
Cc: common-lisp@su-ai

	
	The constant overhead is zero in any reasonable implementation of multiple
	values.
We seem to have different ground rules here.

Unless you remove all m-v stuff at compile time, I do not see how you can
write a Lisp that has m-v, which is as fast as a good one without m-v.
Since one can demonstrate the impossibility of total run-time removal,
Lisps with m-v will be slower.  And I believe this is whether or not
m-v are used.

If you are arguing that CL, or any "reasonable implementation" of lisp
already pays the run-time cost, that is a different argument.
(E.g. it has been argued that spaghetti stacks are free in interlisp
  because the cost has already been paid when implementing other features;
  yet overall, interlisp speed suffers somewhat for this generality.)

In summary:

In Franz and probably other VAX Lisps,
compiled access to a value on a stack is implemented
as an addressing mode: PART of a SINGLE INSTRUCTION!  If you can show how
to check for multiple-valued-ness without the execution of a single
instruction or the use of any data space, in a language not otherwise
encumbered, I will believe it is free.  If it is not free, I suggest
alternatives and justification be considered.

Note, I am not arguing against conceptual simplicity; in fact I
brought up the divide function to make that point.  If it is decided
that conceptual simplicity is worth doubling the time to access
values some percent of the time, fine.

∂14-Nov-82  1314	UCBERNIE.jkf@Berkeley (John Foderaro) 	m-v on conventional machines   
Date: 14-Nov-82 11:54:06-PST (Sun)
From: UCBERNIE.jkf@Berkeley (John Foderaro)
Subject: m-v on conventional machines
Message-Id: <8210141954.22028@UCBERNIE.BERKELEY.ARPA>
Received: by UCBERNIE.BERKELEY.ARPA (3.227 [10/22/82])
	id A22021; 14-Nov-82 11:54:14-PST (Sun)
Received: from UCBERNIE.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A00135; 14-Nov-82 12:55:05-PST (Sun)
To: common-lisp@su-ai

  I too must disagree with Moon's statement that m-v's are free on
conventional machines if the user doesn't use them:

1) You must put a special mark on the stack for every tail recursive
   call, whether you plan to use m-v's or not.  This is not free on
   conventional machines, and tail recursive calls happen often.

2) Lisps on conventional machines often have a mode which permits rapid
   execution at the price of losing the ability to interpret the stack's
   contents.  Since a m-v return requires being able to go back on the
   stack to find a possible m-v-b, such rapid execution modes would
   have to be forbidden, causing grief to those users who don't care
   about m-v's.   The difficulty of interpreting the stack's contents
   on conventional machines is compounded by the fact that the operating
   system often dumps data on the stack (during interrupts for example) and
   your lisp system will have to make sure that it ignores those stack
   frames.  Also, if you run multiple languages inside your lisp, then
   you will have stack frames whose form you have no way of predicting in
   advance.


As an exercise in futility, I will express my feelings on what m-v's should
do:
  m-v's should be a protocol for passing multiple values from callee to
caller.   If the caller does a m-v call and the last thing executed before
returning to the caller does a values, then the values will be transfered
back.  All other cases are undefined!!!!!   Like everything else in lisp, if
the user does something illegal it is his own fault and the system may or
may not catch it (depending on how expensive the checks are on a given
machine).  In a lisp on a conventional machine, the best place to check for
things like this

(multiple-value-list (progn (values 'a 'b 'c) nil)) --> (nil b c)

is not at runtime, but at compile time (or by using a special program which
does extensive type analysis of the source code).  Thus, since the above
example is illegal, its result is undefined, and so (nil b c) is as good a
value as any to return.



∂14-Nov-82  1350	Scott E. Fahlman <Fahlman at Cmu-20c> 	Multiple Values 
Date: Sunday, 14 November 1982  16:48-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Multiple Values


All of these arguments about multiple values are interesting, possibly
valid, and should be kept in mind the next time we design a new Lisp
system.  It is too late for us to seriously consider any changes in the
fundamental function-calling mechanisms of Common Lisp unless it is
shown that the current mechanisms are fatally flawed -- not just
inelegant or slightly inefficient on some architectures.

-- Scott

∂14-Nov-82  1535	HEDRICK at RUTGERS 	results of analyzing answers to my question about m.v.'s    
Date: 14 Nov 1982 1827-EST
From: HEDRICK at RUTGERS
To: common-lisp at SU-AI
Subject: results of analyzing answers to my question about m.v.'s
Message-ID: <"MS10(2117)+GLXLIB1(1135)" 11871971621.32.19.89560 at RUTGERS>

Having started this discussion on multiple values, I feel some
responsibility to prevent it from going off into unnecessary directions.
What I was trying to do was to determine what was needed to implement
m.v.'s.  Moon's response, as well as a private interchange with Steele,
gave the information I needed.  Since other people seem to share my
original concerns, it seems worthwhile telling everybody the design I
have arrived at from this information. To be honest, I would prefer to
see a definition wherein an m.v. producer is an error unless there was
some m.v. receiver there to receive it. That is easy to implement.  But
I am now convinced that there are designs for implementing the existing
C.L. semantics without incurring unreasonable overheads on conventional
machines.

Let me approach this by successive approximation.

Stage I.  M.v. producer is called only when there is an m.v. receiver
to receive the value.

The Maclisp implementation will work here.  (VALUES A B C) simply saves
away the values of A, B, and C in some global places.  MV-LIST (or
anything else) just takes values from that global places and returns
them.  In most cases this mechanism would suffice taken alone. However
there are a couple of cases (MVPROG1 and MVCALL) where  multiple values
have to be saved while an arbitrary computation is done.  Thus it is
probably best for the values to be stored on a stack.  This will allow
for the possibility that m.v.'s can be done recursively.  The simplest
implementation is to push the number of m.v.'s on the top of the stack.
As long as every m.v. producer has an m.v. consumer, this implementation
should be sound.

Stage II.  The real case.

The problem is that the receiver may not call the producer directly.
Furthermore, we have no way of getting rid of m.v.'s if they are
produced erroneously, e.g.
   (multiple-value-list (values a b c) nil)
Thus I propose the following:

  - VALUES and VALUES-LIST will produce multiple values only if they
	know they are going to be used
  - we establish a protocol that allows us to follow the stack to
	see whether they are going to be used

The trickiest part is the second.  This is going to require some care
in the translator, but I claim that it is not that complex.  We have
three categories of calls:

  - calls where multiple values are required.  These are calls
	made by MV-LIST, MV-BIND, etc. (the m.v. consumers).  If the
	thing called would not normally produce m.v.'s, we need to
	convert the single normal value to a single m.v.
  - calls where multiple values are not allowed.  There are calls
	such as all but the last in a PROGN, where any m.v.'s are
	discarded.
  - calls where m.v.'s are returned if available, but are not required.
	I have it on good authority that the only case where this applies
	is terminal calls, i.e. the last call in a function (last being
	judged in execution, not lexically.  e.g. in
		(defun foo nil (cond (x (bar)) (t (baz]
	(bar) is a terminal call.

Let's ignore the third case for the moment.  All we need is some way to
mark calls so VALUES can tell whether m.v.'s are really going to be
used.  Clearly we want to mark the calls where m.v.'s are going to be
used, as opposed to those where m.v.'s are not going to be used, since
we want the overhead to be confined to users of m.v.'s. On the PDP-10
the obvious way to do this is to put a special instruction after the
call.  One way to do this is to put a particular no-op after each such
call. (Since the PDP-10 has several million kinds of no-ops, we can
afford to use one as a flag.)  Then VALUES would simply look up the
stack and see if its return address points to such a no-op.  As it
happens, we will probably do something a bit trickier.  We will probably
use a call to a routine MAKE-MV.  Thus a call done inside MV-LIST would
look like
  (MULTIPLE-VALUE-LIST (FOO) (BAR))
	CALL FOO	;m.v.'s not needed - nothing special
	CALL BAR	;m.v.'s needed - flag it with CALL MAKE-MV
	CALL MAKE-MV
	CALL MULTIPLE-VALUE-LIST ;do the actual return of the m.v.'s

The idea is that when we return from BAR, we will do a skip return if
we are actually returning multiple values (I will show how that happens
in a minute).  In that case the m.v.'s are left as is.  If we are not
returning m.v's, we do the normal return, and fall into the call to
MAKE-MV.  MAKE-MV is the routine that takes the conventional single
value and stores it away as a single multiple value.  Clearly this is
going to have to be done anyway when m.v.'s are needed, so we might as
well use CALL MAKE-MV as the flag that m.v.'s are required.

Now, we have two ways of implementing this, either of which is fairly
easy:

1) make sure that all terminal calls are compiled as jumps.  This is
a fairly standard optimization.  If done reliably, it guarantees that
the third case I ignored above will never occur.  VALUES will simply
be able to look at the place where it called directly, with no fancy
stack chasing.  If the return address points to CALL MAKE-MV,
VALUES puts the m.v.'s onto the mv stack, and takes the skip return.
Otherwise it returns the first of the m.v.'s, ignores the rest, and
does a conventional return.  If you choose this implementation, then
you will have to look at forms such as MVPROG1, which explicitly pass on
m.v.'s in contexts other than terminal calls.  They will have to
do calls that require m.v.'s, save those m.v.'s, and then themselves
return as VALUES (or any other m.v. producer) would do (i.e. looking
at their return address and throwing away the m.v.'s if they are not
required).

2. Have VALUES detect terminal calls, and simply follow the stack up
until something is found which is not a terminal call.  Otherwise
do things as in 1.  (That is, once you find something other than a
terminal call, look to see whether the return address there points to
MAKE-MV...)  If you choose this implementation there is a simple
modification for handling MVPROG1 and similar forms.  Add yet another
special mark (i.e. a no-op used only for this), call it MVFLAG.

   (mvprog1 (foo) (bar))
	call foo
	mvflag
	push returned value
	call bar
	pop returned value
	return

If somewhere inside FOO there is a call to VALUES, the stack search
will detect MVFLAG as the next instruction after the return address.
MVFLAG will be treated like a terminal call, i.e. the stack search
will continue to see whether the caller of the MVPROG1 really needed
the m.v.'s or not.  If so, they will be put on the m.v. stack, and
then the caller will retrieve them.  (The call to BAR will not be
pass on m.v.'s because of the POP after it.  This POP prevents the
next thing from being a RETURN, and thus prevents it from looking
like a terminal call.)

This mechanism has the advantage that if my informants are wrong, and
there is some context other than terminal calls that preserves m.v.'s,
we can handle it by putting MVFLAG there.

Both of the mechanisms suggested have only slight overhead, and that
overhead exists only if m.v.'s are used.  The extra no-op's are used
only in code compiled for m.v. receivers (or constructions such as
MVPROG1 that explicitly protect m.v.'s).  The m.v. producers need
only look up the stack to see what to do.  m.v.'s are never produced
if they are going to be thrown away.  I think that these mechanisms,
or something closely related, should work on machines other than the 
PDP-10.

I am not pleased with this sort of hackery, but it is no worse than
that needed to implement default arguments, &REST, and funarg's.
I would rather see Lisp free from this sort of thing, but I think I
have shown that it is possible to do with acceptable overhead and
no increased complexity in the compiler (except that you must be
able to detect terminal calls, something that all compilers known to
me do anyway).


None the less, I do not accept the argument that it is too late to
eliminate M.V.'s from Common Lisp, should people decide to do so.
Clearly the time to eliminate things is now.  We will be able to add
things later, but not to remove them.  But you should realize that
I am really a reactionary.  If it came to a vote, I would vote against
default arguments, &REST, and multiple values.
   --------

∂14-Nov-82  2207	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	implementing multiple values
Date: 13 Nov 1982 2117-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: implementing multiple values
To: common-lisp at SU-AI

We have gotten to the place where I have to actually implement multiple
values.  I find that I need to know a bit more about what the semantics
are, and what compromises are and are not acceptable.  What I would love
to hear is that I can use the Maclisp implementation.  It is certainly
the obvious approach for a conventional machine:  VALUES just saves away
its arguments in some global place (global variables - probably we would
use a separate stack - it doesn't much matter).  Then MULTIPLE-VALUE-xxx
simply retrieves them and makes them into a list, binds variables to
them, etc.  The problem turns out to be knowing when it is safe to use
those stored-away values. E.g. consider the following example from Maclisp:

(multiple-value-list (progn (values 'a 'b 'c) nil)) --> (nil b c)

It seems fairly clear that this should return either (nil) or (a b c).
This seems like a simple bug in the Maclisp implementation.  But it
does illustrate the kind of problems that are going to come up.
I do need to know exactly how long multiple values last.  Here are
the definitions I can see as being reasonable, with the ones I
prefer first (as you might guess, this is simply in order of how easy
they are to implement):

  - an m.v. receiver is only valid when the most recent value computed
	was computed by an m.v. producer.  Other cases are errors, and
	the results are undefined.
  - an m.v. receiver returns the most recent values produced by an
	m.v. producer.  Other non-multiple-values produced in the
	interim are ignored.
  - an m.v. receiver returns the most recent value computed, m.v. or
	otherwise.
  - like the last, except that some constructs "kill" multiple values
	and some do not.  If this definition is used, we need a list
	of the ones that do and don't.

Probably the last two definitions are going to require that every
value computation will interact with the m.v. mechanism, an overhead
I would like to avoid.  At least this is true if m.v.'s can be survive
function returns.  Consider the following example:

    (defun foo nil (bar) 'success)

Since (BAR) may return multiple values, even something as simple as
'SUCCESS is going to have to explicitly do something to make sure that
any multiple values returned by BAR are no longer active.  Either that
or

   (defun foo nil (bar))

is going to have to do something explicit to make sure that if (BAR)
happens to return multiple values, they get returned.

In any case, I need a precise definition.  Can somebody help? The
following cases are given just to spark your thoughts, not to relieve
Guy of the need to give a  precise specification. Please assume that
functions stay defined until they are explicitly redefined.

1.

(defun foo nil (values a b c))
(defun bar nil (foo))
(defun baz nil (multiple-value-list (bar]

2.

(defun baz nil (multiple-value-list
		 (cond ((moon-phase) (foo))
		       (t  (trunc 5 2]

3.

(defun bar nil (cond ((moon-phase) (foo))
		     (t (trunc 5 2]
(defun baz nil (multiple-value-list (bar]

4.

(defun baz nil (multiple-value-list (progn (foo]

5.

(defun baz nil (multiple-value-list (progn (foo) nil]



-------

∂16-Nov-82  0848	Kent M. Pitman <KMP at MIT-MC> 	Multiple Value Return and Continuation Passing Style 
Date: 15 November 1982 06:34-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  Multiple Value Return and Continuation Passing Style
To: common-lisp at SU-AI

I guess it's worth noting just for completeness that there is an alternative
to the multiple-value-return idea which is suggested by continuation-passing
style a la Sussman/Steele papers... I take no stand on whether this would be
the right thing for Common-Lisp, but I point it out for completeness since
it involves no pervasive effect upon the whole interpreter to implement things
in this style. Here's an example from the preliminary T manual (May '82):

    (DIV2 n1 n2 proc)

     Division yielding quotient and remainder. Not yet implemented. The
     PROC should be a procedure of two arguments; it will be invoked on
     the quotient and remainder. For example:

      (DIV2 11 4 LIST)  => (2 3)
      (DIV2 11 4 PROJ0) => 2

Where PROJ0 is like the subr version of BLOCK0 (which is T's name for PROG1).

This is upward compatible with the LispM in that although it doesn't use 
multiple values at all, it can be implemented by taking advantage of 
functions that return them. eg, a sample LispM implementation would be:

 (DEFUN DIV2 (X Y FN)
   (MULTIPLE-VALUE-BIND (QUO REM)
       (QUOTIENT X Y)
     (FN QUO REM)))

Also, remember that constructs like:

 (MULTIPLE-VALUE-LIST (PROG1 (G) (H) (I)))

where (G) might return multiple values can always be re-written if G can
be made to accept a continuation arg as something like:

 (G #'(LAMBDA (&REST ARGS) (H) (I) ARGS))

The intent here is not to say this is what we should do, but just to make
sure we're not overly restricting our mode of thinking in this issue...
-kmp

∂16-Nov-82  0856	Kim.fateman@Berkeley 	multiple thanks   
Date: 15-Nov-82 08:53:20-PST (Mon)
From: Kim.fateman@Berkeley
Subject: multiple thanks
Message-Id: <8210151653.22738@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A22720; 15-Nov-82 08:53:18-PST (Mon)
To: hedrick@rutgers
Cc: common-lisp@su-ai

Thanks for presenting a proposed mechanism for multiple values which seems
to penalize the producers of multiple values (and the implementors of 
lisp systems).  Yet,now there is this hidden cost in
using some m-v producers: should one use them, since in some
circumstances they have to do a fair amount of stack-grovelling?
(e.g. one might think that "floor" would always be fairly cheap to use).

∂16-Nov-82  0859	Masinter at PARC-MAXC 	Named lambdas    
Date: 15-Nov-82 11:22:23 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Named lambdas
To: common-lisp at SU-AI

That the interpreter/compiled code forgets the name of the function you are executing in and/or the debugger has trouble finding it from looking at
the stack seems more like a lack of functionality on the part of the debugger.
Enough information is there to determine it (e.g., looking at the instruction 
preceding the return PC to see what function was called) that a kludge like
NAMED-LAMBDA doesn't seem at all a reasonable part of the white pages.

I had imagined, incorrectly, that NAMED-LAMBDA actually had some semantics
associated with it, e.g. it was similar to the Interlisp notion of creating
a frame with a name which was visible to STKPOS, RETFROM, and other stack
primitives. The current common-lisp spec seems to have a big hole in the area
of primitives which would allow one to write an implementation-independent 
debugger.

∂16-Nov-82  0900	JONL at PARC-MAXC 	Multiple-Value implementations 
Date: 15 NOV 1982 1421-PST
From: JONL at PARC-MAXC
Subject: Multiple-Value implementations
To:   hedrick at RUTGERS
cc:   common-lisp at SU-AI, jonl

Apologies for not being able to reply as fast and prolifically
as others on this issue (still "snowed under" from house buying etc),
but I think the VAX/NIL method of handling multiple values should
be considered.  It has the virtue of being incredibly more
siimple than the summary you suggested, and the minor disadvantage
that MVPROG1 is slightly more expensive than it would be in a stack-
oriented implementation.

One machine register is dedicated to communicating back the number
of values returned by any function.  This is the only failing of the
MacLisp "add-on" macro scheme -- it was judged to be too expensive  to
the non MV user to have every function, including built-in system
functions, take the time (adn space!) to do this; besides, all compiled
code would be invalidated should such a demand be enforced.  

But back to the to the topic: on the VAX, the function-exit sequence includes
a two-byte instruction to set the number of values being returned.  Thus
(COND ((FOO) 'A) (T (VALUES 'B 'A)))  would have two slightly different exit
sequences (if this form were the return-value of a function).  All values
are returned in a "value-return" vector; and as Moon rightly pointed out,
having the first location of this conceptual vector be the register where
single-value function results would *normally* be found means that non-users
of the MV stuff pay only the two-byte penalty (this is truly zilch on the VAX,
considering its funciton call overhead, and it ought to be so on the PDP10).
Since this is not a stack protocol, then a tail-recursive instance of MVPROG1 must
be compiled in such a way as to save-and-restore the active value-return vector;
the cost of this may not be zilch (that is, it may actually be measurable), but
then how often and how important is this case?

The compiler need not be more clever than to "fold-out" lexical instances of
apparent mv usage.  Callers who want exactly one value from a function call need
not be perturbed at all (unless  you want to provide run-time checking for the
case of zero arguments returned).  Sume support might be given to the interpreter so 
that it not actually cons-up-into-a-list the multiple values returned -- such
as using resource-allocated scratch vectors or whatnot; perhaps some syntax is
needed whereby a "scratch list" can be given to MULTIPLE-VALUE-LIST.  [Unfortunately,
not all of these ideas got integrated into VAX/NIL before the mail development
group dissolved -- it was just using the MacLisp-like macros last time I checked --
but most of them had been coded and tested out.  It  may still be at what
you called "stage 1".]

I prefer the notion of disconnecting any rigid link between caller and callee
on this mater -- there is no m ore reason why returning multiple-values when not
explicitly "called for" is bad than there is reason to proscribe value-returning
functions from being called "for effects".  Like Moon pointed out in reply to
Fateman's concern: it's better to produce the multiple valuues even when not
wanted than it would be to produce some gross structure that had to be "torn apart"
at run time to get at the one value wanted.

∂16-Nov-82  0900	Masinter at PARC-MAXC 	Re: #, 
Date: 15-Nov-82 11:48:48 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Re: #,
To: common-lisp at SU-AI

I would like to see most of the special forms currently in reader macros
merely be abbreviations for some form, since then it would not preclude
building a residential environment around common-lisp.

As for #,: Interlisp has three macros for constants:

(CONSTANT form). Returns the value of form available at compile time. 

(LOADTIMECONSTANT form). Returns the value of form as of load time.

(DEFERREDCONSTANT form). Returns the value of form as of first execution.

All of these merely return the value of "form" when interpreted. Some 
implementations of Interlisp don't support LOADTIMECONSTANT (the compiled-
code loader won't handle it) and those get turned into DEFERREDCONSTANT.

Larry

∂16-Nov-82  0957	DLW at MIT-MC 	multiple-value return    
Date: Monday, 15 November 1982  19:34-EST
Sender: DLW at MIT-OZ
From: DLW at MIT-MC
To:   Kim.fateman at Berkeley
Cc:   common-lisp at su-ai
Subject:  multiple-value return
In-reply-to: The message of 14-Nov-82 09:42:03-PST (Sun) from Kim.fateman@Berkeley

If you spent more time thinking about how to produce a low-cost
implementation and less time trying to convince us to remove multiple
values from the language, I bet you could come up with
a cheap implementation.  It's largely a matter of how
you choose to expend your efforts.  I'm glad there are
some people on this mailing list who are spending their
time trying to solve problems and figure out good ways
to implement Common Lisp.

Indeed, a very tricky and crafty scheme might be needed
to implement multiple values efficiently.  That's fine.
As long as the user doesn't see it, it's worth it.  I
consider this analogous to the "fast number" scheme in
PDP-10 Maclisp.  Our goal should be to eliminate the
"Lisp is inherently inefficient and can't ever be competitive
with other languages" mentality.

It's also a good thing that Common Lisp is not being designed
purely by a group of language implementors, who have lots
of motivation to eliminate features to keep their own job
easy.  Common Lisp's design has been heavily influenced
by the experience of real users of Maclisp and the Lisp Machine,
who are interested in getting work done and writing code that
can be both efficient and elegant, and who are not interested
especially in keeping things easy for the implementors.  Let
us continue to develop Common Lisp with the needs of the user
foremost in our minds.

∂16-Nov-82  1028	BROOKS at MIT-OZ at MIT-MC 	Re: DLW's message and Fateman's FLOOR.    
Date: 16 Nov 1982 1316-EST
From: BROOKS at MIT-OZ at MIT-MC
Subject: Re: DLW's message and Fateman's FLOOR.
To: common-lisp at SU-AI

Right.

Most of the time the complaint about FLOOR being expensive
doesn't apply, as it will get compiled down to one result.
But what about when it is a tail recursive call. The compiler
can't know whether both values are needed. How about having
some way of declaring that a function will only return one
value: e.g.

(DEFUN USER-MOD3 (X)
  (DECLARE (SINGLE-VALUE USER-MOD3))
  (MOD X 3))

where we probably want something less ugly.

I suspect (as long as we don't arbitrarily start loading up all
sorts of random functions with multiple values) that this would
only be needed very infrequently.
-------

∂16-Nov-82  1052	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
Date: Tuesday, 16 November 1982  13:52-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   BROOKS at MIT-OZ at MIT-MC
Cc:   common-lisp at SU-AI
Subject: DLW's message and Fateman's FLOOR.


I don't think we need a new declaration.  If you want to suppress the
return of multiple values for some form in tail-recursive position, you
can easily do that with, for example,

... (return (prog1 (trunc x y))) ...

Static analysis at compile time will now show that only one value is
coming back.  As Rod Brooks points out, one would seldom bother with
this: it is useful only in a call to a multiple-value producer in
tail-recursive position in a place where the speed matters.  The use of
TRUNC and friends in a context where the consumer of the value is
lexically apparent can be optimized at compile-time.

-- Scott

∂16-Nov-82  1106	HEDRICK at RUTGERS 	Re: #,    
Date: 16 Nov 1982 1355-EST
From: HEDRICK at RUTGERS
To: Masinter at PARC-MAXC, common-lisp at SU-AI
Subject: Re: #,
Message-ID: <"MS10(2117)+GLXLIB1(1135)" 11872446256.46.19.20844 at RUTGERS>
Regarding: Message from Masinter at PARC-MAXC of 15-Nov-82 1148-EST

I strongly concur with Masinter's request to define the forms to which
the # constructs expand.  It should be possible to represent anything
that can be in a Lisp file using S-expressions, for fairly obvious
reasons.  Although I regard existing "residential system" as
relatively unattractive (in particular I think most of our users
prefer an LEDIT interface to EMACS to the Interlisp structure editor),
we have some very attractive proposals for systems that mix features
of in-core function editors and systems such as LEDIT.  Certainly this
kind of system will only work if we can write back out what we read
in.  This includes both # constructs and comments.  We will surely
define these things locally if we have to, but it seems like a good
idea for everybody to agree on them.
   --------

∂16-Nov-82  1117	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
Date: Tuesday, 16 November 1982  13:52-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   BROOKS at MIT-OZ at MIT-MC
Cc:   common-lisp at SU-AI
Subject: DLW's message and Fateman's FLOOR.


I don't think we need a new declaration.  If you want to suppress the
return of multiple values for some form in tail-recursive position, you
can easily do that with, for example,

... (return (prog1 (trunc x y))) ...

Static analysis at compile time will now show that only one value is
coming back.  As Rod Brooks points out, one would seldom bother with
this: it is useful only in a call to a multiple-value producer in
tail-recursive position in a place where the speed matters.  The use of
TRUNC and friends in a context where the consumer of the value is
lexically apparent can be optimized at compile-time.

-- Scott

∂16-Nov-82  1151	Guy.Steele at CMU-CS-A 	1000th message  
Date: 16 November 1982 1315-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: 1000th message

Since I started collecting COMMON-LISP messages into a
separtate file on 27 October 1981, this is the one-thousandth
message.

∂16-Nov-82  1227	MOON at SCRC-TENEX 	Defining the forms to which the # constructs expand    
Date: Tuesday, 16 November 1982  15:22-EST
From: MOON at SCRC-TENEX
To:   HEDRICK at RUTGERS, Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Defining the forms to which the # constructs expand

I agree with you, since I think that primitives should always be available
to the user.

Note, however, that you both missed a vital point.  Neither #. nor #,
expands into a form!  Both of these can be used inside of an expression
which is data, as well as inside an expression which is a program.  When
reading into the environment (as opposed to reading into the compiler),
the #. and #, constructs must produce precisely the result of evaluating
their argument.  They cannot produce any sort of "wrapper" around it.

The only hidden primitive involved in #. and #, is the "magic wrapper"
that #, uses when reading into the compiler.

The inability to deal with things like #. is the inherent bankruptcy of
residential systems, if by that you mean an editor which regenerates your
source text from the actual contents of memory, rather than keeping a
separate copy of it.  On the other hand, if by residential system you mean
merely the ability to switch rapidly between typing at the Lisp evaluator
and typing at the editor, and the ability to edit single functions and get
them into memory without the overhead of reading or compiling whole files,
this is what we have in the Lisp machine, while still using text-based
editing, and Boy!  Is it ever an improvement over the old file-based ways
of doing things!

∂16-Nov-82  1247	BROOKS at MIT-OZ at MIT-MC 	(prog1 (trunc x y))   
Date: 16 Nov 1982 1524-EST
From: BROOKS at MIT-OZ at MIT-MC
Subject: (prog1 (trunc x y))
To: common-lisp at SU-AI

(return (prog1 (trunc x y))) looks like awful black magic, and
the intent is not very clear. How about
  (or (trunc x y) ())
since in that position multiple values are defined not to work
so the compiler can figure it out there too. I'd prefer to
see a clear mechanism provided rather than (by default) encouraging
users to come up with obscure gobble-de-gook to make use of
essentially side effects of the semantics of special forms.
-------

∂16-Nov-82  1334	Alan Bawden <ALAN at MIT-MC> 	(prog1 (trunc x y)) 
Date: 16 November 1982 15:45-EST
From: Alan Bawden <ALAN at MIT-MC>
Subject:  (prog1 (trunc x y))
To: common-lisp at SU-AI

I believe the LispMachine uses (VALUES (TRUNC X Y)) to force the return of
a single value.  What could be clearer?

∂16-Nov-82  1333	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
Date: 16 November 1982 1538-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Forcing one value from a function

I have been given to believe that in Lisp Machine LISP
the approved convention is
	(VALUES (FLOOR x y))
to get back exactly one value.  I suppose this might be
somewhat misleading to the novice.
--Guy

∂16-Nov-82  1423	Ron <FISCHER at RUTGERS> 	Re: Obliquity of the vernacular...
Date: 16 Nov 1982 1648-EST
From: Ron <FISCHER at RUTGERS>
Subject: Re: Obliquity of the vernacular...
To: BROOKS at MIT-OZ at MIT-MC, common-lisp at SU-AI
In-Reply-To: Your message of 16-Nov-82 1524-EST

I agree with BROOKS.  Where is all the perspicuity to which the manual
constantly refers?  How could something as obscure as (prog1 (trunc x
y)) be suggested in this light?  Give the poor thing a name if it will
be used.

(ron fischer)
-------

∂16-Nov-82  1555	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
Date: 16 November 1982 1538-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Forcing one value from a function

I have been given to believe that in Lisp Machine LISP
the approved convention is
	(VALUES (FLOOR x y))
to get back exactly one value.  I suppose this might be
somewhat misleading to the novice.
--Guy

∂16-Nov-82  1805	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
Date: 16 Nov 1982 1650-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: (prog1 (trunc x y))
To: BROOKS at MIT-OZ at MIT-MC, common-lisp at SU-AI
In-Reply-To: Your message of 16-Nov-82 1324-MST

Indeed, this seems like a natural candidate for a declaration, being in the
category of "optional optimization." (DECLARE (SINGLE-VALUE TRUNC)) isn't
that ugly.
-------

∂16-Nov-82  1806	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
Date: 16-Nov-82 16:25:04 PST (Tuesday)
From: Masinter at PARC-MAXC
Subject: Re: Defining the forms to which the # constructs expand
In-reply-to: MOON's message of Tuesday, 16 November 1982  15:22-EST
To: (MOON at SCRC-TENEX)
cc: common-lisp at SU-AI

Foo. By a residential system, I mean one in which you can write programs in Lisp to
write and modify programs (using the normal S-expression representation of the
program), and have the program-modified programs be first class.

I suppose since you haven't seen the point of this, I should give an example.
Let's suppose, for example, that I wanted to swap the order of arguments to a
function. I might write a program/edit command which would go through my code,
switching the  arguments, and wrapping the whole thing with a LET if necessary
to enforce argument evaluation. 

I could imagine writing TECO macros to do this, where you look at the text and
pretend that you were looking at the s-expression, but the most natural way to
do this is to READ in the program, apply a transformation, and prettyprint it
out again. It isn't acceptable if information like #. and #, get lost. It is
preferable that the mechanism by which that information is preserved is visible,
so that the code walkers can know about it.

You may not think this is an important kind of thing to do, but it seems that
defining COMMON-LISP in a way which precludes building such tools is unnecessary
and a mistake.

∂16-Nov-82  1817	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
Date: 16 Nov 1982 1650-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: (prog1 (trunc x y))
To: BROOKS at MIT-OZ at MIT-MC, common-lisp at SU-AI
In-Reply-To: Your message of 16-Nov-82 1324-MST

Indeed, this seems like a natural candidate for a declaration, being in the
category of "optional optimization." (DECLARE (SINGLE-VALUE TRUNC)) isn't
that ugly.
-------

∂16-Nov-82  1817	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
Date: 16-Nov-82 16:25:04 PST (Tuesday)
From: Masinter at PARC-MAXC
Subject: Re: Defining the forms to which the # constructs expand
In-reply-to: MOON's message of Tuesday, 16 November 1982  15:22-EST
To: (MOON at SCRC-TENEX)
cc: common-lisp at SU-AI

Foo. By a residential system, I mean one in which you can write programs in Lisp to
write and modify programs (using the normal S-expression representation of the
program), and have the program-modified programs be first class.

I suppose since you haven't seen the point of this, I should give an example.
Let's suppose, for example, that I wanted to swap the order of arguments to a
function. I might write a program/edit command which would go through my code,
switching the  arguments, and wrapping the whole thing with a LET if necessary
to enforce argument evaluation. 

I could imagine writing TECO macros to do this, where you look at the text and
pretend that you were looking at the s-expression, but the most natural way to
do this is to READ in the program, apply a transformation, and prettyprint it
out again. It isn't acceptable if information like #. and #, get lost. It is
preferable that the mechanism by which that information is preserved is visible,
so that the code walkers can know about it.

You may not think this is an important kind of thing to do, but it seems that
defining COMMON-LISP in a way which precludes building such tools is unnecessary
and a mistake.

∂16-Nov-82  1817	Glenn S. Burke <GSB at MIT-ML> 	Re: #,  
Date: 16 November 1982 19:24-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: Re: #,
To: common-lisp at SU-AI

What can be done to allow load-time evaluation in a general fashion is
this.  (This has been implemented in Maclisp.  I won't say how because
it is a dirty kludge and was then specialized to a particular purpose.)

Provide the user with some means by which he can get load-time evaluation
performed to provide some object, no matter where it is in whatever
structure is being "dumped", by virtue of having some symbol (of HIS
choosing) as the car of a list.  (The CADR being the form which gets
evaluated at load time, for instance, although you might not want to
maintain that restriction.)

Then, the user is free to provide how to handle:
   (1)  What to do when the form is encountered by the compiler as a
form to be compiled, by defining some sort of compiler-macro or
optimizer or rewrite rule or whatever we have for that (which we
should also define).
   (2)  What to do when the form is encountered by the evaluator.
Since these forms are typically produced during compilation (by virtue
of the reading being done by the compiler, something which the user
should be able to determine [yet another thing to define]), this could
be considered an error, or the function could be a macro which quotes
itself, effectively causing the object to be self-evaluating.

So, for example, if this worked by virtue of the symbol having a
non-null :load-time-evaluation-form property, one might implement the
Maclisp SQUID form as follows:

;SQUID, "Self Quoting Internal Datum", has as its value a marker which
; you list around a form which should be evaluated at load time.  THe
; form is otherwise treated as being self-evaluating.
(defvar squid
  (copysymbol 'squid))

;Tell the compiler/assembler about the marker.
(putprop squid t :load-time-evaluation-form)

;Define how such a form compiles and evaluates:
(defun squid-quoter (form)
   (list 'quote form))

;I guess the following is probably wrong for common-lisp but anyway:
(fset squid '(macro . squid-quoter))

Then, the code for #, could simply do
	(if *reading-for-compilation*
	    (list squid (read))
	    (eval (read)))

"*reading-for-compilation*" should probably be
"*reading-for-external-compilation*" to distinguish it from the case
when the compiler is compiling directly to core.
----
Of course another way to do this is to have a flavor or
extend/message-passing system and simply define the right messages to
interface to the compiler and evaluator.
----
If you try to generalize this too much you run into problems
differentiating your runtime and compile-time environments;  for
example a macro which contains pointers to datastructure which should
be created with a special load-time-eval construct, but it can be used
both by the interpreter and the compiler.  Having the compiler not
bash the runtime environment with macro definitions it is compiling
(but save the definitions away and expand them otherwise) alleviates
this, but only for the single-file compilation.  There are potentially
other subtleties which make the read switch inadequate, such as having
a single textual definition which both needs to be compiled to a file
and stored in core (the traditional macro definition bashing the
runtime environment, for example, but this might arise in other ways).

Anyway, the reason i brought all this up is that we have played some
with writing, saving, and referring to nodes in semantic networks
here, and that is the sort of thing which "users" might try to do.
[JonL and/or Guy can testify to the Maclisp hacking in this regard
from variously the OWL, LMS, XLMS, and Brand-X systems, each of which
implemented yet another representation scheme and found the Lisp
primitives inadequate.]

∂16-Nov-82  1852	Guy.Steele at CMU-CS-A 	Masinter's remarks on #,  
Date: 16 November 1982 2129-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Masinter's remarks on #,

I am very much in sympathy with the goal of writing program-writing programs
and program-transforming programs.  I don't think the existence or
non-existence of #, makes that job any harder or easier, however.
I think that any mechanism that can also preserve the distinction
between #o777 and 511, or for that matter between |(foo| and \(foo,
or even between (x . (a b c)) and (x a b c) [I sometimes write the former
in a constant a-list if necessary to preserve visual similarity of the
entries]---such a mechanism can also deal with #,.  The fact is that
vanilla READ is a many-to-one mapping; by the time you've got the
S-expression in memory you have already lost.  Preservation of the
information requires using a parser other than READ, which may imply
generation of internal structure different from what READ would
produce, that may be unsuitable for evaluation.  Alternatively, various
kinds of hashing could be used.  Nevertheless, in every LISP from
LISP 1.5 on, READ has been a many-to-one mapping.

∂16-Nov-82  2007	MOON at SCRC-TENEX 	Re: Defining the forms to which the # constructs expand
Date: Tuesday, 16 November 1982  23:02-EST
From: MOON at SCRC-TENEX
To:   Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Re: Defining the forms to which the # constructs expand
In-reply-to: The message of 16-Nov-82 16:25:04 PST () from Masinter at PARC-MAXC

    Date: 16-Nov-82 16:25:04 PST (Tuesday)
    From: Masinter at PARC-MAXC

    You may not think this is an important kind of thing to do, but it seems that
    defining COMMON-LISP in a way which precludes building such tools is unnecessary
    and a mistake.

I could say exactly the same thing, word for word, about #,.  Of course the
presence of #, in the language hardly precludes building tools that can't work
with it, it only means that those tools cannot work with that construct, and a
user must choose one or the other.  This is not ideal, but I thought we went
through this discussion last year, and concluded that there was no way to
satisfy all requirements at the same time.  Of course, as Steele points out in
his message, you only have to crank up your cleverness a little and use a
smarter reader, and you can still write the same tools.

∂16-Nov-82  2113	Glenn S. Burke <GSB at MIT-ML> 	multiple values   
Date: 17 November 1982 00:12-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: multiple values
To: common-lisp at SU-AI

NIL is not going to use the multiple-value scheme described by JonL,
but most likely something similar to what is in use on the "A"
lisp machine.  Function calls which pass back multiple-values
tail-recursively will be flagged;  extra information will be pushed
for call frames which expect to receive multiple values.  Returning
multiple values will involve tracing back call frames, and then if
it is found that multiple values are not expected, throwing them away,
otherwise interpreting what was pushed there in some fashion.

A declaration to the effect that a function returns exactly one value
always will be helpful.  My feeling is that this should not be used to
enforce the single-value return, except perhaps by having the
interpreter complain when the function returns multiple values.  (We
have some philosophy about declarations and program behaviour, don't
we?)  Actually stripping extra values can be done with (VALUES
<form>), which doesn't seem to me to be to be particularly unclear.

∂17-Nov-82  0305	Masinter at PARC-MAXC 	Re: #, 
Date: 15-Nov-82 11:48:48 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Re: #,
To: common-lisp at SU-AI

I would like to see most of the special forms currently in reader macros
merely be abbreviations for some form, since then it would not preclude
building a residential environment around common-lisp.

As for #,: Interlisp has three macros for constants:

(CONSTANT form). Returns the value of form available at compile time. 

(LOADTIMECONSTANT form). Returns the value of form as of load time.

(DEFERREDCONSTANT form). Returns the value of form as of first execution.

All of these merely return the value of "form" when interpreted. Some 
implementations of Interlisp don't support LOADTIMECONSTANT (the compiled-
code loader won't handle it) and those get turned into DEFERREDCONSTANT.

Larry

∂17-Nov-82  0305	Alan Bawden <ALAN at MIT-MC> 	Defining the forms to which the # constructs expand    
Date: 16 November 1982 21:45-EST
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Defining the forms to which the # constructs expand
To: Masinter at PARC-MAXC
cc: Moon at SCRC-TENEX, common-lisp at SU-AI

    Date: 16-Nov-82 16:25:04 PST (Tuesday)
    From: Masinter at PARC-MAXC

    ..., but the most natural way to do this is to READ in the program,
    apply a transformation, and prettyprint it out again. It isn't
    acceptable if information like #. and #, get lost. It is preferable
    that the mechanism by which that information is preserved is visible,
    so that the code walkers can know about it.

    You may not think this is an important kind of thing to do, but it seems
    that defining COMMON-LISP in a way which precludes building such tools is
    unnecessary and a mistake.

Common Lisp is already chocked full of reader features that cannot be
preserved across an operation such as you discribe.  Things like the case
of symbols and the base of numbers are all lost in this procedure.  The ";"
comment character is pretty hard to deal with through reading and printing
(you can't just expand into a form), and no scheme I have yet seen will
properly preserve all cases of "`"'ed expressions (although the MacLisp
scheme for this is pretty close).

I would NEVER run any of my MacLisp or LispMachine code through READ and
then PRINT, it would render it totally unreadable.  If precluding such
tools is a mistake, then we have made that mistake long ago.


∂17-Nov-82  1323	JONL at PARC-MAXC 	Expansion of #, and the "residential" question.    
Date: 17 NOV 1982 1322-PST
From: JONL at PARC-MAXC
Subject: Expansion of #, and the "residential" question.
To:   moon at MIT-AI, masinter, alan at MIT-MC
cc:   common-lisp at SU-AI

As one who has "crosssed the barrier" between the MacLisp/Interlisp
style of programming, let me proffer an opinion as to what the
"residential" style means.

"Residential" means that files, in the sense of structured
words/bytes on some disk volume, don't really exist!

At first I was taken aback when I found out that Interlisp's
FILEPKG only incidentally dealt with "files" in the above sense.
A "file" is primarily viewed as an agglomeration of functions,
variables with initial values, macros, typed-definitions and so on.
The problems observed to stem from the many-to-one mapping of
READ are irrelevant, and somewhat orthogonal to this issue; in fact,
Interlisp does have a #. feature in its reader -- control-Y -- and
although it doesn't have a general input-radix feature, you can
type numbers in octal or decimal and no attempt is made to remember
how it was read in.

Of course, real disks do exist, and the FILEPKG will incidentally 
"preserve" a "residential file" by prettyprinting a full snapshot of
it onto such a volume; and also the compiler will produce
a compiled disk file upon request.  One thinks of these as information
interchange media, rather than as the real source of the programs
contained therein.

The paramount issue, as raised by ALAN, is that in the MIT world,
one just never, but never, allows the machine-generated prettyprint
of his functions to be stored on disk file, or to be used for much
of anything other than casual inspection at the terminal.  Even
the style of editing isn't the critical factor (at lest for Interlisp-D
users -- tant pis for Interlisp-10), for there is a moderately good
E-style input buffer (E is the Standford editor which inspired EMACS)
called TTYIN.

In fact, I'd like to take this opportunity to praise the Display-based
structure editor of Interlisp-D, upon which I've become increasingly
dependent recently.  The combination of bitmap-display, multiple-fonts,
interface to old-style Interlisp structure editor, mouse-oriented
new-style operations, TTYIN keyboard interface, and so on, make this
the best editor by far, for LISP programs and data, of all those I've
ever seen.

Footnote:  there were a few comments about how semi-colon comments
    are "lost" by the READer; in Interlisp, the corresponding notion
    is asterisk comments, and the are not lost, but incorporated bodily
    intot he source code.  This has two implications: the reader's
    macrocharacter scheme is modified so taht 'FOO reads in as (QUOTE FOO)
    but Don't reads in as a 5-character symbol.  The second is that you
    can't bput comments just anywhere you please; e.g.
        (CONS X (* This is a comment about X.)
              Y)
    is wrong.  I've ocasionally resorted to kludges like
        (CONS (PROG1 X (* This is a comment about X.))
               Y)
    At least the prettyprinter moves comments over to a "comment
    column", just as the MacLisp GRINDEF would put semi-colon
    comments over in a comment column.
 

∂17-Nov-82  1359	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
Date: 17 NOV 1982 1357-PST
From: JONL at PARC-MAXC
Subject: What's wrong with '#,<frob> ?
To:   common-lisp at SU-AI

As GSB related, the Maclisp notion of #, centers around a hokey
notion of "reading for the purpose of compiling this function", as
opposed to reading for any other purpose.  The probelm as I see it
is that QUOTE is being squeezed a bit beyond its capabilities.

QUOTE should imply a constant which is constant over all incarnations
of Lisp, and throughout all time.  The #, indicates something
which varies on a per-loadup basis, but is constant after that.
Previous to "#,", users would just set aside a global variable 
which would be initialized a load up time.  But I much prefer
    (MUMBLE-UPON X '(SOME #,(machine-name) MESSAGES))
to the less apealing
    (MUMBLE-UPON X GLOBALVARIABLE.FOR.MSG.FUNCTION.A0025)

Suggestion:  a new special form, say CQUOTE, which is like QUOTE
    but actually processes over its form, looking for
    certain substitutions to make (such as evaluating some part).
    this is hardly a new idea, since Adolfo Guzeman had such a
    macro in his PhD Thesis program in 1967 (running on a PDP6
    at that -- R.I.P. PDP6!)  Thus the above example would become
        (MUMBLE-UPON X (CQUOTE (SOME (:, (machine-name)) MESSAGES))
    or, if you will permit me the a few # macrocharacter extensions,
        (MUMBLE-UPON X #!(SOME #,(machine-name) MESSAGES))

There are problems to be worked out about whether the processing is
to happen at read time, at compile time, at load time, or at first
reference (Masinter's msg noted severl Interlisp special forms to make
these distinctions).  But it does bring some of the burden for
identifying an "evaluation context" for data back to the original user.

I might add, in addendum to GSB's note, the Bob Kerns and I worked
a long time at trying to get the compiler/assembler to "percolate"
information about squids u p from the inner guts of quoted data
to some "higher" level so that FASLOAD wouldn't crap out because
the load-time evaluation wound up calling FASLOAD recursively.  [I dont
thnk we ever got it 100% right -- I believe I saw another Maclisp bug
report last summer which would have been explaind by this.  But
there is a point of diminishing returns of COMPLR development, and besides
the problem goes away if you cause the needed file to be loaded in
befor hand]

As ALAN mentioned, only the Maclisp version of backquote has the option
of guaranteeing to the user some interal structure of the output
of the backquote and comma macros -- and having some such guarantee
is crucial to having a "residential" system which doesn't keep the text
of all its sources internally.  So how about "conditionalquote", i.e.
CQUOTE, by analogy to the BQUOTE case?

∂17-Nov-82  1541	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
Date: 17 NOV 1982 1357-PST
From: JONL at PARC-MAXC
Subject: What's wrong with '#,<frob> ?
To:   common-lisp at SU-AI

As GSB related, the Maclisp notion of #, centers around a hokey
notion of "reading for the purpose of compiling this function", as
opposed to reading for any other purpose.  The probelm as I see it
is that QUOTE is being squeezed a bit beyond its capabilities.

QUOTE should imply a constant which is constant over all incarnations
of Lisp, and throughout all time.  The #, indicates something
which varies on a per-loadup basis, but is constant after that.
Previous to "#,", users would just set aside a global variable 
which would be initialized a load up time.  But I much prefer
    (MUMBLE-UPON X '(SOME #,(machine-name) MESSAGES))
to the less apealing
    (MUMBLE-UPON X GLOBALVARIABLE.FOR.MSG.FUNCTION.A0025)

Suggestion:  a new special form, say CQUOTE, which is like QUOTE
    but actually processes over its form, looking for
    certain substitutions to make (such as evaluating some part).
    this is hardly a new idea, since Adolfo Guzeman had such a
    macro in his PhD Thesis program in 1967 (running on a PDP6
    at that -- R.I.P. PDP6!)  Thus the above example would become
        (MUMBLE-UPON X (CQUOTE (SOME (:, (machine-name)) MESSAGES))
    or, if you will permit me the a few # macrocharacter extensions,
        (MUMBLE-UPON X #!(SOME #,(machine-name) MESSAGES))

There are problems to be worked out about whether the processing is
to happen at read time, at compile time, at load time, or at first
reference (Masinter's msg noted severl Interlisp special forms to make
these distinctions).  But it does bring some of the burden for
identifying an "evaluation context" for data back to the original user.

I might add, in addendum to GSB's note, the Bob Kerns and I worked
a long time at trying to get the compiler/assembler to "percolate"
information about squids u p from the inner guts of quoted data
to some "higher" level so that FASLOAD wouldn't crap out because
the load-time evaluation wound up calling FASLOAD recursively.  [I dont
thnk we ever got it 100% right -- I believe I saw another Maclisp bug
report last summer which would have been explaind by this.  But
there is a point of diminishing returns of COMPLR development, and besides
the problem goes away if you cause the needed file to be loaded in
befor hand]

As ALAN mentioned, only the Maclisp version of backquote has the option
of guaranteeing to the user some interal structure of the output
of the backquote and comma macros -- and having some such guarantee
is crucial to having a "residential" system which doesn't keep the text
of all its sources internally.  So how about "conditionalquote", i.e.
CQUOTE, by analogy to the BQUOTE case?

∂17-Nov-82  2259	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
Date: 17 Nov 1982 2259-PST
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: duplicate-p?
To: common-lisp at SU-AI


 I have been getting a LOT of duplicate messages from this mailing list,
most recently I got a gratuitous extra copy of Hedrick's "multiple value"
query of Nov 13.

 Is anyone else also receiving this garbage?  Whose mailer is stuttering?
-------

∂17-Nov-82  2316	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
Date: 17 Nov 1982 2259-PST
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: duplicate-p?
To: common-lisp at SU-AI


 I have been getting a LOT of duplicate messages from this mailing list,
most recently I got a gratuitous extra copy of Hedrick's "multiple value"
query of Nov 13.

 Is anyone else also receiving this garbage?  Whose mailer is stuttering?
-------

∂18-Nov-82  0847	Masinter at PARC-MAXC 	Re: Masinter's remarks on #,    
Date: 18-Nov-82  8:47:44 PST (Thursday)
From: Masinter at PARC-MAXC
Subject: Re: Masinter's remarks on #,
In-reply-to: Guy.Steele's message of 16 November 1982 2129-EST (Tuesday)
To: Guy.Steele at CMU-CS-A
cc: common-lisp at SU-AI

While READ is many-to-one, most of the identifications are merely syntactic;
that is (x . (a b c)) and (x a b c) really are the same program fragment
as far as program semantics go, while #,X and 3  (when X=3) are semantically
different.

One test for the distinction between syntactic and semantic macro characters is
whether READ = READ-PRINT-(new environment)-READ. The difficult cases then
remain #+ #- #.  and #,. 

Larry

∂19-Nov-82  1904	Glenn S. Burke <GSB at MIT-ML> 	named lambdas
Date: 19 November 1982 21:54-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: named lambdas
To: common-lisp at SU-AI

In NIL, a subr (compiled-code object) is the only thing which is allowed
to go into a function cell.  There is mediation performed by FSET to
handle this.  SUBRs for compiled functions have the function name in them.

Interpreted DEFUN does an FSET of the name to an interpreter-closure,
which also has the function name in it.  FSYMEVAL on the name returns
the closure (not the trampoline subr).  Although FLET doesn't happen
to do this because it is currently a macro which expands into a different
NIL binding construct, it could be written as a special form which
also stored the name in the closure.

So, does FDEFINITION want to return the lambda expression of a defun,
or the closure?  Is it different from FSYMEVAL on a symbol?  Looks
like the function cell of your typical interpreted function is going
to have to have an interpreted-lexical-closure in it, so it looks like
everything of interest is going to be encapsulated somehow by
something which would be a more appropriate place for the name.

I'm not really trying to argue against named-lambdas.  That would be
hypocritical since i recently put them into NIL, although they haven't
been exercised and i may have missed a couple places (especially in
the compiler, but that's going away anyway).  But it seems that the
problem they solve might not actually occur that much now.

∂19-Nov-82  1940	MOON at SCRC-TENEX 	named lambdas  
Date: Friday, 19 November 1982  22:36-EST
From: MOON at SCRC-TENEX
To:   common-lisp at SU-AI
Subject: named lambdas
In-reply-to: The message of 19 Nov 1982 21:54-EST from Glenn S. Burke <GSB at MIT-ML>

FDEFINITION on a symbol should be the same as FSYMEVAL.

What you get if you do (PRINT (FDEFINITION foo)) necessarily has to be
implementation-dependent, it appears.  So in that sense NAMED-LAMBDA should
not be in Common Lisp, nor should LAMBDA.  Two exceptions to this:

The user should be given certain portable operations on functions,
including extracting their name.  In the case of interpreted functions it
should also be possible to extract the argument list and the body.

The user should be able to construct functions using more primitive
mechanisms than DEFUN.  One way to do this is to say that any list starting
with LAMBDA is acceptable as a function, and will be translated into
whatever the implementation wants.  Storing this function with FDEFINE and
then retrieving it with FDEFINITION will not, in general, return the same
object.  One could accept NAMED-LAMBDA at this level, too, although I like
JonL's idea for flushing it.  Another way would be to add a new primitive
MAKE-FUNCTION.

To do this right requires a portable specification of the behavior of
the interpreter's representation of a lexical environment.

∂19-Nov-82  1720	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
Date: Friday, 19 November 1982, 20:19-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Named lambdas
To: Masinter at PARC-MAXC, common-lisp at SU-AI
In-reply-to: The message of 15 Nov 82 14:22-EST from Masinter at PARC-MAXC

    Date: 15-Nov-82 11:22:23 PST (Monday)
    From: Masinter at PARC-MAXC
    That the interpreter/compiled code forgets the name of the function you are
    executing in and/or the debugger has trouble finding it from looking at
    the stack seems more like a lack of functionality on the part of the debugger.
    Enough information is there to determine it 

Consider the following case:

(defun a (x y) ...)

(setq var (fdefinition 'a))

The value of var is now the definition of a, namely, the lambda expression
itself, or named-lambda expression on the Lisp Machine currently.

(funcall var 1 2)

At this point, suppose an error happens inside the body of a's
definition.  There is no way to tell that the function on the stack is
named "a" except because it says so inside it; currently, this is done
with named-lambda, although I agree that a stylized declaration could be
used instead.  But there's no way to get the name "a" from the surrounding
context.

I could come up with more involved cases, involving compiled functions
calling interpreted functions, but you get the idea.

∂22-Nov-82  0156	Kent M. Pitman <KMP at MIT-MC> 	a LAMBDA special form  
Date: 22 November 1982 04:55-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  a LAMBDA special form
To: MOON at SCRC-TENEX
cc: common-lisp at SU-AI

    Date: Friday, 19 November 1982  22:36-EST
    From: MOON at SCRC-TENEX
    To:   common-lisp at SU-AI
    Re:   named lambdas

    ... One way to do this is to say that any list starting with LAMBDA is
    acceptable as a function, and will be translated into whatever the
    implementation wants...

ie, LAMBDA should be a special form which returns a "function" (I use quotes
since I don't mean here an datatype, but rather an intension on a [possibly
already existing] datatype.) A typical system-dependent implementation being
something like
 (defmacro lambda (bvl &body body) `#'(lambda ,@body)).
Similarly for named-lambda.

I think this is a good idea.


    ... Another way would be to add a new primitive MAKE-FUNCTION ...

I would say this should be not so much an addition as possible extension.
The LAMBDA special form would have the interesting advantage of not needing
a preceeding #' and would still be statically analyzable by the compiler,
which is a decided advantage. But LAMBDA would not be as general (without
asking the user to call something like EVAL, which is obviously wrong).
So both are really called for.

∂22-Nov-82  1255	Masinter at PARC-MAXC 	Re: Named lambdas
Date: 22-Nov-82 12:54:20 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Re: Named lambdas
In-reply-to: dlw at SCRC-TENEX's message of Friday, 19 November 1982, 20:19-EST
To: common-lisp at SU-AI

If you 

(defun a (x y) ..)

and then

(setf (fdefinition 'b) (fdefinition 'a))

and then call b, should it say you are inside a?

In lieu of any primitives or functions which manipulate these "names", it may
be moot whether the name is associated with "original definition" (i.e., what
you called defun with) or "call location" (i.e., where the definition came
from this time).

∂22-Nov-82  1459	MOON at SCRC-TENEX 	Re: Named lambdas   
Date: Monday, 22 November 1982  17:52-EST
From: MOON at SCRC-TENEX
To:   common-lisp at SU-AI
Subject: Re: Named lambdas
In-reply-to: The message of 22-Nov-82 12:54:20 PST () from Masinter at PARC-MAXC

    Date: 22-Nov-82 12:54:20 PST (Monday)
    From: Masinter at PARC-MAXC

    If you 
    (defun a (x y) ..)
    and then
    (setf (fdefinition 'b) (fdefinition 'a))
    and then call b, should it say you are inside a?

I say yes, because I believe that functions are first-class objects and
have names.  Thus the defun creates a function named a and then fdefine's
the symbol a to it.  The setf picks up that function and puts in another
cell as well.  But it's the same function.

∂22-Nov-82  1630	JONL at PARC-MAXC 	Re: Named lambdas    
Date: 22 NOV 1982 1630-PST
From: JONL at PARC-MAXC
Subject: Re: Named lambdas
To:   MOON at MIT-MC, common-lisp at SU-AI
cc:   JONL

In response to the message sent  Monday, 22 November 1982  17:52-EST from MOON@SCRC-TENEX

I like this analysis in your reply -- it finally puts some
sense into what has been a confusing notion, namely "nameing"
of functions.

If I may paraphrase, "functions" in the computer sense, i.e.
compiled-code objects, lambda expressions, closures, etc, may
have a name which is independent of any symbol to which that
"function" has been assigned (by fdefinition).  The name is more
like commentary on the code body, and would be helpful in
debugging.  Thus we could have 500 functions with  the "name"
FOO, and have 500 symbols all with the "same function" as
their functional definition.

Assignment of functions to symbols, via fdefinition, is a tool
of programming syntax, and nameing of functions is a tool of
user commentary?

∂01-Dec-82  0933	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	(↑ 0.0 0.0) AND (↑ 0 0.0) 
Date: Wednesday, 1 December 1982, 12:30-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
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 <ALAN at SCRC-TENEX>

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 <ALAN at SCRC-TENEX>
    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.

∂01-Dec-82  1126	Kim.fateman@Berkeley
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. :-)

∂01-Dec-82  1412	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML> 	x↑0.0 
Date: Wednesday, 1 December 1982, 16:44-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML>
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.

∂01-Dec-82  1513	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: x↑0.0    
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.


-------

∂01-Dec-82  1530	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: x↑0.0    
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.


-------

∂01-Dec-82  1822	Earl A. Killian <EAK at MIT-MC> 	function ballot  
Date: 1 December 1982 21:17-EST
From: Earl A. Killian <EAK at MIT-MC>
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.

∂01-Dec-82  1838	Scott E. Fahlman <Fahlman at CMU-CS-C> 	function ballot
Date: Wednesday, 1 December 1982  21:38-EST
From: Scott E. Fahlman <Fahlman at CMU-CS-C>
To:   Earl A. Killian <EAK at MIT-MC>
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

∂01-Dec-82  1838	Earl A. Killian <EAK at MIT-MC> 	function ballot  
Date: 1 December 1982 21:17-EST
From: Earl A. Killian <EAK at MIT-MC>
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.

∂01-Dec-82  1928	MOON at SCRC-TENEX 	function ballot
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 <Fahlman at CMU-CS-C>

    Date: Wednesday, 1 December 1982  21:38-EST
    From: Scott E. Fahlman <Fahlman at CMU-CS-C>

    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.

∂01-Dec-82  2306	Guy.Steele at CMU-CS-A 	More on 0↑0
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

∂01-Dec-82  2304	Guy.Steele at CMU-CS-A 	0↑0   
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

∂02-Dec-82  0404	JONL at PARC-MAXC 	Re: x↑0.0  
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.

∂02-Dec-82  0502	JONL at PARC-MAXC 	Speaking of issues left of the Ballots ...    
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 <n> <start-position> &optional <end-position>)
   which would translate into something like a currently-defined LDB
   with bytespec of (BYTE (1+ (- <start> <end>)) <start>).  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. 

∂03-Dec-82  1102	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	0↑0   
Date: Friday, 3 December 1982, 12:51-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
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.

∂03-Dec-82  1102	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	function ballot 
Date: Friday, 3 December 1982, 12:54-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
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?

∂03-Dec-82  1451	Kent M. Pitman <KMP at MIT-MC> 	ENCLOSE and EVAL  
Date: 3 December 1982 17:50-EST
From: Kent M. Pitman <KMP at MIT-MC>
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...?


∂03-Dec-82  1502	Guy.Steele at CMU-CS-A 	Re: ENCLOSE and EVAL 
Date:  3 December 1982 1754-EST (Friday)
From: Guy.Steele at CMU-CS-A
To: Kent M. Pitman <KMP at MIT-MC>
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

∂03-Dec-82  1513	Kent M. Pitman <KMP at MIT-MC> 	EAK's fuction ballot   
Date: 3 December 1982 18:02-EST
From: Kent M. Pitman <KMP at MIT-MC>
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

∂03-Dec-82  1538	Kent M. Pitman <KMP at MIT-MC> 	EAK's fuction ballot   
Date: 3 December 1982 18:02-EST
From: Kent M. Pitman <KMP at MIT-MC>
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

∂03-Dec-82  1603	Eric Benson <BENSON at UTAH-20> 	Re: EAK's fuction ballot   
Date:  3 Dec 1982 1659-MST
From: Eric Benson <BENSON at UTAH-20>
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.
-------

∂04-Dec-82  1505	Earl A. Killian <EAK at MIT-MC> 	bit-vectors 
Date: 4 December 1982 18:06-EST
From: Earl A. Killian <EAK at MIT-MC>
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?

∂04-Dec-82  1511	Earl A. Killian <EAK at MIT-MC> 	` and '
Date: 4 December 1982 18:13-EST
From: Earl A. Killian <EAK at MIT-MC>
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?

∂04-Dec-82  1522	Alan Bawden <ALAN at MIT-MC> 	` and '   
Date: 4 December 1982 18:23-EST
From: Alan Bawden <ALAN at MIT-MC>
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)))

∂04-Dec-82  1739	George J. Carrette <GJC at MIT-MC> 	bitvectors verses bignums    
Date: 4 December 1982 20:37-EST
From: George J. Carrette <GJC at MIT-MC>
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.

∂20-Dec-82  1845	MOON at SCRC-TENEX 	Speaking of issues left of the Ballots ...   
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 <n> <start-position> &optional <end-position>)
       which would translate into something like a currently-defined LDB
       with bytespec of (BYTE (1+ (- <start> <end>)) <start>).  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.

∂21-Dec-82  1502	Glenn S. Burke <GSB at MIT-ML> 	LDB vs LOAD-BYTE  
Date: 21 December 1982 18:05-EST
From: Glenn S. Burke <GSB at MIT-ML>
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.

∂21-Dec-82  1557	Glenn S. Burke <GSB at MIT-ML> 	LDB vs LOAD-BYTE  
Date: 21 December 1982 18:05-EST
From: Glenn S. Burke <GSB at MIT-ML>
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.

∂22-Dec-82  1948	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	parse-number  
Date: Wednesday, 22 December 1982, 22:42-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: parse-number
To: Bernard S. Greenberg <BSG 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 21 Dec 82 14:57-EST from Bernard S. Greenberg <BSG at SCRC-TENEX>

    Date: Tuesday, 21 December 1982, 14:57-EST
    From: Bernard S. Greenberg <BSG at SCRC-TENEX>

    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.

∂23-Dec-82  0507	David L. Andre <DLA at SCRC-TENEX at mit-mc> 	parse-number  
Date: Thursday, 23 December 1982, 00:06-EST
From: David L. Andre <DLA at SCRC-TENEX at mit-mc>
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 <Moon at SCRC-TENEX>

    Date: Wednesday, 22 December 1982, 22:42-EST
    From: David A. Moon <Moon at SCRC-TENEX>
	Date: Tuesday, 21 December 1982, 14:57-EST
	From: Bernard S. Greenberg <BSG at SCRC-TENEX>
	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") ==> #<INTERNED-SYMBOL 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.

∂23-Dec-82  1012	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	parse-number 
Date: Thursday, 23 December 1982, 12:42-EST
From: Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc>
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 <Moon at SCRC-TENEX>

    Date: Wednesday, 22 December 1982, 22:42-EST
    From: David A. Moon <Moon at SCRC-TENEX>
	Date: Tuesday, 21 December 1982, 14:57-EST
	From: Bernard S. Greenberg <BSG at SCRC-TENEX>
	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.

∂23-Dec-82  1119	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	parse-number    
Date: Thursday, 23 December 1982, 13:40-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
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 <DLA at SCRC-TENEX>

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.

∂23-Dec-82  1304	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	parse-number 
Date: Thursday, 23 December 1982, 15:37-EST
From: Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc>
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 <dlw at SCRC-TENEX>

    Date: Thursday, 23 December 1982, 13:40-EST
    From: Daniel L. Weinreb <dlw at SCRC-TENEX>
    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?

∂23-Dec-82  1315	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	parse-number    
Date: Thursday, 23 December 1982, 13:40-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
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 <DLA at SCRC-TENEX>

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.

∂23-Dec-82  1412	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	parse-number 
Date: Thursday, 23 December 1982, 17:09-EST
From: Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc>
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 <Moon at SCRC-TENEX>
	Date: Tuesday, 21 December 1982, 14:57-EST
	From: Bernard S. Greenberg <BSG at SCRC-TENEX>
	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.

∂12-Jan-83  1236	MOON at SCRC-TENEX 	Two small issues, and a test of whether the DCA has broken this mailing list    
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<space>;
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

∂26-Feb-83  1757	Guy.Steele at CMU-CS-A 	Proposed Common LISP Function (forwarded)
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 <WHOLEY@CMU-CS-C>; 21 Feb 83 14:12:15 EST
Date: 21 Feb 83 14:12:10 EST
From: Skef Wholey <Wholey@CMU-CS-C>
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 - - - -

∂27-Feb-83  1938	MASINTER.PA@PARC-MAXC.ARPA 	Ballot proposal  
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

∂27-Feb-83  2306	Moon@SCRC-TENEX 	concatenating strings  
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 <Moon at SCRC-TENEX at MIT-MC>
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 <KMP at MIT-MC>

    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.

∂27-Feb-83  2324	MASINTER.PA@PARC-MAXC 	(APPLY #'CONCATENATE 'STRING L) 
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

∂28-Feb-83  1406	MOON@SCRC-TENEX 	(APPLY #'CONCATENATE 'STRING L)  
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.

∂28-Feb-83  1437	HEDRICK@RUTGERS 	Re: (APPLY #'CONCATENATE 'STRING L)   
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).
-------

∂28-Feb-83  2025	FAHLMAN@CMU-CS-C 	Implementation Limits 
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 <FAHLMAN@CMU-CS-C>; 28 Feb 83 23:18:07 EST
Date: 28 Feb 83 23:18:06 EST
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
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

∂28-Feb-83  2122	GSB@MIT-ML 	number of arguments limitations  
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 <GSB @ MIT-ML>
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.

∂01-Mar-83  1951	Guy.Steele at CMU-CS-A 	NMapDelRassRevAppCatSqrtQ 
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

∂04-Mar-83  1553	FISCHER@RUTGERS 	Re: Recent ballot 
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 <FISCHER@RUTGERS>
Subject: Re: Recent ballot
To: common-lisp@SU-AI

I believe that, taken in a non-mathematical context, this line from
the file <SLISP.CODE>SPIRRAT.SLISP says it all:

"...irrational functions are part of the standard Spicelisp environment."

Uh hum... also :-)

(ron)
-------

∂04-Mar-83  1553	FISCHER@RUTGERS 	What is <SLISP.CODE>SPIRRAT.SLISP?    
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 <FISCHER@RUTGERS>
Subject: What is <SLISP.CODE>SPIRRAT.SLISP?
To: common-lisp@SU-AI

Why it's the file that contains definitions for dealing with irrationals of
course...

Still more *;-)

(ron)
-------

∂10-Mar-83  0906	JonL.pa@PARC-MAXC 	number of arguments limitation 
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.


∂10-Mar-83  1147	JonL.pa@PARC-MAXC 	Upcoming Manual work, and Compatibililty issue.    
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.

∂14-Mar-83  1110	Mailer@SU-SCORE 	LetS in Common Lisp    
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 ...


∂28-Mar-83  1208	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML> 	#A()  
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 <dlw at SCRC-TENEX at MIT-ML>
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.)

∂28-Mar-83  1541	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML> 	#A()  
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 <dlw at SCRC-TENEX at MIT-ML>
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.)

∂29-Mar-83  0849	Daniel L. Weinreb <dlw at SCRC-TENEX> 	#nA(...)   
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 <dlw at SCRC-TENEX>
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...

∂29-Mar-83  1334	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	char-not-equal
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 <BSG%SCRC-TENEX@MIT-MC>
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.

∂30-Mar-83  0759	Bernard S. Greenberg <BSG at SCRC-TENEX at mit-mc> 	digit-weight 
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 <BSG at SCRC-TENEX at mit-mc>
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?

∂30-Mar-83  1135	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	char-not-equal 
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 <Moon%SCRC-TENEX@MIT-MC>
Subject: char-not-equal
To: Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC>
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 <BSG%SCRC-TENEX at MIT-MC>

    Date: Tuesday, 29 March 1983, 16:07-EST
    From: Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC>
    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.

∂30-Mar-83  1134	David A. Moon <Moon at SCRC-TENEX at mit-mc> 	char-not-equal
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 <Moon at SCRC-TENEX at mit-mc>
Subject: char-not-equal
To: Bernard S. Greenberg <BSG@SCRC-TENEX at MIT-MC at mit-mc>
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 <BSG%SCRC-TENEX at MIT-MC>

    Date: Tuesday, 29 March 1983, 16:07-EST
    From: Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC>
    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.

∂30-Mar-83  1603	Moon%SCRC-TENEX@MIT-MC 	short-float-negative-epsilon   
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 <Moon%SCRC-TENEX@MIT-MC>
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.

∂04-Apr-83  1140	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-MC> 	defstruct printed representation
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 <dlw%SCRC-TENEX@MIT-MC>
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.

∂05-Apr-83  1413	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-MC> 	More trivia 
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 <dlw%SCRC-TENEX@MIT-MC>
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.)

∂05-Apr-83  1924	Guy.Steele@CMU-CS-A 	Proposed change to SPECIAL: quick poll 
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 <FAHLMAN@CMU-CS-C>; 5 Apr 83 10:51:19 EST
Date: Tue, 5 Apr 1983  10:51 EST
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
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 - - - -

∂06-Apr-83  2237	MOON at SCRC-TENEX 	Proposed change to SPECIAL: quick poll  
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.

∂07-Apr-83  2238	Scott E. Fahlman <Fahlman@CMU-CS-C> 	Proposed change to SPECIAL: quick poll
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 <FAHLMAN@CMU-CS-C>; 8 Apr 83 01:33:45 EST
Date: Fri, 8 Apr 1983  01:33 EST
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
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

∂08-Apr-83  1117	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	nsubstitute-if/if-not   
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 <BSG%SCRC-TENEX@MIT-MC>
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?

∂08-Apr-83  1328	MOON at SCRC-TENEX 	Proposed change to SPECIAL: quick poll  
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 <Fahlman at CMU-CS-C>
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 <Fahlman@CMU-CS-C>

    Date: Fri, 8 Apr 1983  01:33 EST
    From: Scott E. Fahlman <Fahlman@CMU-CS-C>

    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.

∂10-Apr-83  1934	David A. Moon <MOON%SCRC-TENEX@MIT-MC> 	What should LAST of an atom do?    
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 <MOON%SCRC-TENEX@MIT-MC>
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.

∂10-Apr-83  2101	Scott E. Fahlman <Fahlman@CMU-CS-C> 	What should LAST of an atom do?  
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 <FAHLMAN@CMU-CS-C>; 10 Apr 83 23:55:02 EST
Date: Sun, 10 Apr 1983  23:55 EST
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   David A. Moon <MOON%SCRC-TENEX@MIT-MC>
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 <MOON%SCRC-TENEX at MIT-MC>


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.

∂11-Apr-83  0046	Glenn S. Burke <GSB @ MIT-ML> 	What should LAST of an atom do?   
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 <GSB @ MIT-ML>
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.

∂12-Apr-83  1210	RPG  	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 <your favorite adjective> 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-

∂12-Apr-83  2240	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	What should LAST of an atom do? -- conclusion
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 <Moon%SCRC-TENEX@MIT-MC>
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 <MOON%SCRC-TENEX at MIT-MC>,
             The message of 10 Apr 83 23:55-EST from Scott E. Fahlman <Fahlman at CMU-CS-C>,
             The message of 11 Apr 83 03:43-EST from Glenn S. Burke <GSB at MIT-ML>

    Date: Sunday, 10 April 1983, 22:30-EST
    From: David A. Moon <MOON%SCRC-TENEX@MIT-MC>
    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 <Fahlman@CMU-CS-C>
    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 <GSB @ MIT-ML>
    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.

∂13-Apr-83  0000	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	Proposed change to SPECIAL: proposed resolution   
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 <Moon%SCRC-TENEX@MIT-MC>
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 <Fahlman at CMU-CS-C>

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.

∂13-Apr-83  2031	Scott E. Fahlman <Fahlman@CMU-CS-C> 	EVAL and friends  
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 <FAHLMAN@CMU-CS-C>; 13 Apr 83 22:05:43 EST
Date: Wed, 13 Apr 1983  22:05 EST
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
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

∂20-Apr-83  0717	David A. Moon <Moon%SCRC-TENEX@MIT-ML> 	DEFSETF   
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 <Moon%SCRC-TENEX@MIT-ML>
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.

∂20-Apr-83  1011	David A. Moon <Moon%SCRC-TENEX@MIT-ML> 	DEFSETF   
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 <Moon%SCRC-TENEX@MIT-ML>
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.

∂20-Apr-83  2115	Scott E. Fahlman <Fahlman@CMU-CS-C> 	DEFSETF 
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 <FAHLMAN@CMU-CS-C>; 20 Apr 83 23:53:46 EST
Date: Wed, 20 Apr 1983  23:53 EST
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   David A. Moon <Moon%SCRC-TENEX@MIT-ML>
Cc:   Common-Lisp%su-ai@usc-ecl
Subject: DEFSETF
In-reply-to: Msg of 20 Apr 1983 03:58-EST from David A. Moon <Moon%SCRC-TENEX at MIT-ML>


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

∂21-Apr-83  1044	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-ML> 	*prindepth* and *prinlength* versus *prinarray*
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 <dlw%SCRC-TENEX@MIT-ML>
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.

∂21-Apr-83  1311	BENSON at SPA-Nimbus 	*prindepth* and *prinlength* versus *prinarray* 
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 <dlw%SCRC-TENEX at MIT-ML>

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!

∂22-Apr-83  0635	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	MISMATCH/MAXPREFIX/MAXSUFFIX 
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 <BSG%SCRC-TENEX@MIT-MC>
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?

∂22-Apr-83  1332	Skef Wholey <Wholey@CMU-CS-C> 	MISMATCH/MAXPREFIX/MAXSUFFIX 
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 <WHOLEY@CMU-CS-C>; 22 Apr 83 16:19:52 EST
Date: Fri, 22 Apr 1983  16:19 EST
From: Skef Wholey <Wholey@CMU-CS-C>
To:   Common-Lisp%SU-AI@USC-ECL
CC:   Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC>
Subject: MISMATCH/MAXPREFIX/MAXSUFFIX
In-reply-to: Msg of 22 Apr 1983 09:20-EST from Bernard S. Greenberg <BSG%SCRC-TENEX at MIT-MC>

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.

∂22-Apr-83  2032	Leonard N. Zubkoff <Zubkoff@CMU-CS-C> 	MISMATCH/MAXPREFIX/MAXSUFFIX   
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 <ZUBKOFF@CMU-CS-C>; 22 Apr 83 21:30:38 EST
Date: Fri, 22 Apr 1983  21:30 EST
From: Leonard N. Zubkoff <Zubkoff@CMU-CS-C>
To:   Skef Wholey <Wholey@CMU-CS-C>
Cc:   Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC>,
      Common-Lisp%SU-AI@USC-ECL
Subject: MISMATCH/MAXPREFIX/MAXSUFFIX
In-reply-to: Msg of 22 Apr 1983  16:19-EST from Skef Wholey <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

∂22-Apr-83  2119	David A. Moon <Moon%SCRC-TENEX@MIT-MC> 	Proposed improvement to ASSERT
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 <Moon%SCRC-TENEX@MIT-MC>
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)

∂23-Apr-83  1310	David A. Moon <Moon%SCRC-TENEX@MIT-MULTICS> 	DEFSETF proposal, revised
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 <Moon%SCRC-TENEX@MIT-MULTICS>
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.

∂23-Apr-83  2017	Scott E. Fahlman <Fahlman@CMU-CS-C> 	Lunar DEFSETF
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 <FAHLMAN@CMU-CS-C>; 23 Apr 83 23:17:47 EST
Date: Sat, 23 Apr 1983  23:17 EST
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
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

∂26-Apr-83  0947	Daniel L. Weinreb <dlw%SCRC-TENEX@MIT-MC> 	DEFSETF multiple-values feature 
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 <dlw%SCRC-TENEX@MIT-MC>
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.

∂27-Apr-83  1009	Mike McMahon <MMcM@SCRC-TENEX> 	Erring forms of ...CASE...  
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 <MMcM@SCRC-TENEX>
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.

∂27-Apr-83  2056	Kent M. Pitman <KMP @ MIT-MC> 
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 <KMP @ MIT-MC>
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?

∂28-Apr-83  1657	BENSON at SPA-NIMBUS 	Bugs in the Laser Edition   
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.

∂29-Apr-83  1411	Bernard S. Greenberg <BSG%SCRC-TENEX@MIT-MC> 	MISMATCH, From end.
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 <BSG%SCRC-TENEX@MIT-MC>
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.

∂06-May-83  1229	RPG  	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-

∂06-May-83  1257	@USC-ECL:RPG@MIT-MC 
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 <RPG @ MIT-MC>
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-

∂06-May-83  1311	FEINBERG@CMU-CS-C 	Testing, one two...  
Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 6 May 83  13:10:45 PDT
Received: ID <FEINBERG@CMU-CS-C>; 6 May 83 16:10:24 EDT
Date: 6 May 1983  16:10 EDT (Fri)
From: Feinberg@CMU-CS-C
To:   Richard P. Gabriel <RPG@MIT-MC>
Subject: Testing, one two...
Cc:   common-lisp@SU-AI
In-reply-to: Msg of 6 May 1983 15:42 EDT from Richard P. Gabriel <RPG at MIT-MC>

Howdy!

    Date: 6 May 1983 15:42 EDT
    From: Richard P. Gabriel <RPG at MIT-MC>
    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.

∂06-May-83  1742	FAHLMAN@CMU-CS-C 	Package Proposal (moby message) 
Received: from RANDOM-PLACE by SU-AI with TCP/SMTP; 6 May 83  17:41:28 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 6 May 83 20:40:54 EDT
Date: Fri, 6 May 1983  20:40 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
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

∂07-May-83  1411	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	test message--please ignore    
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 <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
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.

∂07-May-83  1506	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	error proposal  
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 <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
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.

∂07-May-83  1804	FAHLMAN@CMU-CS-C 	error proposal   
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 7 May 83  18:04:23 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 7 May 83 21:04:05 EDT
Date: Sat, 7 May 1983  21:04 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   David A. Moon <Moon%SCRC-TENEX@MIT-MC>
Cc:   Common-Lisp@su-ai
Subject: error proposal
In-reply-to: Msg of 7 May 1983 18:02-EDT from David A. Moon <Moon%SCRC-TENEX%MIT-MC at SU-DSN>


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

∂07-May-83  2027	@USC-ECL,@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	Errors 
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 <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
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.

∂07-May-83  2057	LARGE@CMU-CS-C 	error proposal
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 7 May 83  20:56:50 PDT
Received: ID <LARGE@CMU-CS-C>; 7 May 83 23:56:42 EDT
Date: Sat, 7 May 1983  23:56 EDT
From: Jim Large <LARGE@CMU-CS-C>
To:   David A. Moon <Moon%SCRC-TENEX@MIT-MC>
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 <Fahlman>

 

∂07-May-83  2105	LARGE@CMU-CS-C 	error proposal
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 7 May 83  21:05:35 PDT
Received: ID <LARGE@CMU-CS-C>; 8 May 83 00:05:29 EDT
Date: Sun, 8 May 1983  00:05 EDT
From: Jim Large <LARGE@CMU-CS-C>
To:   David A. Moon <Moon%SCRC-TENEX@MIT-MC>
Cc:   Common-Lisp@su-ai
Subject: error proposal
Phoon: LQ+3D.15H.37M.18S.


  Sorry, my babyl backfired.

			-- Jim

∂08-May-83  0902	@USC-ECL,@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	Package Proposal (moby message) 
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 <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
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 <Fahlman at CMU-CS-C>

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., #<PACKAGE DEBUGGER>.  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.

∂09-May-83  2215	DILL@CMU-CS-C 	package proposal comments
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 9 May 83  22:14:41 PDT
Received: ID <DILL@CMU-CS-C>; 10 May 83 01:14:21 EDT
Date: 10 May 83 01:14:21 EDT
From: DILL@CMU-CS-C
Subject: package proposal comments
To: common-lisp@SU-AI

Here are some thoughts about alternatives in the design of the CL
package system, after looking over the original Fahlman proposal and the
comments by Symbolics.  I've tried to separate out considerations that
are mostly independent, and tried to make explicit any assumptions about
how packages are to be used.  I won't present a lot of detailed
alternatives, because Scott has probably seen them before in previous
proposals.

TRANSITIVE VS. INTRANSITIVE "INHERITANCE":

As a general principle, users should be able to ask for only the symbols
(definitions, whatever) they need from a package.  This reduces the
chances of an accidental name conflict among symbols that the user
didn't need anyway.  If transitive inheritance is the primary way for
package A to gain access to package B's definitions, it violates this
principle, because it automatically re-exports all sorts of symbols that
may have nothing to do with the facilities that package A wants to
provide.

For a really huge system (e.g. MACSYMA or the LISP system itself), the
implementors may want to think of the system as being made up of a bunch
of reasonable-sized packages, while users may want to think of it as
a single package (MACSYMA or LISP).  For this purpose, it may be useful
for a package to group together symbols from other packages and export
them in a bunch.  It is not clear that you need more than one level of
"inheritance" for this, though.

By the way, there seems to be a reasonably clean way to do multiple
interfaces to the same package if it is possible to re-export a symbol
that has been imported from somewhere else.  Export the union of the
symbols for all of the interfaces from the package that does the
actual definitions, then import these into a separate new package
for each interface.  Then each of these new packages can export
only those symbols that are relevant to the particular interface
it is associated with.  If this is really worth doing...



"COPY" VS. "POINTER" SEMANTICS FOR IMPORTED SYMBOLS

There have been two general types of package proposals within the
Spice Lisp group in the last two years: when package A uses package B's
symbols, does it get the symbols exported by package B at one particular
time ("copy"), or does it have some sort of pointer to B, so that it can
track changes in B's exported symbols over time ("pointer")?  "Pointer"
semantics seem to require an implicit or explicit order for searching
export lists.

When it is desirable to track changes, pointer semantics is sometimes
more convenient.  The two cases (that I can think of) where changes in
export lists might happen are when someone is debugging a package and
wants to correct a mistake in an export list, and when someone has
decided to export a new symbol from an old package (only really
legitimate when exporting from the LISP package, I think, if then).

This does not necessarily work as well as it ought to.  Usually,
symbols will have been read and interned using one configuration
of export lists, and when the export lists change, there will still
be no easy way of correctly updating the old symbols to be what
they should have been.

The most serious disadvantage of the pointer semantics is that
accidental shadowing is inherent when you attempt to track changes in
export lists.  Suppose package A searches (in order) the export lists of
packages B and C.  If a symbol is added to the export list of package B,
it could shadow a symbols in C that A was previously using.  Since there
are a lot of packages that could be searching B and C in different
orders (and a lot of different values for B and C), this situation is
very difficult to check for and correct.

With copy semantics, a package always knows what symbols it has gotten
from another package immediately after it gets them.  If a conflict
arises, it can be resolved at that time, and no shadowing can occur
without explicit participation by the packages affected.  If symbols are
added to an export list, it is relatively easy to ask for all the new
symbols (but you still have to ask).  It may be more difficult to forget
symbols that have been removed from an export list, since it may be
difficult to tell where they were imported from (not necessarily the
home package, due to re-exporting).

The current proposal seems to use "copy" semantics for IMPORTing
an individual symbol, and "pointer" semantics for using all the
symbols exported by another package: IMPORTed symbols will not
be tracked if they are removed from an export list.  In pure
"copy" semantics, getting the export list of another package is
equivalent to individually importing all those symbols.

Some of these opinions are based on experience I have had using
the MUDDLE package system, which is basically a "pointer" system
with intransitive inheritance.  In my experience, changing an
export list almost never "worked" except when exporting from the
MUDDLE equivalent of the LISP package.


PACKAGES AS A UNIT OF LOADING

If it is assumed that packages correspond closely to a set of
definitions that should be loaded together, we could provide a function
to load a package, given only the package name, only if it has not
already been loaded.  The system can find the appropriate file to load
from, since the user probably doesn't care as long as the package gets
loaded.  Loading only if not already loaded is a win because many
different packages may import from the same package -- it would be a
pain to have to check in each case whether to load it.  This also makes
mutually referential packages (package A imports from package B which
imports from A) easy.

IMPORTing from a package could cause it to be loaded if necessary, as
above.  MACLISP style autoloading is not necessarily a substitute for this
capability; if there are "autoload" properties on symbols, the packages
defining those symbols will have to be defined to the extent of having
created the package object and storing the relevant symbols somewhere.


PACKAGES AS A UNIT OF COMPILATION

A package system that clearly separates out the external and internal
symbols can make it possible for a compiler to do a better job, since
it can assume that internal definitions will not be accessed outside
of the package.  There are a lot of "block compilation" kinds of
optimizations that could be done.

This is not something that is generally done in the Maclisp/Lisp Machine
world now, but I think we ought to leave open the possibility of doing
it in some implementations in the future.  Two ways to avoid losing
this opportunity are to have a warning in the manual that you should
only use internal symbols from another package if you absolutely know
what you're doing, and having a different form of qualification for
internal symbols (I favor "::" but basically don't care).

I think I can generate a list of interesting optimizations if anyone is
interested.
-------

∂09-May-83  2351	FAHLMAN@CMU-CS-C 	New Package Proposal  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 9 May 83  23:51:14 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 10 May 83 02:51:38 EDT
Date: Tue, 10 May 1983  02:51 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   common-lisp@su-ai
Subject: New Package Proposal


I can't seem to get my new and improved package proposal over the net to
SAIL, maybe because it is too long.  Anyway, people who want to see it
should FTP it from CMUC.  The file is <fahlman.slisp>package.mss.

Share and Enjoy,
Scott

∂10-May-83  0834	@MIT-MC:MOON@SCRC-TENEX 	package proposal comments
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  08:34:01 PDT
Date: Tuesday, 10 May 1983  11:34-EDT
From: MOON at SCRC-TENEX
To:   DILL at CMU-CS-C
Cc:   common-lisp at SU-AI
Subject: package proposal comments
In-reply-to: The message of 10 May 83 01:14:21 EDT from DILL@CMU-CS-C

I think you'll find that the package system that finally gets adopted
is consistent with your comments.

∂10-May-83  0956	@MIT-MC:MOON@SCRC-TENEX 	package.mss.108
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  09:55:52 PDT
Date: Tuesday, 10 May 1983  12:53-EDT
From: MOON at SCRC-TENEX
To:   Fahlman at cmu-cs-c
cc:   common-lisp at su-ai, Moon at SCRC-TENEX
Subject: package.mss.108

I am almost completely happy with this.  There is one big problem, one
medium-sized problem, and a few small problems.

Small:

Does the list returned by package-nicknames include the primary name?
Say explicitly.

find-all-symbols has to accept a string as an argument so that one
doesn't spuriously create a symbol just to use as an argument.  I
suppose one could use an uninterned symbol, but it seems better to me
to make it accept either a string or a symbol, or else just a string.
The string of course has to be in the same case as a symbol's print-name;
case-dependent lookup is used.

There are several typographical errors in the description of do-symbols.

Add do-external-symbols

EXPORT and related functions should take an optional second argument which
is the package to operate on, or its name, defaulting to *PACKAGE*.  This
is mainly valuable when you have a module that presents multiple interfaces
and hence has some "extra" packages associated with it; the external
symbols of each package correspond to one interface to that module.  The
code is all loaded into one package, but different things are exported to
different packages; some symbols are present in more than one interface and
hence exported to more than one package.

Medium:

I'm not completely happy with declare-package and the :export keyword.  I
don't like the idea of package A exporting symbols from package B; what if
there is a typographical error, a conceptual mistake, or an obsolete symbol
in the list supplied by package A, which is a duplicate of package B's
list?  I'd like to see some error-checking here.  I suggest that there be
some distinction between declare-package done by the "owner" of the package
vs. declare-package done by some "user" of the package, and a consistency
check between them (what is exported by a user is a subset of what is
exported by the owner, and likewise for what is include-package'd).
Possibly declare-package should be the "user" function, make-package should
be the "owner" function, and make-package should err if the package has
been made already but not if it has been declared already.  in-package
properly should be a variant of make-package, not of declare-package, in
this scenario.  However it is desirable to be able to go "into" a package
more than once; I suggest that perhaps it is wrong for in-package to do an
implicit make, and the make should be done separately.

Large:

The statement "No two symbols in the same package may have the same name"
is not enlarged upon, and furthermore since this doesn't use the
accessible/present terminology that was just defined, it isn't clear which
is meant.

To me, it is clear that the package consistency rules require that no two
symbols -accessible- from the same package have the same name, unless one
has been explicitly shadowed.  Allowing implicit shadowing makes the
result (which of the two symbols is actually accessible) dependent
upon the order in which the symbols were first seen, or on the order
that use-package and include-package put things onto lists, and destroys
read-read consistency.

In your writeup, name clashes are only discussed under IMPORT.  Name
clashes should be given their own discussion section, and the following
functions should be required to check for name clashes: EXPORT, IMPORT,
USE-PACKAGE, INCLUDE-PACKAGE, and the implicit calls to those functions
from MAKE-PACKAGE, DECLARE-PACKAGE, and IN-PACKAGE.  When the externals of
a package are altered, the check for name clashes must extend to all
packages that inherit from that package (via either use or include).  A
name clash occurs when there is an attempt to make a symbol accessible in a
package with the same name as a distinct symbol already accessible in that
package, except when shadowing has been used to declare the user's
intentions (there is a symbol already accessible in the package, with
the same name, that was mentioned by SHADOW).  When a name clash occurs,
a correctable error is signalled.  A variety of ways to continue from
the error may be provided by an implementation, including such possibilities
as declining to perform the invalid operation, uninterning or unexporting
the other symbol, automatically shadowing, and (in some implementations)
linking function and value cells to make the two clashing symbols equivalent
for those uses of symbols (but not equivalent for EQ of course) and
uninterning one of them.  It may also prove desirable in practice to
have variables that can be set to cause automatic continuation from
name clashes; but we shouldn't standardize on those yet.

∂10-May-83  1230	@MIT-MC:MOON%SCRC-TENEX%MIT-MC@SU-DSN 	suggestion for ballot: :allow-other-keys 
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  12:28:51 PDT
Date: 10 May 1983 1526-EDT
From: David A. Moon <MOON%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: suggestion for ballot: :allow-other-keys
To: common-lisp@SU-AI

This is a suggestion to address the query on page 71 of the laser edition.
I'm able to figure out whether this a kludge or not, but I'd like to solicit
a ballot on whether it is too inelegant to include in the language.  Please
read the manual's writeups on &key before voting unless you understand keyword
arguments already.

In addition to the keyword arguments explicitly declared, all functions with
&key in their lambda list accept an additional keyword, :allow-other-keys.
If this keyword is supplied and the value is true, then no error is signalled
if the arguments to the function include unrecognized keywords.  If :allow-other-keys
is unsupplied or supplied with an argument of nil, and the &allow-other-keys
symbol is not used in the lambda list, then it is an error if the argument list
contains keywords not listed in the lambda list.

This allows one to construct a keyword list that has been checked at some high
level, secure in the knowledge that no error will be signalled at a low
level.  The keyword list can be passed to several different functions,
each of which will extract the keywords that are relevant to it.  Note that
both &allow-other-keys and :allow-other-keys are useful features--neither
subsumes the other.
-------

∂10-May-83  1447	@USC-ECL,@MIT-MC:BENSON@SPA-NIMBUS 	Function objects   
Received: from USC-ECL by SU-AI with TCP/SMTP; 10 May 83  14:35:11 PDT
Received: from MIT-MC by USC-ECL; Tue 10 May 83 13:26:59-PDT
Date: Tuesday, 10 May 1983, 13:11-PDT
From: BENSON at SPA-NIMBUS
Subject: Function objects
To: Common-Lisp%su-ai at usc-ecl

The Laser edition is inconsistent in its treatment of functions.  This
inconsistency is due to confusion between the name of a function and the
actual function object.  This confusion has been around for a long time,
and is manifested in many Lisp implementations where the name of a
function object and the object itself are the same.  To quote from the
Standard Lisp Report: "FUNCTION is like QUOTE but its argument may be
affected by compilation."

First, we need to state what we mean by a function object.  The
definition of the FUNCTIONP data type predicate says that it

"is true if its argument is suitable for applying to arguments, using
for example the FUNCALL or APPLY function."

The definition of APPLY states that its argument

"may be a compiled-code object, or a lambda expression, or a symbol; in
the latter case the global functional value of that symbol is used."

(Let's ignore compiled-code objects for the time being; we'll get back
to them later.)  This is the definition which confuses the name (symbol
or lambda expression) and the function object.  Conflicting with this
definition is the Functions section of the Progam Structure chapter
(Section 5.2, p. 42).  It states that

"Lambda-expressions and symbols as names of functions can appear only as
the first element of a function-call form, or as the second element of
the FUNCTION special form."

The definition of the FUNCTION special form, where FN is the second
element of the form, states that

"if FN is a symbol, the functional value of the variable whose name is
that symbol is returned.  If FN is a lambda expression, then a lexical
closure is returned."

Notice that the definition of APPLY doesn't even mention lexical
closures, yet these are the things which are produced by the FUNCTION
special form, which is presumably the preferred means of obtaining a
suitable object to use as an argument to APPLY!

The key to understanding all of this is to realize that the CAR of a
Lisp form (ignoring macros and special forms) is not "not evaluated," in
fact it is a function name which is evaluated to produce a function
object.  In Scheme this evaluation is the same as that used to produce
function arguments, i.e. the function EVAL.  Common Lisp must use a
different algorithm, because it permits symbols to have distinct
variable and function values.  The function which implements this
algorithm is not mentioned in the Common Lisp manual.  In fact I don't
know of any Lisp implementations which provide it; it is usually
open-coded (sometimes a no-op!) within EVAL.  For the sake of
discussion, let's call it FEVAL.  In fact the one we are most interested
in is *FEVAL, analogous to *EVAL, since this function must use the
current lexical environment in its evaluation process.

Evaluation of a form which represents an ordinary function call is thus:
FEVAL the CAR of the form, EVAL all the other elements of the list, call
the result of FEVAL with the EVALed arguments.  FEVAL is useful to
produce a function object which will not be called immediately.  The
FUNCTION special form says in effect: use FEVAL instead of EVAL to
produce this argument.  Conversely, EVAL is also useful in producing
function objects.  FUNCALL allows normal argument evaluation to return
a function object to be called.  Note that neither FUNCTION nor
FUNCALL is needed in Scheme precisely because EVAL and FEVAL are the
same.

FEVAL is a very simple function.  If its argument is a lambda
expression, it returns a closure of the expression over the lexical
environment.  If it is a symbol, the "functional variable" value of the
symbol in the lexical (or global) environment is returned.  Anything
else is an error.  As an upward-compatible extension, function specs as
provided in Zetalisp, such as (:PROPERTY FOO BAR), are treated
essentially the same as symbols.  They simply specify a place from which
to fetch a function object.

The semantics of compiled-code objects have not been described
extensively in the Common Lisp manual.  They are mentioned in the
spurious definition of APPLY above, which might lead one to think of
them as being "like lambda expressions, only faster."  In fact the only
sensible interpretation of a compiled-code object is "like FEVAL of a
lambda expression, only faster."  In other words, anything a lexical
closure can do, a compiled-code object can do.  This should be stated
explicitly in the manual in the data type section.

The argument to APPLY (and FUNCALL) can be a compiled-code object or a
lexical closure; anything else is an error.  A language standard which
considers symbols or lambda expressions to be functions is perpetuating
the confusion described above.

To acheive the effect of using a symbol as a function as described above
(and currently implemented in Zetalisp, for example), that is, using the
global functional value at the time it is called, one must use a closure
which calls the function, e.g. to give BAR as a functional argument to
FOO, where BAR's definition may change between the call to FOO and the
FUNCALL of its functional argument, use: 
 
(FOO #'(LAMBDA (X) (BAR X)))	;BAR is a function of one argument

instead of

(FOO 'BAR)

In general, if the number of arguments is unknown:

(FOO #'(LAMBDA (&REST X) (APPLY #'BAR X)))

Or, if you really mean the global function value, not the lexical:

(FOO #'(LAMBDA (&REST X) (APPLY (SYMBOL-FUNCTION 'BAR) X)))

The current language definition does not provide either a function which
takes a lambda expression and a lexical environment and returns a
lexical closure (*FEVAL) or functions to extract these components from
an existing lexical closure.  These aren't strictly necessary, but
without them many useful parts of a programming environment must be
written non-portably.  For example, GRINDEF is impossible in portable
Common Lisp, since SYMBOL-FUNCTION must return either a lexical closure
or a compiled-code object.  A structure editor which can redefine a
function requires both selector functions and the constructor function,
since it must create a new closure with the modified function body.

I recommend that lexical environments be included in the language as
first-class objects.  *EVAL and EVALHOOK would then be defined to take
exactly two arguments.  ENCLOSE (*FEVAL restricted to lambda
expressions) takes a lambda expression and a lexical environment and
returns a lexical closure.  CLOSURE-EXPRESSION and CLOSURE-ENVIRONMENT
take a lexical closure and return its components.  The constant
NULL-ENVIRONMENT, the empty lexical environment, should be defined.  The
structure of a lexical environment need not (indeed, should not) be
specified. These additions are not major and would aid immensely in
supporting a truly lexical Lisp.

∂10-May-83  1452	@USC-ECL,@MIT-ML:BENSON@SPA-NIMBUS 	suggestion for ballot: :allow-other-keys    
Received: from USC-ECL by SU-AI with TCP/SMTP; 10 May 83  14:51:38 PDT
Received: from MIT-ML by USC-ECL; Tue 10 May 83 14:20:28-PDT
Date: Tuesday, 10 May 1983, 14:19-PDT
From: BENSON at SPA-NIMBUS
Subject: suggestion for ballot: :allow-other-keys
To: common-lisp at SU-AI
In-reply-to: The message of 10 May 83 12:26-PDT from David A. Moon <MOON%SCRC-TENEX%MIT-MC at SU-DSN>

In fact they are mirror images of each other: &ALLOW-OTHER-KEYS is the
receiver's means of permitting other keywords (which may or may not be
captured in a &REST argument), and :ALLOW-OTHER-KEYS T is the
transmitter's means of permitting other keywords.  At first glance it
seems to be a kludge, but any other user-level facility for this
functionality will require something similar in its implementation, i.e.
a parameter to give to the keyword parsing code.

∂10-May-83  1509	KMP@MIT-MC 	Packages
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  15:08:00 PDT
Date: 10 May 1983 18:09 EDT
From: Kent M. Pitman <KMP @ MIT-MC>
Subject:  Packages
To: Common-Lisp @ SU-AI

Here are my notes on CMUC:<FAHLMAN.SLISP>PACKAGE.MSS.108.

Summary

  Item	Importance	Notes
  (1)	Medium		Propose changing "FOO#:BAR" to "#:FOO:BAR".
  (2)	Large		Propose flushing "#:" notation on symbols with NIL
			in their package cell.
  (3)	Small		Questioning use of PUSHNEW in USE-PACKAGE.
  (4)	Small		Wording issue in definition of "UNEXPORT".
  (5)	Tiny		Syntax in "DECLARE-PACKAGE".
  (6)	Medium		Setting *PACKAGE*, etc in init files.
  (7)	Small		LIST-ALL-PACKAGES and anonymous packages.
  (8)	Medium		Adding an optional PACKAGE argument to IMPORT, etc.
  (9)	Medium		Forcing symbols to print with[out] package prefixes.

-----

(1) I dislike "#:" in the middle of a name for several reasons.

    * I think it is ugly. It visually breaks up the symbol in a bad way. 

    * "#" is defined as a token terminator. This would have to be redefined.
      I note (p219, Colander Edition -- sorry; I have no Laser edition)
      there are no non-terminating macro sequences in the attributes table. I
      think this is wise from the point of view of novices. The presence of
      initially defined non-terminating macro sequences would just further
      complicate the knowledge of Lisp syntax a novice would need.

    * I would prefer a prefix notation such as "#:FOO:BAR" rather than 
      "FOO#:BAR". (If not "#:", some other prefix dispatch.) Thinking ahead
      to the multi-level packages for a moment, and given that package ids
      are strings (not symbols), would one write "FOO#:BAR:BAZ" or
      "FOO#:BAR#:BAZ" or ... I would prefer they lead off with an
      identification that the symbol coming up will be an internal one 
      and then give a normal qualified reference. eg, you could define 
      #: to just bind some (unexported) variable 
      *COMPLAIN-ABOUT-INTERNAL-PACKAGE-REFERNCES* to NIL and re-call READ
      without hairing up the language syntax.

    * If "#:" is used to mark symbols with no package cell, it is overloaded
      and visually misleading to have it mean both things.

(2) I dislike visually marking symbols that have no package cell.

    * When writing symbols out to a file and reading them back in, there's
      a high percentage of chance it really doesn't matter what package
      they are read into. To take a simple example, 
       (READ-FROM-STRING (FORMAT NIL "~S"
                    	     (LET ((V (GENSYM))) `(LAMBDA (,V) ,V))))
      won't even "work".

      You'd expect this with gensyms but its more irritating if you've 
      inherited some symbol from another package and you've uninterned
      the symbol from the source package. Suddenly, perfectly valid symbols
      may appear as if "gensymed" and will lose this property of being
      EQ.

      I guess the following properties are relevant ...

	(a) Symbols which were EQ before a PRINT-READ cycle should be EQ 
            afterward.
        (b) Symbols which were not EQ before a PRINT-READ cycle should not be
	    EQ afterward.
        (c) A symbol which was EQ to some other symbol not involved in
            a PRINT-READ cycle should still be EQ to it after such a cycle.

     Given that property (c) is in general very hard to assure, I still place
     a higher priority on (a) than on (b). Printing symbols out with no 
     annotation will guarantee (a) but may violate (b). Printing symbols out
     with the proposed "#:" marking (as I understand it) seems to violate 
     (a) while guaranteeing (b).


     Further, I think people will see "#:" coming out before gensysms for ages
     before they see the other case. I predict this will cause great debugging
     confusion for people that don't understand the other cases where this can
     happen and who have from many experiences come to associate "#:" with 
     gensyminess, not with the heuristic feature off of which it drives.

     An organized plan for treating gensyms would be nice, but in the absence
     of one (I don't think we have time for that now) I don't think that 
     marking things that appear to be gensyms.

     As a minor issue, "#:" would then be free for use in item (1) above.

(3) I'm not sure about using PUSHNEW rather than PUSH after a DELETE
    when calling things like USE-PACKAGE. It seems to me that users will
    expect the most recent call to USE-PACKAGE to have priority. Imagine
    a package A with an external symbol FOO on it. Imagine a package B 
    which does USE-PACKAGE A and then shadows FOO. Imagine some package C,
    the writer of which notices that A:FOO isn't provided in B and who doesn't
    realize that A is included in B. He might ask to USE-PACKAGE A and be
    confused that A:FOO still isn't visible. 

    I'm not so much saying this should be changed as I'm curious why things
    are supposed to happen as documented. Is there an alternative scenario
    that makes mine look less important?

(4) "If @b[unexport] is given a symbol that is already available
     as an internal symbol in the current package, it does nothing; ..."

    I guess my view was that "external" symbols are in some sense a subset
    of "internal" ones; ie, when working "internally" to a package, i expect
    "external" symbols are available (and they are). I was surprised, then,
    by this wording. Does it mean the same as, and would it be clearer as:

    "If @b[unexport] is given a symbol that is already available
     only as an internal symbol in the current package, it does nothing; ..."

(5) In DECLARE-PACKAGE's description , shouldn't you say @b[:nicknames], 
    etc. or @i[nicknames]. I should think @i[:nicknames] would be confusing.

(6) Re: LOAD binding *PACKAGE*
    The LispM has a problem with init files. People like to call pkg-goto
    and assign BASE,IBASE in their inits and find themselves thwarted by
    implicitly bound variables. A popular way to circumvent this problem 
    is by doing (PROCESS-RUN-FUNCTION #'(LAMBDA () (SETQ IBASE 10.)), etc.
    This seems pretty drastic. Will Common Lisp address this issue?

(7) Are packages always global, named objects?  Will there be a provision for 
    anonymous packages or packages rooted elsewhere besides GLOBAL?
    In such an event, should LIST-ALL-PACKAGES be constrained to return 
    even anonymous packages?

(8) IMPORT, EXPORT, etc. use the "current package".  I would prefer to have
    them take &OPTIONAL (PACKAGE *PACKAGE*) since I find it very ugly to write
    (LET ((PACKAGE *PACKAGE*)) (IMPORT ...)) if I happen not to have that 
    package selected.

(9) There are occasionally times when one would like a symbol to be printed
    with any package prefix unconditionally. Such is the case for APROPOS,
    for example. I would like the method by which I can make this happen be
    explicit. On the LispM, one resorts to binding PACKAGE to NIL or
    (pkg-find-package "GLOBAL"), but these "solutions" lose awfully if you
    get a breakpoint in those packages since you either end up finding you
    have a bad value for package (and recursively losing) or not finding 
    that you do (and losing in other ways). Perhaps a variable 
    *FORCE-PACKAGE-PREFIXES* which could be set T/NIL. Better still, perhaps
    a variable *PRINT-PACKAGE-PREFIXES* which could be set 
	:ALWAYS	Always print package prefixes
	:NEVER	Never print package prefixes
	:MAYBE	Print package prefixes when not "obvious"
	fn	A one-arg predicate which returns T if the package prefix 
		should be displayed and NIL otherwise.
    Setting it to :NEVER would be great when you want to do simple symbol
    manipulation unrelated to Lisp variables without getting bogged down in
    package I/O behavior. I have some applications where this would have been
    very handy.

--kmp

∂10-May-83  1557	FAHLMAN@CMU-CS-C 	suggestion for ballot: :allow-other-keys  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 10 May 83  15:56:35 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 10 May 83 18:57:12 EDT
Date: Tue, 10 May 1983  18:57 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   David A. Moon <MOON%SCRC-TENEX%MIT-MC@SU-DSN>
Cc:   common-lisp@SU-AI
Subject: suggestion for ballot: :allow-other-keys
In-reply-to: Msg of 10 May 1983  15:26-EDT from David A. Moon <MOON%SCRC-TENEX%MIT-MC at SU-DSN>


Urk!

I've always thought that &allow-other-keys was a crock, and that
unrecognized keywords should just be quietly ignored.  That would solve
this problem in a truly elegant way and speed up calls to keyword
functions by a moderate factor, since it takes a separate scan of the
argument list to look for bogus keywords.  I will admit that signalling
the unrecognized-keyword error is useful in catching spelling errors,
but a good editor top-level could take care of that.

Just thought I'd rasie this possibility before we add yet another
epicycle.

-- Scott

∂10-May-83  1641	@USC-ECL,@MIT-MC:BENSON@SPA-NIMBUS 	Function objects   
Received: from USC-ECL by SU-AI with TCP/SMTP; 10 May 83  16:35:19 PDT
Received: from MIT-MC by USC-ECL; Tue 10 May 83 13:26:59-PDT
Date: Tuesday, 10 May 1983, 13:11-PDT
From: BENSON at SPA-NIMBUS
Subject: Function objects
To: Common-Lisp%su-ai at usc-ecl

The Laser edition is inconsistent in its treatment of functions.  This
inconsistency is due to confusion between the name of a function and the
actual function object.  This confusion has been around for a long time,
and is manifested in many Lisp implementations where the name of a
function object and the object itself are the same.  To quote from the
Standard Lisp Report: "FUNCTION is like QUOTE but its argument may be
affected by compilation."

First, we need to state what we mean by a function object.  The
definition of the FUNCTIONP data type predicate says that it

"is true if its argument is suitable for applying to arguments, using
for example the FUNCALL or APPLY function."

The definition of APPLY states that its argument

"may be a compiled-code object, or a lambda expression, or a symbol; in
the latter case the global functional value of that symbol is used."

(Let's ignore compiled-code objects for the time being; we'll get back
to them later.)  This is the definition which confuses the name (symbol
or lambda expression) and the function object.  Conflicting with this
definition is the Functions section of the Progam Structure chapter
(Section 5.2, p. 42).  It states that

"Lambda-expressions and symbols as names of functions can appear only as
the first element of a function-call form, or as the second element of
the FUNCTION special form."

The definition of the FUNCTION special form, where FN is the second
element of the form, states that

"if FN is a symbol, the functional value of the variable whose name is
that symbol is returned.  If FN is a lambda expression, then a lexical
closure is returned."

Notice that the definition of APPLY doesn't even mention lexical
closures, yet these are the things which are produced by the FUNCTION
special form, which is presumably the preferred means of obtaining a
suitable object to use as an argument to APPLY!

The key to understanding all of this is to realize that the CAR of a
Lisp form (ignoring macros and special forms) is not "not evaluated," in
fact it is a function name which is evaluated to produce a function
object.  In Scheme this evaluation is the same as that used to produce
function arguments, i.e. the function EVAL.  Common Lisp must use a
different algorithm, because it permits symbols to have distinct
variable and function values.  The function which implements this
algorithm is not mentioned in the Common Lisp manual.  In fact I don't
know of any Lisp implementations which provide it; it is usually
open-coded (sometimes a no-op!) within EVAL.  For the sake of
discussion, let's call it FEVAL.  In fact the one we are most interested
in is *FEVAL, analogous to *EVAL, since this function must use the
current lexical environment in its evaluation process.

Evaluation of a form which represents an ordinary function call is thus:
FEVAL the CAR of the form, EVAL all the other elements of the list, call
the result of FEVAL with the EVALed arguments.  FEVAL is useful to
produce a function object which will not be called immediately.  The
FUNCTION special form says in effect: use FEVAL instead of EVAL to
produce this argument.  Conversely, EVAL is also useful in producing
function objects.  FUNCALL allows normal argument evaluation to return
a function object to be called.  Note that neither FUNCTION nor
FUNCALL is needed in Scheme precisely because EVAL and FEVAL are the
same.

FEVAL is a very simple function.  If its argument is a lambda
expression, it returns a closure of the expression over the lexical
environment.  If it is a symbol, the "functional variable" value of the
symbol in the lexical (or global) environment is returned.  Anything
else is an error.  As an upward-compatible extension, function specs as
provided in Zetalisp, such as (:PROPERTY FOO BAR), are treated
essentially the same as symbols.  They simply specify a place from which
to fetch a function object.

The semantics of compiled-code objects have not been described
extensively in the Common Lisp manual.  They are mentioned in the
spurious definition of APPLY above, which might lead one to think of
them as being "like lambda expressions, only faster."  In fact the only
sensible interpretation of a compiled-code object is "like FEVAL of a
lambda expression, only faster."  In other words, anything a lexical
closure can do, a compiled-code object can do.  This should be stated
explicitly in the manual in the data type section.

The argument to APPLY (and FUNCALL) can be a compiled-code object or a
lexical closure; anything else is an error.  A language standard which
considers symbols or lambda expressions to be functions is perpetuating
the confusion described above.

To acheive the effect of using a symbol as a function as described above
(and currently implemented in Zetalisp, for example), that is, using the
global functional value at the time it is called, one must use a closure
which calls the function, e.g. to give BAR as a functional argument to
FOO, where BAR's definition may change between the call to FOO and the
FUNCALL of its functional argument, use: 
 
(FOO #'(LAMBDA (X) (BAR X)))	;BAR is a function of one argument

instead of

(FOO 'BAR)

In general, if the number of arguments is unknown:

(FOO #'(LAMBDA (&REST X) (APPLY #'BAR X)))

Or, if you really mean the global function value, not the lexical:

(FOO #'(LAMBDA (&REST X) (APPLY (SYMBOL-FUNCTION 'BAR) X)))

The current language definition does not provide either a function which
takes a lambda expression and a lexical environment and returns a
lexical closure (*FEVAL) or functions to extract these components from
an existing lexical closure.  These aren't strictly necessary, but
without them many useful parts of a programming environment must be
written non-portably.  For example, GRINDEF is impossible in portable
Common Lisp, since SYMBOL-FUNCTION must return either a lexical closure
or a compiled-code object.  A structure editor which can redefine a
function requires both selector functions and the constructor function,
since it must create a new closure with the modified function body.

I recommend that lexical environments be included in the language as
first-class objects.  *EVAL and EVALHOOK would then be defined to take
exactly two arguments.  ENCLOSE (*FEVAL restricted to lambda
expressions) takes a lambda expression and a lexical environment and
returns a lexical closure.  CLOSURE-EXPRESSION and CLOSURE-ENVIRONMENT
take a lexical closure and return its components.  The constant
NULL-ENVIRONMENT, the empty lexical environment, should be defined.  The
structure of a lexical environment need not (indeed, should not) be
specified. These additions are not major and would aid immensely in
supporting a truly lexical Lisp.

∂10-May-83  1721	@USC-ECL,@MIT-XX:BENSON@SPA-NIMBUS 	Summary of message on function objects 
Received: from USC-ECL by SU-AI with TCP/SMTP; 10 May 83  17:19:41 PDT
Received: from MIT-XX by USC-ECL; Tue 10 May 83 17:15:22-PDT
Date: Tuesday, 10 May 1983, 17:12-PDT
From: BENSON at SPA-NIMBUS
Subject: Summary of message on function objects
To: BENSON at SPA-NIMBUS, Common-Lisp%su-ai at usc-ecl
In-reply-to: The message of 10 May 83 13:11-PDT from BENSON at SPA-NIMBUS

To summarize the important points of the previous note:

The Common Lisp manual must make clear the distinction between function
objects (lexical closures and compiled-code objects) and function names
(lambda expressions and symbols), and the evaluation process which
produces function objects from function names.

The first argument to APPLY or FUNCALL (for which FUNCTIONP is
true) must be a compiled-code object or a lexical closure.  Anything
else is an error.

Lexical environments are Lisp objects which need a section in the data
types chapter.  ENCLOSE takes a lambda expression and a lexical
environment and returns a lexical closure.  CLOSURE-EXPRESSION takes a
lexical closure and returns the lambda expression which it encloses.
CLOSURE-ENVIRONMENT takes a lexical closure and returns the lexical
environment it was closed over.

∂10-May-83  1728	@MIT-MC:MOON@SCRC-TENEX 	not about suggestion for ballot: :allow-other-keys
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  17:28:39 PDT
Date: Tuesday, 10 May 1983  20:26-EDT
From: MOON at SCRC-TENEX
To:   Scott E. Fahlman <Fahlman at CMU-CS-C>
Cc:   common-lisp at SU-AI
Subject: not about suggestion for ballot: :allow-other-keys
In-reply-to: The message of Tue 10 May 1983  18:57 EDT from Scott E. Fahlman <Fahlman@CMU-CS-C>

    Date: Tue, 10 May 1983  18:57 EDT
    From: Scott E. Fahlman <Fahlman@CMU-CS-C>
    In-reply-to: Msg of 10 May 1983  15:26-EDT from David A. Moon <MOON%SCRC-TENEX%MIT-MC at SU-DSN>

    I've always thought that &allow-other-keys was a crock, and that
    unrecognized keywords should just be quietly ignored.
Does this mean you also think that missing required arguments should
default to nil and extraneous arguments should be quietly ignored?
Note that I said that supplying an unrecognized keyword "is an error",
not "signals an error."  This was quite deliberate.  I also never said
whether the checking was done at run time, link time, or compile time,
also quite deliberately.  The rest of your message speaks for itself.

∂10-May-83  1807	FAHLMAN@CMU-CS-C 	&allow-other-keys
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 10 May 83  18:07:30 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 10 May 83 21:08:29 EDT
Date: Tue, 10 May 1983  21:08 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   MOON%SCRC-TENEX @ mit-mc
Cc:   common-lisp@SU-AI
Subject: &allow-other-keys


No, I don't think that missing required args should default to nil or
that extraneous arguments should be ignored.  But keyword lists have a sort
of built-in safety about them that counted-and-ordered argument lists
don't have.  Or at least they would if misspelling could be ruled out.

I don't really expect to win on this one, and am not entirely sure that
I want to.  A trial balloon, as they say in Washington.

If we continue with the current &allow-other-keys business, the
:allow-other-keys extension doesn't seem too bad.  It adds complexity,
but I have nothing less complex to propose.

-- Scott

∂10-May-83  1841	FAHLMAN@CMU-CS-C 	package proposal comments  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 10 May 83  18:40:43 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 10 May 83 21:41:15 EDT
Date: Tue, 10 May 1983  21:41 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   DILL@CMU-CS-C
Cc:   common-lisp@SU-AI
Subject: package proposal comments
In-reply-to: Msg of 10 May 83 01:14:21 EDT from DILL


A quick response to your comments (which reached me to late to be
reflected in the latest package proposal):

Transitive and Intransitive inheritance: The latest proposal provides
the user with a choice.

Copy vs. Pointer semantics: Both systems have problems.  I now believe
that copy semantics has worse problems, but I could be wrong.  In any
event, I'm reluctant to completely redo the proposal the other way
unless the problems with deep-binding inheritance are fatal.

Packages as the unit of loading and compilation:  We've been around this
a few times, and always come up with lots of problems.  Loading the
right set of files is a tricky and implementation-dependent business.  I
would like to see a comprehensive version-maintenance system in Common
Lisp someday (need a thesis topic?) but there is no way we're going to
get all that ironed out in time to make the first edition of the manual.

-- Scott

∂10-May-83  1943	@MIT-MC:MOON@SCRC-TENEX 	Packages  
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  19:40:57 PDT
Date: Tuesday, 10 May 1983  22:19-EDT
From: MOON at SCRC-TENEX
To:   Kent M. Pitman <KMP at MIT-MC>
Cc:   Common-Lisp at SU-AI
Subject: Packages
In-reply-to: The message of 10 May 1983 18:09 EDT from Kent M. Pitman <KMP @ MIT-MC>

    Date: 10 May 1983 18:09 EDT
    From: Kent M. Pitman <KMP @ MIT-MC>

I'd like to respond to this at length since I think I understand all this stuff now.

    (1) I dislike "#:" in the middle of a name for several reasons.

        * I think it is ugly. It visually breaks up the symbol in a bad way. 

This is precisely why I suggested it.  The internal-symbol qualified name syntax
is very rarely used, and if it is used in a program the programmer is almost
certainly doing something wrong, probably due to a misunderstanding.  So I
thought it was a good idea for it to be ugly.

        * "#" is defined as a token terminator. This would have to be redefined.
          I note (p219, Colander Edition -- sorry; I have no Laser edition)

It's unfortunate that you weren't sent a Laser edition; this was fixed at the
discussion meeting in Pittsburg last August.

        * I would prefer a prefix notation such as "#:FOO:BAR" rather than 
          "FOO#:BAR". (If not "#:", some other prefix dispatch.) Thinking ahead
          to the multi-level packages for a moment, and given that package ids
          are strings (not symbols), would one write "FOO#:BAR:BAZ" or
          "FOO#:BAR#:BAZ" or ... I would prefer they lead off with an
          identification that the symbol coming up will be an internal one 
          and then give a normal qualified reference. eg, you could define 
          #: to just bind some (unexported) variable 
          *COMPLAIN-ABOUT-INTERNAL-PACKAGE-REFERNCES* to NIL and re-call READ
          without hairing up the language syntax.

I can't make any sense of this.  #: is no more and no less hairing up the
language syntax than : itself is.

        * If "#:" is used to mark symbols with no package cell, it is overloaded
          and visually misleading to have it mean both things.

I don't think so; certainly no more than dot is overloaded.  Before a symbol
and inside of a symbol are just different, that's all.

    (2) I dislike visually marking symbols that have no package cell.

This was agreed upon in August.  Again it's unfortunate that you never saw a
Laser edition manual.  But if we go back and argue over everything we've done
in the past year we'll never get this language defined.  Doubly unfortunate
that you never saw the quotation from the Federalist papers in the front of
the laser edition.  As it happens I don't much like marking uninterned symbols
specially myself, but I'm not going to quarrel over it.  Easy enough to
put in a *prinfoo* flag to turn it off it really irritates.

        * When writing symbols out to a file and reading them back in, there's
          a high percentage of chance it really doesn't matter what package
          they are read into. To take a simple example, 
           (READ-FROM-STRING (FORMAT NIL "~S"
                        	     (LET ((V (GENSYM))) `(LAMBDA (,V) ,V))))
          won't even "work".

This just means that you're one of the large community of users who will
always run with *princircle* set to t, commendably preferring correctness 
over efficiency.  This doesn't have much to do with packages, or even symbols,
though, really.

          You'd expect this with gensyms but its more irritating if you've 
          inherited some symbol from another package and you've uninterned
          the symbol from the source package. Suddenly, perfectly valid symbols
          may appear as if "gensymed" and will lose this property of being
          EQ.

Since inheriting is "by reference" rather than "by value", this can't
happen.  The inherited symbol isn't accessible if it gets uninterned from
the place it is being inherited from.  This is important.
But perhaps you really meant to say "imported."  You are right about
this misfeature, which was mentioned in Fahlman's documentation.  Removing
the flagging of uninterned symbols would hardly fix this misfeature, it
would simply obscure it somewhat, since now you would have "perfectly
valid symbols" that would print without a package prefix when they should
have had a prefix.  The only advice I can give is if you move a symbol from
one package to another and forget to setf the symbol-package to the new
package, then you forgot something.

          I guess the following properties are relevant ...

    	(a) Symbols which were EQ before a PRINT-READ cycle should be EQ 
                afterward.
            (b) Symbols which were not EQ before a PRINT-READ cycle should not be
    	    EQ afterward.
            (c) A symbol which was EQ to some other symbol not involved in
                a PRINT-READ cycle should still be EQ to it after such a cycle.

         Given that property (c) is in general very hard to assure, 

I can't think of any examples of cases where it is at all difficult to assure.
Can you supply one?

								    I still place
         a higher priority on (a) than on (b). Printing symbols out with no 
         annotation will guarantee (a) but may violate (b). Printing symbols out
         with the proposed "#:" marking (as I understand it) seems to violate 
         (a) while guaranteeing (b).

Again, *princircle* is the answer to this.  Of course it can only work within
a single form, so it isn't a complete answer, which by the very definition of
interning is impossible.

         Further, I think people will see "#:" coming out before gensysms for ages
         before they see the other case. I predict this will cause great debugging
         confusion for people that don't understand the other cases where this can
         happen and who have from many experiences come to associate "#:" with 
         gensyminess, not with the heuristic feature off of which it drives.

Maybe.  That depends on whether prefixes and infixes are considered to be
the same by most people.

    (3) I'm not sure about using PUSHNEW rather than PUSH after a DELETE
        when calling things like USE-PACKAGE. It seems to me that users will
        expect the most recent call to USE-PACKAGE to have priority. Imagine
        a package A with an external symbol FOO on it. Imagine a package B 
        which does USE-PACKAGE A and then shadows FOO. Imagine some package C,
        the writer of which notices that A:FOO isn't provided in B and who doesn't
        realize that A is included in B. He might ask to USE-PACKAGE A and be
        confused that A:FOO still isn't visible. 

Correcting your typo of USE-PACKAGE when you meant INCLUDE-PACKAGE, this
scenario is exactly why I pointed our in my comments the need for more
comprehensive handling of name clashes.  The order of searching ancestors
cannot be allowed to make a difference if we are to remain sane.

    (4) "If @b[unexport] is given a symbol that is already available
         as an internal symbol in the current package, it does nothing; ..."

        I guess my view was that "external" symbols are in some sense a subset
        of "internal" ones; ie, when working "internally" to a package, i expect
        "external" symbols are available (and they are). I was surprised, then,
        by this wording. Does it mean the same as, and would it be clearer as:

        "If @b[unexport] is given a symbol that is already available
         only as an internal symbol in the current package, it does nothing; ..."

The wording probably needs to be clarified.  I think Fahlman's intention was
that the terms "internal" and "external" were to be taken as mutually exclusive.
Internal is synonymous to neither "accessible" nor "present".

    (5) In DECLARE-PACKAGE's description , shouldn't you say @b[:nicknames], 
        etc. or @i[nicknames]. I should think @i[:nicknames] would be confusing.

    (6) Re: LOAD binding *PACKAGE*
        The LispM has a problem with init files. People like to call pkg-goto
        and assign BASE,IBASE in their inits and find themselves thwarted by
        implicitly bound variables. A popular way to circumvent this problem 
        is by doing (PROCESS-RUN-FUNCTION #'(LAMBDA () (SETQ IBASE 10.)), etc.
        This seems pretty drastic. Will Common Lisp address this issue?

In the Lisp machine, this was recently corrected by introducing a new special
form (macro), SETQ-GLOBALLY, along with accompanying functions SET-GLOBALLY,
SYMEVAL-GLOBALLY, MAKUNBOUND-GLOBALLY.  These operate on the global value of
a dynamic variable, regardless of any bindings that may currently be in effect.
They are slow.  SETQ-GLOBALLY is also undoable.  I hesitate to propose these
for Common Lisp right now while we are in a rush to get a consistent, stable,
documented language that we can all implement and use as a basis for future
standardized extensions.

    (7) Are packages always global, named objects?  Will there be a provision for 
        anonymous packages or packages rooted elsewhere besides GLOBAL?
        In such an event, should LIST-ALL-PACKAGES be constrained to return 
        even anonymous packages?

Fahlman wanted to keep the proposal simple so yes there is only one
namespace of package names and you aren't allowed to call the primitive
that creates a package object without giving it a name and linking it into
the data structure.

Packages are non-hierarchical so "rooted" makes no sense.  Are anonymous packages
good for something?

I expect that on the Lisp machine there will be a provision for nicknames
to a package that are only recognized in qualified names and only when
*package* is one of certain other packages.  This extension to Common Lisp
is good when renaming a whole group of related packages.  This may be what
you want.

    (8) IMPORT, EXPORT, etc. use the "current package".  I would prefer to have
        them take &OPTIONAL (PACKAGE *PACKAGE*) since I find it very ugly to write
        (LET ((PACKAGE *PACKAGE*)) (IMPORT ...)) if I happen not to have that 
        package selected.

I agree.

    (9) There are occasionally times when one would like a symbol to be printed
        with any package prefix unconditionally. Such is the case for APROPOS,
        for example. I would like the method by which I can make this happen be
        explicit. On the LispM, one resorts to binding PACKAGE to NIL or
        (pkg-find-package "GLOBAL"), but these "solutions" lose awfully if you
        get a breakpoint in those packages since you either end up finding you
        have a bad value for package (and recursively losing) or not finding 
        that you do (and losing in other ways). Perhaps a variable 
        *FORCE-PACKAGE-PREFIXES* which could be set T/NIL. 

This would be a good name but unfortunately the name that is consistent with
the other printer control flags is *PRINPACKAGE*.  I proposed this at one
point and would still like to see it; after we agree on the basic package
system I will send a message containing a small list of non-controversial
extensions like this which I would like to see included in the standard
language.

							   Better still, perhaps
        a variable *PRINT-PACKAGE-PREFIXES* which could be set 
    	:ALWAYS	Always print package prefixes
    	:NEVER	Never print package prefixes
    	:MAYBE	Print package prefixes when not "obvious"
    	fn	A one-arg predicate which returns T if the package prefix 
    		should be displayed and NIL otherwise.

Having more choices than T and NIL seems like a good idea here, although
I'm not sure that the full hair of a predicate would be used.

        Setting it to :NEVER would be great when you want to do simple symbol
        manipulation unrelated to Lisp variables without getting bogged down in
        package I/O behavior. I have some applications where this would have been
        very handy.

I don't understand this.  What problem is solved by changing it from the
default state (:MAYBE ?) to :NEVER?  No symbol you can type in without
a package prefix will be printed back out with one.

∂10-May-83  2012	FAHLMAN@CMU-CS-C 	Packages    
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 10 May 83  20:12:21 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 10 May 83 23:10:00 EDT
Date: Tue, 10 May 1983  23:09 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   MOON%SCRC-TENEX@mit-mc, Kent M. Pitman <KMP@MIT-MC>
Cc:   Common-Lisp@SU-AI
Subject: Packages
In-reply-to: Msg of 10 May 1983  22:19-EDT from MOON at SCRC-TENEX


I essentially agree with everything MOON said in response to KMP's
message.  I was about to send a very similar message myself.

The only thing I would add is that INIT files are nowhere defined in the
white pages (and probably should not be), but if they were, there is no
reason that they have to follow all the rules LOAD does.  Certain kinds
of state, like the value of *PACKAGE*, want to be preserved across a
LOAD, while an INIT file may well want to change assorted aspects of the
global state.  So I don't see a problem here.

I do have some problems with a couple of the things MOON suggested in
his earlier message on packages, and I'm working on a response to that.

-- Scott

∂10-May-83  2039	ALAN@MIT-MC 	Summary of message on function objects & :allow-other-keys    
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  20:39:36 PDT
Date: 10 May 1983 23:41 EDT
From: Alan Bawden <ALAN @ MIT-MC>
Subject:  Summary of message on function objects & :allow-other-keys
To: BENSON @ SPA-NIMBUS
cc: Common-Lisp @ SU-AI
In-reply-to: Msg of 10 May 1983 17:12-PDT from BENSON at SPA-NIMBUS

:allow-other-keys sounds ok to me.

    Date: Tuesday, 10 May 1983, 17:12-PDT
    From: BENSON at SPA-NIMBUS

    The first argument to APPLY or FUNCALL (for which FUNCTIONP is
    true) must be a compiled-code object or a lexical closure.  Anything
    else is an error.

I would object to this.  I certainly agree that there is an inelegance in
allowing symbols to serve as functions when passed as arguments to APPLY
and FUNCALL (Algol 68 would be proud of a feature like this), but this is
not an inelegance with any far-reaching consequences (assuming we clarify
the manual about the term "closure", which it does tend to use rather
randomly), and it is a traditional convenience supported by most of Common
Lisp's ancestors.

I don't see any compelling reason to introduce an ENCLOSE function, or to
make environments first-class data objects.  The latter seems like a
unnecessary constraint on implementors.  (I might go for an ENCLOSE like in
the Scheme "Revised Report" that takes a \representation/ of an
environment, but I still don't see the need for it.)

A function to retrieve the lambda-expression from a closure also seems to
me to be assuming a bit to much about the internals of a closure (why
should that information still be there?  What happens if it is a \compiled/
closure).  I presume each implementation can provide rational debugging
facilities to allow me to determine just where a closure originated.

∂10-May-83  2118	ALAN@MIT-MC 	Two New Package Proposal Comments (and a grotesque suggestion)
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  21:18:26 PDT
Date: 11 May 1983 00:20 EDT
From: Alan Bawden <ALAN @ MIT-MC>
Subject:  Two New Package Proposal Comments (and a grotesque suggestion)
To: Fahlman @ CMU-CS-C
cc: common-lisp @ SU-AI
In-reply-to: Msg of Tue 10 May 1983  02:51 EDT from Scott E. Fahlman <Fahlman at CMU-CS-C>

In Newton's init file it says: (use-package calculus).  I presume this is a
typo for (use-package "calculus") or perhaps (use-package 'calculus).

I also presume

(declare-package "phlogiston"
  :export ("heat-flow" "cold-flow" "make-fire-bottle"))

should read

(declare-package "phlogiston"
  :export ("HEAT-FLOW" "COLD-FLOW" "MAKE-FIRE-BOTTLE"))

Since the case of these various string arguments will become the case of
the exported symbols.  It sure does SHOUT at you though.  

If we allowed symbols to be treated as strings here, then

(declare-package "phlogiston"
  :export (:heat-flow :cold-flow :make-fire-bottle))

will work, although it is a bit misleading.  Perhaps

(declare-package "phlogiston"
  :export (#:heat-flow #:cold-flow #:make-fire-bottle))

???

∂10-May-83  2146	FAHLMAN@CMU-CS-C 	package.mss.108  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 10 May 83  21:45:36 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 11 May 83 00:46:19 EDT
Date: Wed, 11 May 1983  00:46 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   moon%scrc-tenex@mit-mc
Cc:   common-lisp@su-ai
Subject: package.mss.108


Dave,

I've got no problem with any of your "small" issues.  I'll make all
those changes.

The use of a symbol argument (not a string) in FIND-ALL-SYMBOLS was
deliberate.  It didn't seem to me that interning a symbol (internally in
the user package or wherever the user is typing) was something
particularly to be avoided.  With a string, you get all the issues of
case, and with a symbol argument you automatically get the intuitive
thing.  But I've got no real problem with allowing either a string or a
symbol here.

On the two larger issues you raise, I think we have some fundamental
disagreements.

    Medium:

    I'm not completely happy with declare-package and the :export keyword.  I
    don't like the idea of package A exporting symbols from package B; what if
    there is a typographical error, a conceptual mistake, or an obsolete symbol
    in the list supplied by package A, which is a duplicate of package B's
    list?

The symbols that are put into B by a DECLARE-PACKAGE statement in file A
are declared in an export list, and you have to be careful when typing
export lists.  There is no reason to believe that B is going to be
sloppier than A.

There is, of course, the problem of these lists getting out of synch,
but I think that this problem is not likely to be a serious one, since
the list in B is supposed to be a subset of the list in A -- B just
declares those symbols from A that it actually uses.  If A gets
augmented, that causes no problem for B.  If something that B uses gets
taken out of A (rare compared to augmentation), you're going to end up
with an undefined function or unbound symbol bug, but that is
unavoidable under any scheme.  You also end up with a stray external
symbol in package B because of the declaration in A, but the chances
that this stray symbol is really going to screw anyone seem pretty small
to me.

So you have an error (getting out of synch) that COULD occur in a rare
situation (removing an external symbol from some package's interface),
and that is unlikely to cause trouble if it does occur.

I don't see how the "owner vs. user" error checking that you advocate
can work unless you require that the exporting package be loaded before
the using package (in which case the user doesn't need to declare the
package at all).  In files that use external symbols from one another, all
of the exports would have to be done before either file is loaded -- the
package creation and exporting would have to be split into a separate
file.  Admittedly this is safer, but it is also a LOT less convenient.
I just don't think that the danger of an occasional stray external, as
described above, is worth that sort of restriction.  Unless I'm
overlooking some more common source of errors or you have some way to do
the consistency checking without restricting load-order, I feel strongly
that we should keep PACKAGE-DECLARE the way it is.

    Large:

    In your writeup, name clashes are only discussed under IMPORT.  Name
    clashes should be given their own discussion section, and the following
    functions should be required to check for name clashes: EXPORT, IMPORT,
    USE-PACKAGE, INCLUDE-PACKAGE, and the implicit calls to those functions
    from MAKE-PACKAGE, DECLARE-PACKAGE, and IN-PACKAGE.  When the externals of
    a package are altered, the check for name clashes must extend to all
    packages that inherit from that package (via either use or include).  A
    name clash occurs when there is an attempt to make a symbol accessible in a
    package with the same name as a distinct symbol already accessible in that
    package, except when shadowing has been used to declare the user's
    intentions (there is a symbol already accessible in the package, with
    the same name, that was mentioned by SHADOW).  When a name clash occurs,
    a correctable error is signalled.

Well, there are two cases here.  I have no strong objection to making
IMPORT, USE-PACKAGE, and INCLUDE-PACKAGE look around when they are
called and cause a correctable error if some symbol is about to be
shadowed.  We would have to add some sort of :INTENTIONALLY-SHADOWING
list to these forms so that the error can be suppressed for specific
known clashes, but that's OK.  I also have no objection to having EXPORT
look at its package's ancestors and signal an error if the
newly-exported symbol would shadow an inherited one.

What I object to very strongly (I think) is the notion that any of these
operations, when performed in package X, have to worry about what's
going on down in the descendant packages.  It's tricky enough to make
this work looking up the tree, and I think it's impossible to sort it
out looking down.  All sorts of things might have been shadowed and moved
around by explicit agreement, and trying to decide after the fact what
is to be an error would be impossible.

Once again, we are talking about adding a LOT of conceptual hair to
handle a problem that will seldom occur and that will probably not screw
anyone if it does occur.  It will very rarely be the case that you want
to mess with the external symbols of a package after other packages have
begun using it, and even if you do, it is unlikely to cause any trouble.
If (EXPORT FOO) is called in package X and package Y, which uses X, has
no FOO of its own, there's no problem.  If Y does have a FOO, it will
continue to use its own FOO, and things are no worse than before.  If Y
includes X (relatively rare), it is just the same, except that Y's
descendants now see X:FOO, while Y sees its own internal FOO.  But the
descendants couldn't have wanted to get Y's internal FOO, so this is OK.
I'm sure there's some way to construct a bug out of all this, but it
doesn't look to me like it's going to be a problem for real users.

-- Scott

∂10-May-83  2236	FAHLMAN@CMU-CS-C 	[Mailer: Message of 11 May 83 00:55:02 EDT]    
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 10 May 83  22:36:21 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 11 May 83 00:58:57 EDT
Date: Wed, 11 May 1983  00:58 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   common-lisp@su-ai
Subject: [Mailer: Message of 11 May 83 00:55:02 EDT]

Date: 11 May 83 00:57:16 EDT
From: The Mailer Daemon <Mailer>
To:   <FAHLMAN>
Re:   Message of 11 May 83 00:55:02 EDT

Message failed for the following:
common-lisp@SU-AI: Timed out waiting for FTP reply
            ------------
Received: ID <FAHLMAN@CMU-CS-C>; 11 May 83 00:55:02 EDT
Date: Wed, 11 May 1983  00:55 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   Alan Bawden <ALAN@MIT-MC>
Cc:   common-lisp@SU-AI
Subject: Two New Package Proposal Comments (and a grotesque suggestion)
In-reply-to: Msg of 11 May 1983 00:20 EDT from Alan Bawden <ALAN at MIT-MC>


I'm not too fond of your grotesque suggestion.

I just got done telling MOON that people are unlikely to have typos in
the :export part of DECLARE-PACKAGE and you come up with this.  Sigh!

This string/case business is clearly a source of typos just waiting to
happen, so something has to be done about that.  Also, I guess if you
call EXPORT, the system should see how long you've been awake and signal
a correctable error if it's more than 20 or so hours.  Only the
clear-headed should be allowed to touch packages.

-- Scott

∂10-May-83  2350	KMP@MIT-MC 	Request for clarification about "package users/owners"    
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  23:50:02 PDT
Date: 11 May 1983 02:48 EDT
From: Kent M. Pitman <KMP @ MIT-MC>
Subject:  Request for clarification about "package users/owners"
To: Fahlman @ CMU-CS-C, Moon @ SCRC-TENEX
cc: Common-Lisp @ SU-AI

    "...  I don't like the idea of package A exporting symbols from 
     package B; what if there is a typographical error, a conceptual mistake,
     or an obsolete symbol in the list supplied by package A, which is a 
     duplicate of package B's list?..."

    "...I don't see how the "owner vs. user" error checking that you advocate
     can work unless you require that the exporting package be loaded before
     the using package (in which case the user doesn't need to declare the
     package at all)..."

    "What I object to ... is the notion that any of these operations,
     when performed in package X, have to worry about what's going on down
     in the descendant packages..."

To paraphrase a popular slogan,...

  Packages don't export symbols, programs export symbols.

Programs have meaning even (especially) after all its symbols have been
seen and interned by READ, and possibly after the binding of *PACKAGE*
has gone away. A program does not exist "in a package". The names of the
entry points into a package are the only thing which are in the package.
Anything else is simply code which sets up or implements some feature 
which allows that entry point does what it does, but properly speaking
that code has nothing at all to do with packages. There is certainly no
property about the code from a file which says "I am in the ... package."
At best, packageness is a property of a written program's syntax. Not
all programs, however, are written. Some, for example, are consed on the
fly. Some, perhaps, are even compiled on the fly.

I acknowledge Moon's concern about users vs owners of packages having
various rights which may not be equivalent; I don't here want to take a
stand on that issue. My real aim is to say that I am not sure I agree
that it is trivially obvious what it means for one to be "in a package"
or not in one, so the idea of error checking or otherwise controlling 
it seems exceedingly tricky/ill-defined.

I hope my question is clear. It may well be that you mean something
completely reasonable, but if so, I am not sure what that might be.
If this message isn't clear, send me private mail and I'll clarify
the question in greater length ... 
--kmp

∂10-May-83  2349	@MIT-MC:MOON@SCRC-TENEX 	package.mss.108
Received: from MIT-MC by SU-AI with TCP/SMTP; 10 May 83  23:47:46 PDT
Date: Wednesday, 11 May 1983  02:28-EDT
From: MOON at SCRC-TENEX
To:   Scott E. Fahlman <Fahlman at CMU-CS-C>
Cc:   common-lisp at su-ai
Subject: package.mss.108
In-reply-to: The message of Wed 11 May 1983  00:46 EDT from Scott E. Fahlman <Fahlman@CMU-CS-C>

    Date: Wed, 11 May 1983  00:46 EDT
    From: Scott E. Fahlman <Fahlman@CMU-CS-C>

    The use of a symbol argument (not a string) in FIND-ALL-SYMBOLS was
    deliberate.  It didn't seem to me that interning a symbol (internally in
    the user package or wherever the user is typing) was something
    particularly to be avoided.  With a string, you get all the issues of
    case, and with a symbol argument you automatically get the intuitive
    thing.  But I've got no real problem with allowing either a string or a
    symbol here.

Just in case you didn't catch it the first time around, my point here was
that if you want to find out "are there any symbols named X, and if so
where are they", asking the question shouldn't perturb the environment in a
way that changes the answer, by creating a possibly-new symbol named X.  In
particular it's quite a useful response when FIND-ALL-SYMBOLS tells you
"no, there aren't any symbols named X, anywhere".  Let's just make it
accept either a symbol or a string.  Users calling it directly will pass
symbols, probably, while user-interface tools will tend to pass strings.

        I'm not completely happy with declare-package and the :export keyword.  I
        don't like the idea of package A exporting symbols from package B; what if
        there is a typographical error, a conceptual mistake, or an obsolete symbol
        in the list supplied by package A, which is a duplicate of package B's
        list?

    There is, of course, the problem of these lists getting out of synch,
    but I think that this problem is not likely to be a serious one, since
    the list in B is supposed to be a subset of the list in A -- B just
    declares those symbols from A that it actually uses....
    I don't see how the "owner vs. user" error checking that you advocate
    can work unless you require that the exporting package be loaded before
    the using package (in which case the user doesn't need to declare the
    package at all).

Let me be extra explicit here.

"Loading" a package is what the program that "owns" that package does.

"Declaring" a package is something anyone who uses it can do, if they don't
require that the package's program be loaded before they are.  A package
may be declared any number of times, both before and after it has been
loaded.

A package contains a bit that is set when it is "loaded".

Declaring a package after it has been loaded checks that the symbols exported
by the declaration are a subset of the package's externals, native or inherited.

Declaring a package before it exists creates the data structure but doesn't
mark it loaded.  Declaring a package before it is loaded creates externals
according to the export list and does inheriting according to the include
list, and doesn't do error checking.

Loading a package that already exists, because it was declared one or more
times before it was loaded, checks that the externals and inclusions the
package has are subsets of those declared by the guy who is now loading it,
who is the only one who knows what is really right.

The rule that is implemented is that what the declarer says about the
package must be a subset of what the loader says about it.  This is checked
as soon as they both have spoken.  If the rule is violated, a continuable
error is signalled and continuing acts as if the declarer knew what he was
doing better than the loader.

Note that declaring a package that is constructed by inclusion of other
packages requires that the declarer, unmodularly, understand this structure.
Maybe you don't use declaring much for that kind of package.

[This paragraph has nothing to do with the subject at hand, and applies
equally well to any package system, or any system that has globally named
objects.]
We arrange for something reasonable to happen if a package is loaded
twice; the issue here is figuring out whether it was loaded by the same
program, which was loaded twice for some reason, or whether two different
programmers chose the same package name, unbeknownst to each other.  This
is probably done in an implementation-dependent way (the Lisp machine will
base it on the name of the file containing the code that loaded the
package).  Some implementations will choose not to detect this kind of name
conflict at all, while others will choose always to signal an error when a
package is loaded twice, assuming that if the user is loading a program
twice he knows about it and will continue from the error.  (Previously I
called this "making" a package, but that could be taken to mean the
primitive that creates the package data structure.)

        In your writeup, name clashes are only discussed under IMPORT....

    What I object to very strongly (I think) is the notion that any of these
    operations, when performed in package X, have to worry about what's
    going on down in the descendant packages.  It's tricky enough to make
    this work looking up the tree, and I think it's impossible to sort it
    out looking down.  All sorts of things might have been shadowed and moved
    around by explicit agreement, and trying to decide after the fact what
    is to be an error would be impossible.

I don't know what direction is "up" for you and what direction is "down".
But no matter which way I interpret it I don't believe it is impossible, or
even hard.  It is useless to do name clash checking if you don't do it
completely.  More below.

My previous proposal said that every package contained a list of the symbols
in that package that had been shadowed, which was specifically remembered
for the use of name-clash error checking.  Indeed if you don't remember
what the user said to shadow you can't do name-clash checking.

    Once again, we are talking about adding a LOT of conceptual hair to
    handle a problem that will seldom occur and that will probably not screw
    anyone if it does occur.

In practice, this is the problem that makes people frequently curse the day 
packages were ever invented.  The point here is that while it may seem rare
and unlikely to screw anyone to you, from your present abstract viewpoint,
when a name clash occurs it is so unpredictable, and so pernicious in its
effects, that it is very important to have iron clad assurance that these
things can't happen.  If I may make a strained analogy, suppose we came up
with a really neat efficient garbage collection algorithm, based on hashing,
which worked really well except that one in a million times, or say one
in 2↑32 times, it would throw away something it should have kept.  Well,
probably no one will ever notice, it's pretty rare, right?

Incidentally I don't believe that this adds any conceptual hair whatsoever.
It adds a small amount of implementation hair, in that you need backpointers
from packages to their inheritors, but that is not conceptual hair.  You
already have the concept of shadowing.  The rule "no two symbols with the
same name may be accessible from the same package, unless one of them was
explicitly declared via shadowing" seems the soul of simplicity to me.
I'm then just proposing that the rule be enforced, i.e. it be "signals
an error" rather than "is an error."
Much better than the same rule, plus "except when include-package is used
to more than one level" or "except when export is called after intern has
already been called" or "except when debugging late at night and typing
spastically."

∂11-May-83  0309	KMP@MIT-MC 	New Error Proposal
Received: from MIT-MC by SU-AI with TCP/SMTP; 11 May 83  03:09:32 PDT
Date: 11 May 1983 05:59 EDT
From: Kent M. Pitman <KMP @ MIT-MC>
Subject:  New Error Proposal
To: Moon @ SCRC-TENEX
cc: Common-Lisp @ SU-AI

The new error proposal looks mostly good. A few remarks, though...

* Based on heavy experience with the old and new error system, I feel 
  strongly that one consistent irritation of the old system was that 
  it didn't clearly distinguish between the cause and correction of
  an error and that CERROR as currently proposed will perpetuate that
  problem. eg, when you ran with error messages turned on but errors 
  ignored, typeout like "continuing will do such-and-so" was at least
  irritating and frequently wrong. I put out for discussion the idea
  that the CERROR should be modified as follows...

  CERROR format-string-1 format-string-2 &rest args
  Signal an error, with the message constructed by applying FORMAT to
  format-string-1 and the arguments. If the debugger is entered, it
  may choose to offer a message composed by calling FORMAT on 
  format-string-2 and the arguments, describing what will happen if
  the error is proceeded.  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"
	          "~1G:~[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."
		  "Replace ~S and try again." X)
	  (FORMAT T "~&New word: ")
	  (SETQ X (READ)))

* It occurs to me that the naming of CTYPECASE and ETYPECASE might 
  be solved in a completely different way. Rather than adding new
  special forms, one could make several kinds of otherwise clauses.
  The argument against this might be that it means more special cases of
  symbols in the case-list position, making that position more visually
  ambiguous. The counter-argument (held by some (eg, me)) is that people
  should use parens around everything but the otherwise options anyway.
  Examples:
	(SETQ X 1/3)
	(TYPECASE X
	  ((INTEGER) (- X))
	  ((SYMBOL)  (INVERSE X))
	  (:OTHERWISE-ERROR))
	Error: The value of X, 1/3, was neither an integer nor a symbol.
	(TYPECASE X
	  ((INTEGER) (- X))
	  ((SYMBOL)  (INVERSE X))
	  (:OTHERWISE-CERROR))
	Error: The value of X, 1/3, was neither an integer nor a symbol.
        Entering Debugger. Options:
           Meta-A: Store a new value in X and retry erring code.
           Meta-B: Return to Lisp toplevel.
           Meta-C: Logout
        >> Meta-A
        New Value for X: 9
        -9

* I liked your stating explicitly not to put "Error: " at the head of
  error messages. I would further like it specified that multi line error
  messages should not be padded (with spaces, ";", etc.) because tools such
  as the debugger (or whatever) will take care of padding lines with the 
  appropriate text.
  (ERROR (FORMAT NIL "FOO~%BAR"))
  should print out as:
    >>Error: FOO
             BAR
  not as
    >>Error: FOO
    BAR
  Ditto for the continuation string. The LispM currently has the bug
  that proceed options come out as:
    s-A:     This is a proceed option
    extending over multiple lines.
    s-B:     This is another.
  when
    s-A:     This is a proceed option
             extending over multiple lines.
    s-B:     This is another.
  would be better. Note that (ERROR (FORMAT NIL "FOO~% BAR"))
  would want to come out like
    >>Error: FOO
              BAR
  The reason for guaranteeing something like this is that users will frequently
  see the error coming out only in the debugger and may feel an urge to write
  (ERROR (FORMAT "FOO~%~16TBAR")) or some such so it'll look pretty. If another
  program gets ahold of such a format string and tries to use it elsewhere,
  though, it'll look like garbage.  Better the user should just be told flat out
  that "any necessary padding for continuation lines will be taken care of". eg,
  I have seen Maclisp code where users did:
    (ERROR (FORMAT NIL "FOO~%;BAR")) 
  since they  knew that the first line would have a leading ";" and the rest
  would not. If the error message style is with leading, that should be supplied
  on line 1 and on continuation lines by the system.

  This also takes care of people who try to assume that line 1 will be shorter
  than subsequent lines because they know a 20 character leader will occur on
  that line and tends to produced multi-line messages where lines have balanced
  lengths, rather than multi-line messages where the first line is considerably
  shoerter than subsequent lines.

* I don't see any reason why
  (ABORT-PROGRAM)
  can't be a synonym for what the LispM calls (SIGNAL 'SYS:ABORT). This
  is a pretty useful thing to put on interrupt characters. All you have to
  do is add an additional special form
  (CATCH-PROGRAM-ABORTS ...) or some such which does
  (CONDITION-CASE ()
     (PROGN ...)
   (SYS:ABORT ...))
  on the LispM. In a Lisp where conditions didn't exist, people could do
  the equivalent with CATCH/THROW.

  In fact, I don't know why just ABORT and CATCH-ABORT aren't adequate names.
  I find the word "program" ambiguous on a mainframe between meaning the 
  toplevel form I invoked in my read-eval-print loop and the exec command I
  used to invoke the Lisp. (ie, the c-Abort vs c-m-Abort distinction on the
  LispM). 

  In any case, I think these are valid kinds of issues for programmers to
  want to do in a machine independent fashion and should be included.

* In things like CHECK-ARG, etc. I see no reason their forms shoudln't be
  evaluable multiple times. It's essential that it be clearly documented,
  but that's easy to do. In the rare case that multiple evaluation would be
  a screw, a simple LET will probably fix the user's problem. If we later
  find out it's easy to guarantee single evaluation, it's easier to relax
  things and tell him so than it is to go the other route if people have 
  written code depending on single evaluation.

--kmp

∂11-May-83  1223	FAHLMAN@CMU-CS-C 	package.mss.108  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 11 May 83  12:22:33 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 11 May 83 15:22:28 EDT
Date: Wed, 11 May 1983  15:22 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   moon%scrc-tenex@mit-mc
Cc:   Common-Lisp@su-ai, fahlman@CMU-CS-C
Subject: package.mss.108


Tried to send this out earlier, but lost because of incompatible
mail-address protocols.  Trying again...


Dave,

OK, given your clarifications, I guess I am almost completely happy with
all the changes you propose.  I'm still a little unclear on how the
error-cheking in declare-package would be handled when a package is loaded
from multiple files (as the LISP package would be, for instance), but I
will review your note carefully and see if I can figure out something
appropriate.

I have a feeling that some of this emphasis on error checking is a
slight over-reaction to your experience with the old LispM package
system, which sometimes does seem like it's out to screw people in all
possible ways.  But given that Common Lisp will eventually be used by
all sorts of non-sophisticated users who would be totally mystified by a
package bug (now you see it, now you don't), I guess we'd better lean
way over in the direction of safety.  I yield to the voice of first-hand
experience.

While I'm on this theme, I withdraw my earlier suggestion that we flush
&allow-other-keywords.  Temporary insanity, the result of over-work.

I will put all these changes in tonight, unless you think it would go
quicker (fewer additional iterations) if you did the next edit.  Let me
know what you think will be easiest all around.  If I don't hear from
you by tonight, I'll do it.

-- Scott

∂11-May-83  1443	@USC-ECL,@MIT-ML:MOON@SCRC-TENEX 	need for export controls  
Received: from USC-ECL by SU-AI with TCP/SMTP; 11 May 83  13:01:33 PDT
Received: from MIT-ML by USC-ECL; Wed 11 May 83 12:59:08-PDT
Date: Wednesday, 11 May 1983  15:37-EDT
From: MOON at SCRC-TENEX
To:   common-lisp at su-ai
Subject: need for export controls

I was rather incoherent last night.  The scenario where a problem occurs
because a symbol is exported that shouldn't have been, perhaps because
of a mistake in a declare-package, is as follows:

Package A is use-package'd by packages B and C.
The programs in B and C each use a symbol BLORPH, knowing it
to be internal.  Let's say they use it as an indicator to put
on property lists.
A gets a new external, BLORPH, that it didn't have before.
Perhaps this is for real, or perhaps it's just a typo for BLEAGH.
If this external is added after B and C have already been loaded
and have each interned their own BLORPH, you get a name clash error
(even if only one of B and C have been loaded).
If this external is added when neither B nor C has been loaded yet,
when they do get loaded and make their BLORPH, they both get the
same symbol.  If they can ever get "near each other," e.g. they both
try to put BLORPH properties on the same symbol, you have an undetected
name clash.

Morals of the story:

If you want to be very conservative, use SHADOW on all symbols that
you use as unique, private identifiers, rather than simply making the
(usually correct) assumption that you won't inherit anything by the name.

There are two kinds of externals: the kind that are only accessed via
qualified names, which are safe from undetected name clashes, and the
kind that are accessed via use-package or include-package.  Every new
external of the latter kind must be accompanied by documentation when
released to the world.

As a third style (besides qualified names and wholesale use-package),
B and C could have IMPORTed just the symbols they actually wanted from A.
I don't think Common Lisp can legislate any of these three styles out
of existence, though; consider the LISP package, which it would be
silly to access in any but the "use" style.

The name clash detection I am promoting will detect all clashes in the
qualified name style (where it becomes ambiguous what a certain qualified
name refers to), clashes in the import style where you accidentally
referenced a name before you imported it and hence got an internal symbol,
and clashes in the use style caused by modifying a package after someone
has already inherited it.  It cannot detect clashes in the import style
where "the left hand doesn't know what the right hand is doing," i.e. two
parts of a program in a single package don't agree about whether a certain
name is to be private or imported.  In general it cannot detect name
clashes among the denizens of a single package!  It cannot detect clashes
in the use style where a new symbol, unanticipated by the inheriting
programs, is exported by the ancestor program -before- the inheriting
programs are loaded.  This one I think is inherent in the nature of
packages, or in the nature of contracts, and cannot be solved.

It would be very nice if the Common Lisp manual, at least in the second
edition, does not make the mistake we made in the Lisp machine manual and
omit all discussion of these issues, on the grounds that it would scare
the users or that it would make the manual too big.  It's important to
have a clear exposition of what the problems with packages are.  Maybe
I should just write (with help from others, surely) a freestanding paper
on the subject.

∂11-May-83  1955	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	package.mss.108 
Received: from MIT-MC by SU-AI with TCP/SMTP; 11 May 83  19:54:48 PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Wed 11-May-83 22:05:32-EDT
Date: Wednesday, 11 May 1983, 22:09-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: package.mss.108
To: Scott E. Fahlman <Fahlman%CMU-CS-C@SU-DSN>
Cc: Common-Lisp@su-ai
In-reply-to: The message of 11 May 83 15:22-EDT from Scott E. Fahlman <Fahlman at CMU-CS-C>

    Date: Wed, 11 May 1983  15:22 EDT
    From: Scott E. Fahlman <Fahlman@CMU-CS-C>

    I'm still a little unclear on how the
    error-cheking in declare-package would be handled when a package is loaded
    from multiple files (as the LISP package would be, for instance).

I guess the real issue is here is not so much multiple files as the
setting up of a package's externals by a bunch of separate EXPORT
"statements" rather than by a :EXPORT keyword to MAKE-PACKAGE (or
whatever we call it), which is what I had assumed without thinking about
it.  Thus you don't really know when a package is all loaded so that you
can error-check any declares that may have been done.

To you, this means that the error checking is useless.  To me, it means
declare-package is a kludge.  I'm not sure what we should do about this.
If all else fails you could just put in a function that is called explicitly
to do the error checking, and try to encourage people to put it at the end of
their program or wherever.

But note that in the example on p. 292 of the Laser edition of two programs
that depend on each other, it appears that what you are expected to do is
in this order:

1. Make your package
2. Do your export statements
3. Do your require statements, loading anything you need
4. Do your use statements, maybe adding what you just loaded to your package

The key thing here is that the export statements are all done -before- anyone
tries to look at the package from the outside, getting rid of the loading order
issues.  I guess it's up to you what style you want to promote.  Since my style
is to put all the package setup forms in separate files from the code, avoiding
any issue of loading order dependency entirely, it doesn't matter to me.

∂12-May-83  0321	DILL@CMU-CS-C 	package changes
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 12 May 83  03:21:34 PDT
Received: ID <DILL@CMU-CS-C>; 12 May 83 03:06:45 EDT
Date: 12 May 83 03:06:44 EDT
From: DILL@CMU-CS-C
Subject: package changes
To: common-lisp@SU-AI

I'll give one more push for major changes before I decide that I'm
obstructing progress.

It is not clear to me how an implementation can reasonably assure that
"no two symbols accessible to a package have the same name" with
"reference style" USE-PACKAGE.  Consider the following simple case of
accidental shadowing:

Pn is a package; Sm is a symbol.

  1. P3 exports S1.
  2. P1 uses P3
  3. P1 uses P2.
  4. P2 exports	S1' (a non-EQ symbol with the same pname as S1).

Read-Read consistency is violated, since the result of interning "S1"
before step 4 will not be EQ to interning it after step 4.

Similarly, Print-Read and Print-Print consistency are violated: try
printing S1 immediately before step 4, Read the result or print it again
after step 4.

This problem can occur no matter what the searching order of the various
packages is.

It can be very expensive to check for. With INCLUDE-PACKAGE, you have to
find all packages using P2, and check that there is either a symbol with
pname "S1" appearing in the use list ahead of P2 or that there is no
conflicting symbol appearing after P2 in the use list to be assured that
this has not happened.  With INCLUDE-PACKAGE, it is much more
complicated, since step 4 may cause S1' to be exported to many different
packages.

A much worse problem is that after detecting this situation, the user
will then have to deal with potentially a lot of questions demanding
that he resolve conflicts between many symbols in many packages, perhaps
for packages he knows nothing about.

----------------------------------------------------------------

I propose modifying Fahlman's proposal as below.

1. Flush INCLUDE-PACKAGE and UNINCLUDE-PACKAGE.

  The only reason I can see to have these functions is to build big
packages out of little ones.  Here is a more tasteful solution
that requires no additional functions:

a) Define a package to represent the whole system, and export from it
all the symbols that users will want to import from it.  

b) For the little packages composing the system, build them in the
natural way, except IMPORT all the symbols from the package of part a.
These packages will define the various functions, properties, and values
associated with these symbols.  Each of these "internal" packages can
hide its own internal symbols, and communicate with other internal
packages by exporting symbols and importing them in the ordinary way.
The user won't see any of these symbols unless he imports them
intentionally from one of the internal packages.  So, the user can
see it as a single large system by just importing the package defined
in part a.

With the addition of a structured package name space of some kind, the
names of the "internal" packages could also be isolated in order to
avoid conflicts with user-level package names.

Another way to group a bunch of packages would be to build another
package which imports symbols from the grouped package, and then
selectively exports them for importation by users.


2.  Flush DECLARE-PACKAGE.  Require that ALL symbols exported by a
package be exported before being imported (in any way) into other
packages (modulo debugging).


3.  Define (USE-PACKAGE P) to IMPORT the symbols in package P's export
list at the time that USE-PACKAGE is called ("copy" style).  Mistakes in
export lists will have to be remedied by tracking down the packages that
have imported them.  This may seem like a pain, but is probably 
inconsequential compared with the pain of tracking down wrong symbols
that were read by a package importing from a bogus export list.

The disadvantage of this definition that can be inferred from comments
on proposals is that it won't be possible for packages to export new
symbols from LISP and have them automatically appear in other packages.
This is not a serious problem (I believe).  No package author in his
right mind would use the new LISP features without taking steps to
ensure that they have been loaded -- and if he does this, he can equally
well do a (USE-PACKAGE LISP), after doing so.  The only potential
exception is the USER package; for this, packages exporting from LISP
can also explicitly IMPORT the symbols into USER.

The combined effect of these changes greatly simplifies the explanation
of how symbols are looked up, which is the closely related to the
conceptual simplicity of the system.  It is also safer.

----------------------------------------------------------------

I also propose the following function:

@defun[Fun {load-package} Args {@i[package-name]} @Optional {@i[file-name]}]

If the package @i[package-name] exists, do nothing.  Otherwise, load the
file named by @i[file-name].  If this argument is not supplied, load the
package from a file established by the system as the standard source for
that package, signalling an error if there is no file established for
@i[package-name].  If loading the file did not cause the package to
exist, signal an error.

USE-PACKAGE should call this function if the package it needs is not
defined.  Add an optional filename argument to USE-PACKAGE.

Note that a load can be forced by calling LOAD explicitly.

----------------------------------------------------------------

Here's how these changes would affect the example Fahlman gave in
his proposal [my comments in square brackets]:

[The init file would be simplified by not having to load the packages.
USE-PACKAGE and LOAD-PACKAGE would be sufficient.]

The file "alchemy.lisp":

@begin [lisp]
;;; Alchemy functions, written and maintained by Merlin, Inc.

;;; This file uses some functions from "Phogiston.lisp".
(declare-package "phlogiston"
  :export ("heat-flow" "cold-flow" "make-fire-bottle"))
[delete this previous s-expression]

;;; All of the following is in the ALCHEMY package.
(in-package "alchemy")

;;; Here is our external interface.
(export '(lead-to-gold gold-to-lead vms-to-unix pawn-to-king4
	  elixir-of-life))


;;; We use this a lot, so import it.  [insert: (load-package
phlogiston).  The phlogiston package will be able to use our symbols,
because we have already created the package and exported them.  It will
not try to load this package again because the package will already
exist.  Note that we have not used any symbols from phlogiston, yet, so
it's okay to load it now, if necessary.]

(import '(phlogiston:make-fire-bottle))

(defun lead-to-gold (x)
  "Takes a quantity of lead, returns gold."
  (when (> (phlogiston:heat-flow x) 3)	        ; Using a qualified symbol.
	(make-fire-bottle x))			; Using an imported symbol.
  (gild x))

;;; And so on ...
@end [lisp]

The file "phlogiston.lisp":

@begin [lisp]
;;; Phlogiston functions, written and maintained by Thermofluidics, Ltd.

;;; This file uses the ALCHEMY package from file "alchemy.lisp".
;;; The symbols listed are the only ones actually referenced.
(declare-package "alchemy"
  :export ("gold-to-lead" "elixir-of-life"))
[delete this]

;;; All of the following is in the PHLOGISTON package.
(in-package "phlogiston")

;;; Here is our external interface.
(export '(heat-flow cold-flow mix-fluids separate-fluids
	  burn make-fire-bottle))

;;; We use this a lot, so import it.
[same comments apply here as in the phlogiston.  If we load this one
first, it will not be loaded again, and it's symbols can be used by
phlogiston]
(use-package "alchemy")


(defun heat-flow (amount x y)
  "Make some amount of heat flow from x to y."
  (when feeling-weak
	(quaff (elixir-of-life)))		; No qualifier needed.
  (push-heat amount x y))

;;; And so on ...
@end [lisp]


[In Fahlman's example, he has an init file that loads both alchemy and
phlogiston -- a call to HEAT-FLOW will not work unless both are loaded.
In this proposal, the user can always (USE-PACKAGE "phlogiston") and call
HEAT-FLOW.  If it was pre-loaded in the init file, this will be faster,
but in either case it will happen exactly once.]

	-Dave
-------

∂12-May-83  1016	RPG  
Here is the package proposal we were all talking about:

This revised proposal incorporates some suggestions that I've received
from various sources, including a lot of feedback from Moon and Weinreb.
(These guys have actually USED a package system for real work, so they
have some strong opinions.)

The revision includes a fair amount of rewriting, intended to make all of
this more penetrable to potential users.  There are a number of little
changes (make-package takes keywords, etc.) and two major changes:

1. FOO:BAR will now reference symbol BAR in package FOO only if BAR is
an external symbol available in FOO.  If BAR is internal in FOO, you get
a correctable error asking if you really want to access an internal
symbol.  If that's really what you want, and you want to avoid the
error, you have to use the #: syntax, as in FOO#:BAR.  This is just a
saftety feature to keep users from accidentally getting hold of things
things they should not be messing with.

2. The earlier proposal's INHERIT-PACKAGE has been split into two
functions: USE-PACKAGE and INCLUDE-PACKAGE.  This gives the user control
over whether or not the external symbols inherited from another package
are to become external symbols of the current package.  Sometimes you
merely want to use another package, but not pass its interface on to
your descendants; sometimes you want to augment a package and pass on an
enriched interface.  So now you get both options.  There are some
corresponding changes to the rules of inheritance and to the definition
of EXPORT.

It would be nice if we could fix up any problems in this proposal fairly
quickly.  Specific suggestions are welcome.  Comments of the form "fix
this up" or "why don't you rewrite this completely " are not useful at
this point unless accompanied by a specific counter-proposal (or unless
you are saying that the proposal is so badly flawed that it would be
better to leave packages out of the white pages altogether).

Here we go again:

***************************************************************************

@chapter [Packages]

@section [Overview]

One problem with earlier 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.  Common Lisp addresses this problem through the @i[package
system], derived from an earlier package system developed for Lisp
Machine Lisp.  In addition to preventing name-space conflicts, the
package system makes the modular structure of large Lisp systems more
explicit.

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'' machinery of earlier Lisp systems.  At any given time one
package is current, and this package is used by the reader in
translating strings into symbols.  The current package is always the
value of the global variable @b[*package*].  It is possible to refer to
symbols in packages other than the current one through the use of
@b[package qualifiers] in the symbol reference.  For example @b[foo:bar]
refers to the symbol whose name is @b[bar] in the package whose name is
@b[foo].

A symbol may appear in many packages, but it will always have the same
print name wherever it appears.  On the other hand, a name may refer to
different symbols in different packages.  No two symbols in the same
package may have the same name.

The Common Lisp package system provides a mechanism for dividing
the symbols in a package into two classes.  @I[External symbols] are
part of the package's public interface to other packages.  These are
usually chosen with some care and are advertised to users of the
package.  @i[Internal symbols] are for internal use only, and these
symbols are normally hidden from other packages.  Most symbols are
created as internal symbols; they become external only if they appear
explicitly in some package's @b[export] command or after an @b[:export]
keyword in a package-creating function.

Packages may be built up in layers.  From the point of view of a
package's user, the package is a single collection of mappings from
strings into internal and external symbols.  However, some of these
mappings may be established by the package itself, while other mappings
are inherited from other packages.  (The mechanisms responsible for this
inheritance will be described below.)  In what follows, we will refer to
a symbol as being "accessible" in a package if it can be referred to in
that package without a qualifier, regardless of whether the mapping
occurs within that package or via inheirtance; we will refer to a symbol
as being "present" in a package if the mapping is in the package itself
and is not inherited from somewhere else.

@section [Consistency Rules]

In dealing with the package system, it is useful to keep in mind the
following consistency rules, which remain in force as long as the value
of @b[*package*] remains constant:

@begin [itemize]
@b[Read-Read consistency:] Reading the same print name always gets you
the same (EQ) symbol.

@b[Print-Read consistency:] An interned symbol always prints as a
sequence of characters which, when read back in, yields the same (EQ)
symbol.

@b[Print-Print consistency:] If two interned symbols are not EQ, then
their printed representations will not be the same sequence of
characters.
@end [itemize]

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:
changing the value of @b[*package*], forcing some action by continuing
from an error, or calling one of the following functions: @b[unintern],
@b[import], @b[export], @b[unexport], @b[shadow], @b[use-package],
@b[unuse-package], @b[include-package], @b[uninclude-package].

@section [Package Names]

Each package has a name (a string) and perhaps some nicknames.  These
are assigned when the package is created, though they can be changed
later.  A package's name should be something long and self-explanatory
like "editor"; there might be a nickname that is shorter and easier to
type, like "ed".  Package name strings retain whatever mixture of upper
and lower case characters the user supplies, but the translation from
names to packages is case-insensitive, so users may refer to a package
without worrying about case.

There is a single name space for packages.  The function
@b[find-package] translates a package-name or nickname into the
associated package.  The function @b[package-name] returns the name of a
package.  The function @b[package-nicknames] returns a list of all
nicknames for a package.  The function @b[rename-package] removes a
package's current name and nicknames and replaces them with new ones
specified by the user.  (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.)

@section [Translating Strings to Symbols]

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], and their package cell contains NIL.

Often it is desirable to refer to an external symbol in some package
other than the current one.  This is done through the use of a
@i[qualified name], consisting of a package name, then a colon, then 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 external symbol named ``@b[buffer]''
available in the package named ``@b[editor]'', regardless of whether
there is a symbol named ``@b[buffer]'' in the current package.  If there
is no package named ``@b[editor]'', or if no symbol named ``@b[buffer]''
is available in ``@b[editor]'' or if ``@b[buffer]'' is an internal
symbol in ``@b[editor]'', a correctable error is signalled to ask the
user what he really wants to do.

On rare occasions, a user may need to refer to an @b[internal] symbol of
some package other than the current one.  It is illegal to do this with
the colon qualifier, since accessing an internal symbol of some other
package is usually a mistake.  However, this operation is legal if you
use ``@b[#:]'' as the separator in place of the usual colon.  If
``@b[editor#:buffer]'' is seen, the effect is exactly the same as
reading ``@b[buffer]'' with @b[*package*] temporarily rebound to the
package whose name is ``@b[editor]''.  This special-purpose qualifier
should be used with caution.

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 provides a special reader syntax for them:
any symbol preceded by a colon but no package name (for example
``@b[:foo]'') is added to (or looked up in) the @b[keyword] package as
an @i[external] symbol.  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.  As a matter of style, keywords should always be accessed using
the leading-colon convention; you never want to import or inherit
keywords into any other package.

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 an external
symbol in the keyword package then it is printed with a preceding colon;
otherwise, if it is available (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, using
``@b[:]'' as the separator if the symbol is external and ``@b[#:]'' if
not.

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 has no recorded home package, but that in fact is
interned in some package.  The system does not check for this.

In summary, the following four cases are defined:

@Begin[describe]
@b[foo:bar] @\Look up "bar" among the external symbols available in the
package named "foo".

@b[foo#:bar] @\Look up "bar" among the external and internal symbols
available in the package named "foo".

@b[:bar] @\The symbol named "bar" is a self-evaluating keyword.

@b[#:bar] @\The symbol named "bar" is uninterned.
@End[describe]

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.

@section [Exporting and Importing Symbols]

Symbols from another package may be added to the current package in
three ways.

First, any individual symbol may be added to the current package by use
of the @b[import] function.  The form @b[(import 'editor:buffer)] takes
the external 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 is present in the current
package, @b[import] has no effect.  If a distinct symbol with the name
@b[buffer] is available in the current package (directly or by
inheritance), a correctable error is signalled.  The user will then be
offered a choice of whether or not the importation of this symbol is to
go forward.

The second mechanism is provided by the @b[use-package] function.  This
causes the current package to inherit all of the external symbols of
some other package.  These symbols become available as @i[internal]
symbols of the current package.  That is, they can be referred to
without a qualifier while this package is current, but they are not
passed along to any other package that uses or includes the current
package.

Often a user, working by default in the @b[user] package, will
load a number of packages into his Lisp to provide an augmented working
environment; then he will call @b[use-package] on each of these packages
so that he can easily access their external symbols.

The third mechanism is provided by the @b[include-package] function.
This is like @b[use-package], but the external symbols of the included
package become available as @i[external] symbols of the current package.
This mechanism makes it possible for one package to augment the
interface provided by another and pass the combined interface along as
its own external interface.  It also provides a convenient way to bundle
a number of packages together into a single one, combining all the
interfaces.  This function is normally only of use to people building
complicated software packages for others to use.

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, use a qualifier, or import that symbol into the current
package.

Most users will not need to concern themselves with the mechanisms by
which this inheritance of symbols takes place, but in some complex
situations the details of this operation may be important.  When a
package is created, it is given an initial list of packages which it
uses and an initial list of packages which it includes.  The
@b[use-package] and @b[include-package] take a list of packages and
consider them in order, left to right.  Each new package is added to the
front of the appropriate list as if by @b[pushnew].  The
@b[unuse-package] and @b[uninclude-package] functions remove packages
from these lists.  The lists are accessible via the @b[package-use-list]
and @b[package-include-list] functions, respectively.

When a name-string N is being looked up in package X, the system first
searches for N among the internal and external mappings present in X
itself.  Then it searches the members of the use-list in order, followed
by members of the include-list.  This search is depth-first: for each
package Y on X's use-list or include-list, the system first examines the
external symbols in Y, then the external symbols in any packages on
Y's include-list (but not its use-list), 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 include or use one another; each would see its own
symbols first, and then its partner's.

<< This order is arbitrary, but we need to specify some canonical order
of search. >>

Of course, there are many ways of implementing inheritance schemes that
are externally equivalent to the one described above but are
more efficient.  Common Lisp implementations are free to use such
schemes, as long as the search finds the same symbols in the same order
as in the scheme described here.

The @b[export] function takes a symbol that is available in the current
package and makes it an external symbol of the current package.  If the
symbol is already available as an external symbol in this package
(dirctly or via include-package), @b[export] has no effect.  If the
symbol is directly present in the package as an internal symbol, it is
simply changed to external status.  If it is available as an internal
symbol via @b[use-package], the symbol is first imported into the
current package, then exported.  (It is now present in the current
package whether or not this package continues to use the symbol's
original package.)  If the symbol is not available at all in the current
package, a correctable error is signalled which, upon continuing, asks
the user whether the symbol should be imported.

The @b[unexport] function is provided mainly as a way to undo erroneous
calls to @b[export].  It works only on symbols that are directly present
in the current package, switching them back to internal status.  It does
not provide a way for the user to get rid of an external symbol that is
inherited via @b[include-package]; if you try to do that, an error is
signalled.  If @b[unexport] is given a symbol that is already available
as an internal symbol in the current package, it does nothing; if it is
given a symbol that is not available in the packge at all, it signals an
error.

@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 use @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 uses 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 external symbols in the this package.  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[system]@\This package name is reserved to the implementation.
Normally this is used to contain names of implementation-dependent
system-interface functions.  This package uses @b[lisp] and has the
nickname @b[sys]. 
@end[description]

@Section[Package System Functions and Variables]

Some of the following have been described earlier, but are included here
for completeness.  Note that the following functions are meant to be
used at top-level in files, and should only be used at top-level if you
want to guarantee proper compilation across all Common Lisp
implemenations: @b[declare-package], @b[in-package], @b[import],
@b[export], @b[unexport], @b[shadow], @b[use-package],
@b[unuse-package], @b[include-package], @b[uninclude-package].

@Defvar[Var {*package*}]
The value of this variable must be 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] @key @i[nicknames] @i[use]
@i[include] @i[export]}]
Creates and returns a new package with the specified package name.  The
@i[:nicknames] argument must be a list of strings to be used as
alternative names for the function.  These names must not conflict with
any existing package names; if they do, a correctable error is
signalled.

The @i[:use] and @i[:include] arguments are lists of packages or
package names whose external symbols are to be inherited by the new
package.  If not supplied, @i[:use] defaults to a list of one package,
the @b[lisp] package; @i[:include] defaults to NIL.  The @i[:export]
argument is a list of strings that are to be interned in this new
package, then exported.

The new package is returned.
@Enddefun

@Defun[Fun {declare-package}, Args {@i[package-name] @key @i[nicknames] @i[use]
@i[include] @i[export]}]
The @b[declare-package] function normally creates a new package, exactly
as @b[make-package] does.  However, if a package of this name already
exists, @b[declare-package] does not signal an error.  Instead, it
augments the existing package.  The use and include lists of the
existing package are augmented with any packages specified here (if
these packages are not already present), and the strings on the
@i[:export] list are interned and exported.  The @i[:nicknames] are merged;
an error is signalled if any of these nicknames conflicts with some
existing package other than the one being augmented.

The new or augmented package is returned.
@enddefun

@Defun[Fun {in-package}, Args {@i[package-name] @key @i[nicknames] @i[use]
@i[include] @i[export]}]
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 to @b[declare-package], except that after
the new package is created (or an existing package found), @b[*package*] is
set 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.
@enddefun

@Defun[Fun {find-package}, Args {@i[name]}]
The @i[name] must be a string that is the name or nickname for a
package.  Returns the corresponding package, or NIL if no such package
exists.  This match ignores case (as in @b[string-equal]).
@Enddefun

@Defun[Fun {package-name}, Args {@i[package]}]
The argument must be a package.  This function returns the string that
names that package.
@Enddefun

@Defun[Fun {package-nicknames}, Args {@i[package]}]
The argument must be a package.  This function returns the list of
nickname strings for that package.
@Enddefun

@Defun[Fun {package-use-list}, Args {@i[package]}]
Returns the list of other packages used by the argument package.
@Enddefun

@Defun[Fun {package-include-list}, Args {@i[package]}]
Returns the list of other packages included in the argument package.
@Enddefun

@Defun[Fun {list-all-packages}, Args {}]
This function returns a list of all packages that currently exist in the
Lisp system.
@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.
@Incompatibility{Conceptually, @b[intern] translates a
string to a symbol.  In Maclisp and several other Lisps, @b[intern] can
take either a string or a symbol as its argument; in the latter case,
the symbol's print name is extracted and used as the string.  However,
this leads to some confusing issues about what to do if
@b[intern] finds a symbol that is not @b[eq] to the argument symbol.  To
avoid such confusion, we require the argument to be a string.}
@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 {find-external-symbol}, Args {@i[string] @optional @i[package]}]
This is identical to @b[find-symbol], but it does not look for internal
symbols even in @i[package] itself.  This is the type of search done by
the reader for symbols qualified with a package name and a colon.  The
return values are the same as for @b[find-symbol], with the third return
value always being T (external symbol) if a symbol is found.
@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 available as external symbols in the current
package.  (See the previous section for details.)
In this and related functions, an argument of NIL is taken to be a list
of no arguments.  Returns T.

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
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.  These symbols become internal symbols in the current
package.  (See the previous section for details.)  Returns T.
@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.  (See the previous section for details.)  Returns T.
@Enddefun

@Defun[Fun {shadow}, Args {@i[symbols]}]
The argument should be a list of symbols, or possibly a single symbol.
The print-name of each symbol is extracted, and the current package is
searched for a symbol of that name.  If such a symbol is present in this
package (directly, not by inheritance) then nothing is done.  Otherwise,
a new symbol is created with this print name, and it 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.
Returns T.
@Enddefun

@Defun[Fun {use-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
the package's use-list if they are not there already.  All external
symbols in the argument packages become available in the current package
as internal symbols.  (See the previous section for details.)  Returns T.
@enddefun

@Defun[Fun {unuse-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 use-list.  Returns T.
@enddefun

@Defun[Fun {include-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
the package's include-list if they are not there already.  All external
symbols in the argument packages become available in the current package
as external symbols.  (See the previous section for details.)  Returns T.
@enddefun

@Defun[Fun {uninclude-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 include-list.  Returns T.
@enddefun

@Defun[Fun {find-all-symbols}, Args {@i[symbol]}]
Searches every package in the Lisp system for symbols whose print-name is the
same as the print-name of the argument symbol and returns a list of
these symbols.
@enddefun

@Defmac[Fun {do-symbols}, Args {(@i[var] @Mopt<@i[package]> @Mopt<@i[result-form]>) @Mstar<@i[declaration]> @mstar<@i[tag] @mor @i[statement]>}]

@b[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 @b[progn]) is
evaluated, and the result is the value of the @b[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 NIL.  @b[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 @b[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 @b[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

@section [An Example]

A user's "lisp init" file (in implementations that provide for such a
thing, might look like the following:

@begin [Lisp]
;;; Lisp init file for I. Newton.

;;; Set up the USER package the way I like it.

;;; Calculus is used a lot.  Get easy access to all its symbols.
(load "calculus.lisp")
(use-package calculus)

;;; I just want a few thing from here, and other things conflict.
;;; Import just what I need into the USER package.
(load "relativity.lisp")
(import '(relativity:speed-of-light
	  relativity:ignore-small-errors))

;;; Things in here I will use with qualifiers if I ever need them.
(load "phlogiston.lsp")
(load "alchemy.lsp")
@end [Lisp]		

Now, suppose that the @b[phlogiston] and @b[alchemy] packages are in
separate files.  Phlogiston wants to use the alchemy package, and
alchemy wants to use several external symbols from phlogiston.  Note the
use of the @b[declare-package] form, which makes it possible to load
these files in either order.  External symbols from the other file must
appear in the @b[:export] list of the declare-package statement, but
only those external symbols that are actually used in the current file
have to be declared.  These declarations can usually be avoided if the
user is willing to require some specific order of file-loading, but this
leads to maintenance headaches.

The file "alchemy.lisp":

@begin [lisp]
;;; Alchemy functions, written and maintained by Merlin, Inc.

;;; This file uses some functions from "Phogiston.lisp".
(declare-package "phlogiston"
  :export ("heat-flow" "cold-flow" "make-fire-bottle"))

;;; All of the following is in the ALCHEMY package.
(in-package "alchemy")

;;; Here is our external interface.
(export '(lead-to-gold gold-to-lead vms-to-unix pawn-to-king4
	  elixir-of-life))


;;; We use this a lot, so import it.
(import '(phlogiston:make-fire-bottle))

(defun lead-to-gold (x)
  "Takes a quantity of lead, returns gold."
  (when (> (phlogiston:heat-flow x) 3)	        ; Using a qualified symbol.
	(make-fire-bottle x))			; Using an imported symbol.
  (gild x))

;;; And so on ...
@end [lisp]

The file "phlogiston.lisp":

@begin [lisp]
;;; Phlogiston functions, written and maintained by Thermofluidics, Ltd.

;;; This file uses the ALCHEMY package from file "alchemy.lisp".
;;; The symbols listed are the only ones actually referenced.
(declare-package "alchemy"
  :export ("gold-to-lead" "elixir-of-life"))

;;; All of the following is in the PHLOGISTON package.
(in-package "phlogiston")

;;; Here is our external interface.
(export '(heat-flow cold-flow mix-fluids separate-fluids
	  burn make-fire-bottle))

;;; We use this a lot, so import it.
(use-package "alchemy")

(defun heat-flow (amount x y)
  "Make some amount of heat flow from x to y."
  (when feeling-weak
	(quaff (elixir-of-life)))		; No qualifier needed.
  (push-heat amount x y))

;;; And so on ...
@end [lisp]

∂12-May-83  1200	@MIT-MC:MOON@SCRC-TENEX 	package changes
Received: from MIT-MC by SU-AI with TCP/SMTP; 12 May 83  12:00:01 PDT
Date: Thursday, 12 May 1983  14:53-EDT
From: MOON at SCRC-TENEX
To:   DILL at CMU-CS-C
Cc:   common-lisp at SU-AI
Subject: package changes
In-reply-to: The message of 12 May 83 03:06:44 EDT from DILL@CMU-CS-C

The first part of your message is quite reasonable, except for the
claim that it is very expensive to check for.  When P2 exports S1',
you simply find every package that uses or includes P2 and call
(FIND-SYMBOL (SYMBOL-NAME S1') Pn) in that package.  This is just INTERN
that doesn't create new symbols.  If this comes back with a symbol that
isn't S1', you have a name conflict, unless the symbol it comes back
with is on the shadow list of Pn.  Of course, you don't ask the user
questions one at a time; you find all the name conflicts first, sort
them according to their various causes, then give the user one explanation
of what happened.  Continuing from the error would presumably be allowed
with several options including both simple ones like "do it anyway"
and "give up on exporting", and complex options like "ask me a separate
question for each package with a conflict".

I haven't studied the rest of your message yet.  Will send more mail
tomorrow or later today.

∂12-May-83  1347	@MIT-MC:dlw%SCRC-TENEX%MIT-MC@SU-DSN 	More about packages, from DLW and BSG
Received: from MIT-MC by SU-AI with TCP/SMTP; 12 May 83  13:46:55 PDT
Received: from SCRC-BORZOI by SCRC-TENEX with CHAOS; Thu 12-May-83 16:44:47-EDT
Date: Thursday, 12 May 1983, 16:48-EDT
From: Daniel L. Weinreb <dlw%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: More about packages, from DLW and BSG
To: common-lisp@su-ai

Actual problems with the proposal:

In your example, have you considered what would happen if you were to
run the Lisp compiler on Newton's init file?  As far as I can tell, the
compiler would signal an error upon seeing the reference to the symbol
"relativity:speed-of-light", because that package would not exist, at
compile time.  You need an eval-when around the load form.

As the proposal is written, use-package will consider its arguments from
left-to-right, and pushnew each one.  This will effectively reverse the
order of the list, which seems confusing.

If you import an uninterned symbol, or otherwise cause a symbol to exist
that is present in some package but has no home package, the rules for
how to print the symbol (assume that package is the current package)
both say that you should print it without any qualifier and that you
should print it with a leading #:.  Presumably the rule for how to print
symbols should be amended to say that it only applies to interned
symbols (those with a home package).  The consistency rules are not
violated, since they are careful to only talk about interned symbols.

If an interned symbol is removed from its home package then the
consistency rules will be violated (the symbol might be printed as
foo:bar or foo#:bar even though it's not in that package).  I don't know
what to do about this.

Places where the proposal is unclear:

There is a fundamental question about the semantics of packages whose
answer I was not sure of until I had read the proposal most carefully,
namely, what does it mean for a symbol to be "external"?  The real
answer is that a given symbol can be interned in many packages, and in
each of these packages it can either be internal or external.  You can
only ask whether a symbol is external in a certain package, not whether
it is external.  Let me assure you that this point is not at all obvious
unless you read the proposal extremely carefully, and it caused us some
confusion at various points.  The first paragraph about external versus
internal gives you the impression that it would be meaningful to have a
function called externalp that just takes a symbol and returns a boolean
value, by its use of language.

An explicit definition of the algorithm for looking up an unqualified
name was given, but no corresponding definition was given of the
algorithm for looking up a name qualified with a colon.  Suppose we are
looking up the string "FOO:BAR", and FOO has an internal symbol named
BAR, and FOO inherits from FIE, and FIE has an external symbol named
BAR.  Does it return the external BAR symbol in FIE, or does it signal
an error because the symbol that it finds isn't external?  It is not
until the function find-external-symbol is defined that we are actually
told the answer to this question (the former).  I had initially assumed
that "FOO:BAR" follows the standard lookup algorithm, and then signals
an error if it finds that the symbol it has found is not an "external
symbol".  (Of course, there's no such thing as being an external symbol,
but I still wasn't sure of that.)  This point also needs more
clarification earlier in the description, possibly by putting in a
separate algorithm just to make things completely clear.  (In
particular, the wording "refers to the external symbol named @b[buffer]
in the package named @b[editor]" is what threw me off most severely.  I
asked myself "what if @b[buffer] is an internal symbol?" and it wasn't
clear what the answer was.  The phrasing suffers from "present King of
France" syndrome.)

I am also unhappy with the sentence in the description of use-package
that says "These symbols become available as @i[internal] symbols".
This is non-strict phrasing, since the term "available" is only defined
in such a way that you can ask whether a symbol is available or not; you
can't ask whether it's available "as" an internal symbol.  The sentence
as phrased deserves to be followed by "so to speak"; it isn't literally
meaningful, and gives me the impression that they "become internal
symbols of the package", which they don't.

The declare-package/error-checking issue:

The statement that "no two symbols of the same name may be accessible
from the same package" is trivially true, from the definition of
"accessible"; after all, find-symbol can only return one symbol.  What
Moon is really saying here, I presume, is that no symbol should shadow
any other symbol unless some explicit mechanism is used that says "hey,
I'm really trying to shadow something".  Moon said elsewhere that "the
order of searching ancestors cannot be allowed to make a difference if
we are to remain sane", which implies the same thing, more or less.  I
presume he's saying that every operation that might set up an implicit
shadowing must be error-checked to make sure that it doesn't do so.

This clearly means that the concept of "shadowed" must be added to the
proposal and defined clearly.  I would presume that shadowing, like
external/internal, is a property of an "interning"; that is, a symbol
can be interned in several packages, and in each package it might or
might not be "shadowing".  Someone must propose what functions exist to
cause an interning to be shadowing, go through some examples of how
you'd use shadowing, and figure out the algorithm for checking for name
conflicts whenever use-package, inherit-package, export, or other
functions are called given that some internings are shadowing and some
are not.  I think Dill's example (the P1, S1 one) shows that the
algorithm is not immediately obvious, particularly when shadowing is
involved.  Until then it's hard to judge whether it all works or not.
By the way, I also noticed the problem of "when do you know that you're
finished loading?".

My analysis of Moon's BLORPH example is that the situation that the
various participants have asked for is that there should be one symbol,
BLORPH, external in the A package, and packages B and C should be using
this symbol.  If BLORPH is created and exported in A before B and C are
loaded, this happens, and otherwise an error gets signalled by Moon's
proposed error-checking stuff.  The existing Zetalisp package system
deals with this by "locking" any package that is used by any other
package; i.e. it never lets you add a new symbol into any ancestor
package.  In either case, Moon's scenario is not really a "screw case",
since there is only one situation that can occur without an error being
signalled.  The official screw cases are where two different things can
happen without any error being signalled.  Moon's example shows how the
current proposal can create this kind of screw.  SEF's comment about
"the old LispM package system, which sometimes does seem like it's out
to screw people in all possible ways" is interesting in this light.

In Dill's new proposal, the same problem is solved by using "copy
semantics".  If you export a symbol in P2 after P1 asked to use P2, then
P1 just doesn't get the new symbol.  So ancestors have to get set up
before they're used.  This is just like the Zetalisp philosophy, except
that you don't get an error message if you do things out of order
(because in the new definition, it's not an error).  The order dependence
is still there.

In the Zetalisp package system, we did what we considered the simple and
safe thing.  We stated at the outset that every package must be declared
before it is used, and the declaration sets up all relevant information
about the package, saying what it inherits from, exports, shadows, etc.
The package declaration must be evaluated (i.e. loaded) before anything
else can even THINK about using the package.

Enough rambling: the major decision to be made at this juncture is
whether we want to try to let you use a package before its owner has
declared it, or whether we want to make sure that the owner declares a
package before anybody tries to use it.  The present proposal attempts
to do the former.  One problem has been pointed out already (by Moon):
declaring a package that is constructed by inclusion of other packages
requires the the declarer know about this structure.  I.e. if I want to
use package foo, and package foo inherits from package bar, I have to
know that.  This is clearly unmodular.  Here's something even worse
about declaring a package that includes some other package.  Consider
(declare-package "foo"
        :include "bar
        :export '("a" "b" "c"))
Are "a", "b", and "c" interned in "foo" or "bar"?  The syntax of
declare-package has to be extended to allow the caller to say so,
explicitly.  Are you grossed out yet?

I think the current favorite counterproposal around here is to say that
for every package, there is a file that sets up that package, specifying
what it uses and includes and exports, and programs that want to access
those packages would have something like Dill's load-package function to
read in that file if it doesn't exist already.  For small packages, the
entire program that makes up that package could be in the file; for
large packages, you have to get the rest of the files loaded yourself,
but this one file has all the relevant forms that set up the package
structure.

∂12-May-83  1611	FAHLMAN@CMU-CS-C 	More about packages, from DLW and BSG
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 12 May 83  16:07:07 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 12 May 83 19:07:13 EDT
Date: Thu, 12 May 1983  19:07 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   Daniel L. Weinreb <dlw%SCRC-TENEX%MIT-MC@SU-DSN>
Cc:   common-lisp@su-ai
Subject: More about packages, from DLW and BSG
In-reply-to: Msg of 12 May 1983 16:48-EDT from Daniel L. Weinreb <dlw%SCRC-TENEX%MIT-MC at SU-DSN>


Gasp!.....
          .
           .
            Thud!

∂12-May-83  1611	FAHLMAN@CMU-CS-C 	More about packages, from DLW and BSG
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 12 May 83  16:10:13 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 12 May 83 19:09:59 EDT
Date: Thu, 12 May 1983  19:09 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   Daniel L. Weinreb <dlw%SCRC-TENEX%MIT-MC@SU-DSN>
Cc:   common-lisp@su-ai
Subject: More about packages, from DLW and BSG
In-reply-to: Msg of 12 May 1983 16:48-EDT from Daniel L. Weinreb <dlw%SCRC-TENEX%MIT-MC at SU-DSN>


Or in other words... Thanks for your extensive feedback, and I'll try to
reflect all of those points in the next version of the proposal, which I
didn't manage to finish last night, but will be finishing sometime in
the next couple of days.  Keep those cards and letters coming.

-- Scott

∂14-May-83  2208	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	New Error Proposal: suggestions to be incorporated 
Received: from MIT-MC by SU-AI with TCP/SMTP; 14 May 83  22:07:51 PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Sun 15-May-83 00:18:40-EDT
Date: Sunday, 15 May 1983, 01:09-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: New Error Proposal: suggestions to be incorporated
To: Kent M. Pitman <KMP%MIT-MC@SU-DSN>
Cc: Common-Lisp@SU-AI
In-reply-to: The message of 11 May 83 05:59-EDT from Kent M. Pitman <KMP at MIT-MC>

    Date: 11 May 1983 05:59 EDT
    From: Kent M. Pitman <KMP @ MIT-MC>

    * Based on heavy experience with the old and new error system, I feel 
      strongly that one consistent irritation of the old system was that 
      it didn't clearly distinguish between the cause and correction of
      an error and that CERROR as currently proposed will perpetuate that
      problem. eg, when you ran with error messages turned on but errors 
      ignored, typeout like "continuing will do such-and-so" was at least
      irritating and frequently wrong. I put out for discussion the idea
      that the CERROR should be modified as follows...

      CERROR format-string-1 format-string-2 &rest args
      Signal an error, with the message constructed by applying FORMAT to
      format-string-1 and the arguments. If the debugger is entered, it
      may choose to offer a message composed by calling FORMAT on 
      format-string-2 and the arguments, describing what will happen if
      the error is proceeded.  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"
		      "~1G:~[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."
		      "Replace ~S and try again." X)
	      (FORMAT T "~&New word: ")
	      (SETQ X (READ)))

You have an excellent point here.  Consider this added to my error proposal.

Let's amend the first example to avoid scaring people with hairy formatology:

	    (UNLESS (= (LIST-LENGTH FORM) 3)
	      (CERROR "Wrong number of arguments in ~S"
		      (IF (< (LIST-LENGTH FORM) 3)
			  "Assume 0 for missing args."
			  "Ignore extra args.")
		      FORM)
	      (SETQ FORM (APPEND FORM '(0 0))))

Let's also include some kind of style suggestion on the second format string
so that if a program automatically continues from the error it might be able
to incorporate the string into an explanation of what it did.  This may be
overambitious since it won't work with any CERROR that asks for new input
when continued, but it could still be worthwhile for a lot of things, and
also may dovetail nicely into the condition system when we put one in some
time in the future.

    * It occurs to me that the naming of CTYPECASE and ETYPECASE might 
      be solved in a completely different way. Rather than adding new
      special forms, one could make several kinds of otherwise clauses.
      The argument against this might be that it means more special cases of
      symbols in the case-list position, making that position more visually
      ambiguous. The counter-argument (held by some (eg, me)) is that people
      should use parens around everything but the otherwise options anyway.
The Common Lisp manual is written to encourage this style.

      Examples:
	    (SETQ X 1/3)
	    (TYPECASE X
	      ((INTEGER) (- X))
	      ((SYMBOL)  (INVERSE X))
	      (:OTHERWISE-ERROR))
	    Error: The value of X, 1/3, was neither an integer nor a symbol.
	    (TYPECASE X
	      ((INTEGER) (- X))
	      ((SYMBOL)  (INVERSE X))
	      (:OTHERWISE-CERROR))

Since OTHERWISE is not a keyword, it would be too confusing for these to
be keywords.  They should be written without a colon.  These are simply
magic words that are part of the syntax of these special forms.

I thought having to insert only a single letter to get this error checking
might encourage people to do it more, since it would seem painless.  However
there is something to be said from a documentation point of view for your
proposal and I'll go along with it if there is general sentiment in favor of it.
I'm still mildly in favor of my original proposal for this, however.

One thing I should point out is that the "ECASE" proposal can be generalized
to COND if we decide we want that, but the "OTHERWISE-ERROR" proposal cannot be,
except in a grotesque way.

    * I liked your stating explicitly not to put "Error: " at the head of
      error messages. I would further like it specified that multi line error
      messages should not be padded (with spaces, ";", etc.) because tools such
      as the debugger (or whatever) will take care of padding lines with the 
      appropriate text.
      (ERROR (FORMAT NIL "FOO~%BAR"))
      should print out as:
	>>Error: FOO
		 BAR
      not as
	>>Error: FOO
	BAR
      Ditto for the continuation string. The LispM currently has the bug
      that proceed options come out as:
	s-A:     This is a proceed option
	extending over multiple lines.
	s-B:     This is another.
      when
	s-A:     This is a proceed option
		 extending over multiple lines.
	s-B:     This is another.
      would be better. Note that (ERROR (FORMAT NIL "FOO~% BAR"))
      would want to come out like
	>>Error: FOO
		  BAR
      The reason for guaranteeing something like this is that users will frequently
      see the error coming out only in the debugger and may feel an urge to write
      (ERROR (FORMAT "FOO~%~16TBAR")) or some such so it'll look pretty. If another
      program gets ahold of such a format string and tries to use it elsewhere,
      though, it'll look like garbage.  Better the user should just be told flat out
      that "any necessary padding for continuation lines will be taken care of". eg,
      I have seen Maclisp code where users did:
	(ERROR (FORMAT NIL "FOO~%;BAR")) 
      since they  knew that the first line would have a leading ";" and the rest
      would not. If the error message style is with leading, that should be supplied
      on line 1 and on continuation lines by the system.

      This also takes care of people who try to assume that line 1 will be shorter
      than subsequent lines because they know a 20 character leader will occur on
      that line and tends to produced multi-line messages where lines have balanced
      lengths, rather than multi-line messages where the first line is considerably
      shoerter than subsequent lines.

I'd like to see all these stylistic suggestions go into the Common Lisp manual.

    * I don't see any reason why
      (ABORT-PROGRAM)
      can't be a synonym for what the LispM calls (SIGNAL 'SYS:ABORT). This
      is a pretty useful thing to put on interrupt characters. All you have to
      do is add an additional special form
      (CATCH-PROGRAM-ABORTS ...) or some such which does
      (CONDITION-CASE ()
	 (PROGN ...)
       (SYS:ABORT ...))
      on the LispM. In a Lisp where conditions didn't exist, people could do
      the equivalent with CATCH/THROW.

      In fact, I don't know why just ABORT and CATCH-ABORT aren't adequate names.
      I find the word "program" ambiguous on a mainframe between meaning the 
      toplevel form I invoked in my read-eval-print loop and the exec command I
      used to invoke the Lisp. (ie, the c-Abort vs c-m-Abort distinction on the
      LispM). 

      In any case, I think these are valid kinds of issues for programmers to
      want to do in a machine independent fashion and should be included.

The c-Abort vs c-m-Abort distinction is a real issue.
CATCH-ABORT should properly include some sort of documentation of what it is
that you are aborting from or to, as ERROR-RESTART in the Lisp machine does.

I think it's going to be too hard to specify the semantics of aborting precisely
enough to make it implementation-independent until we put condition-handling
capabilities into Common Lisp.  So let's just leave it out for now, so we don't
define ourselves into a corner, even though we know very well that it is needed.

    * In things like CHECK-ARG, etc. I see no reason their forms shoudln't be
      evaluable multiple times. It's essential that it be clearly documented,
      but that's easy to do. In the rare case that multiple evaluation would be
      a screw, a simple LET will probably fix the user's problem. If we later
      find out it's easy to guarantee single evaluation, it's easier to relax
      things and tell him so than it is to go the other route if people have 
      written code depending on single evaluation.

Okay, I believe this.


∂14-May-83  2228	FAHLMAN@CMU-CS-C 	New Error Proposal: suggestions to be incorporated  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 14 May 83  22:28:26 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 15 May 83 01:28:02 EDT
Date: Sun, 15 May 1983  01:28 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Cc:   Common-Lisp@SU-AI, Kent M. Pitman <KMP%MIT-MC@SU-DSN>
Subject: New Error Proposal: suggestions to be incorporated
In-reply-to: Msg of 15 May 1983 01:09-EDT from David A. Moon <Moon%SCRC-TENEX%MIT-MC at SU-DSN>


Dave,

I see that you've bought some of KMP's suggestions.  They look OK to me
too.  Several people in our group have independently suggested somehow
getting a second format string into CERROR to say what happens if you
proceed.  I slightly prefer the ECASE format to the OTHERWISE-ERROR
proposal, but I'm not adamant.

Will you edit your error proposal to incorporate the new stuff?  I'd
like to have one message or file containing all the current stuff,
rather than having to hunt around among N messages.

Thanks,
Scott

∂14-May-83  2302	@USC-ECL,@MIT-ML:Moon%SCRC-TENEX%MIT-ML@SU-DSN 	package changes  
Received: from USC-ECL by SU-AI with TCP/SMTP; 14 May 83  23:02:25 PDT
Received: from MIT-ML by USC-ECL; Sat 14 May 83 22:59:14-PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Sun 15-May-83 01:05:34-EDT
Date: Sunday, 15 May 1983, 01:56-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-ML@SU-DSN>
Subject: package changes
To: DILL%CMU-CS-C@SU-DSN
Cc: common-lisp@SU-AI
In-reply-to: The message of 12 May 83 03:06-EDT from DILL at CMU-CS-C

    Date: 12 May 83 03:06:44 EDT
    From: DILL@CMU-CS-C

    ....
    I propose modifying Fahlman's proposal as below.

    1. Flush INCLUDE-PACKAGE and UNINCLUDE-PACKAGE.

      The only reason I can see to have these functions is to build big
    packages out of little ones.  Here is a more tasteful solution
    that requires no additional functions:

    a) Define a package to represent the whole system, and export from it
    all the symbols that users will want to import from it.  

    b) For the little packages composing the system, build them in the
    natural way, except IMPORT all the symbols from the package of part a.

    Another way to group a bunch of packages would be to build another
    package which imports symbols from the grouped package, and then
    selectively exports them for importation by users.

Or just have the little packages USE-PACKAGE the big package (this is how it
works in the Lisp machine now, except that there is a spurious requirement of
hierarchy rather than heterarchy).  Or have the big package not export any
symbols on its own, but have each of the little packages include an EXPORT
statement with the big package as its second argument, taking their own
symbols and exporting them as externals of the big package rather than as
externals of the particular little package.  If they want they could export
symbols from both; it ought to work for a symbol to be an external of more
than one package.

In this case of course one needs to make a conscious decision what the
home package of these symbols should be, which is really a conscious
decision of what prefix one wants to see when the symbol is printed with
a qualified name.  You could want to see either the name of the big
conglomerate package, or the name of the specific internal package that
actually defines the symbol.  An advantage of flushing INCLUDE-PACKAGE
is that it makes the need for this decision more apparent.

The gain in simplification of the implementation from flushing INCLUDE-PACKAGE
is extremely small; I would guess between 15 and 20 lines of code.  But I
am in favor of this anyway, purely for documentation reasons.

    With the addition of a structured package name space of some kind, the
    names of the "internal" packages could also be isolated in order to
    avoid conflicts with user-level package names.

We seem to have decided to avoid things like non-global package naming for
now.  It can easily be added later, but there are more user-interface issues
than you would possibly believe beforehand, as we have found out through sad
experience with the Lisp machine package system.


    2.  Flush DECLARE-PACKAGE.  Require that ALL symbols exported by a
    package be exported before being imported (in any way) into other
    packages (modulo debugging).

I never liked declare-package, and it does seem that the more we look at it
the more problems occur.  Unless Scott's next proposal manages to cleverly fix
all the problems with declare-package, I am in favor of flushing it.  I've
pointed out before how in the simple cases of smallish programs, even including
mutually-referencing packages, one can have the package-setup forms and the
program-defining forms all in a single file while still conforming to the rule
that a package must be set up before it is used.  It only requires that LOAD
be callable from inside LOAD (pace pdp10 Maclisp).

Note: in the above I am using the ugly expression "set up" because in the Lisp
machine this is called "declaring a package", while in the recent Common Lisp
package discussion "declaring a package" has come to mean something else.  I
specifically mean "set up" to be what the author of the package does, with
MAKE-PACKAGE or IN-PACKAGE or whatever it ends up being called.  Don't call
it SETUP-PACKAGE.

    3.  Define (USE-PACKAGE P) to IMPORT the symbols in package P's export
    list at the time that USE-PACKAGE is called ("copy" style).  

I pointed out in November why copy semantics is inherently unworkable
for packages.  But you may not have seen those comments.

								 Mistakes in
    export lists will have to be remedied by tracking down the packages that
    have imported them.  This may seem like a pain, 

Indeed it may.  I think it is important for the package system to provide
aid in tracking down such things.  This is why reference rather than copy
semantics is preferred.  In fact, I'll add to my previous proposal,
that to be workable SHADOW must record what it did in a structure slot in
the package, that IMPORT must do the same thing.

    I also propose the following function:

    @defun[Fun {load-package} Args {@i[package-name]} @Optional {@i[file-name]}]

    If the package @i[package-name] exists, do nothing.  Otherwise, load the
    file named by @i[file-name].  If this argument is not supplied, load the
    package from a file established by the system as the standard source for
    that package, signalling an error if there is no file established for
    @i[package-name].  If loading the file did not cause the package to
    exist, signal an error.

    USE-PACKAGE should call this function if the package it needs is not
    defined.  Add an optional filename argument to USE-PACKAGE.

    Note that a load can be forced by calling LOAD explicitly.

Essentially what you are proposing here is to conflate the ideas of
"package" and "module" (laser manual page 291).  The Lisp machine originally
worked this way, but we abandoned it some years ago.  I'm not sure that I
can come up with an explanation of why this is not a good idea that would
convince anyone not familiar with that history.  Certainly in the simplest
case modules (the units of separate maintenance, compilation, and loading)
and packages (the units of separate symbol naming) are related one-to-one.  But it
is quite possible for a large module to involve more than one package, and
it is also quite possible for a single package to contain more than one
module.  So it doesn't really make sense to replace these two distinct ideas
with one single idea.

Some Lisp machine background that may not be familiar to everyone on the
list:  We use the admittedly-overworked word "system" for what the laser
manual calls a "module".  This is because a system is a compound structure
whose elements are called modules.  A system is the unit of compilation,
loading, and especially maintenance; thus a system is "a program."  A
module is the unit of dependency; thus one module may require loading
a second module into the compiler, to define macros or whatever, before
it may be compiled.  Of course under both of these is a third unit, the
file, which is the atomic unit of compilation and loading but is otherwise
not intrinsically interesting.  Systems can also be recursively constructed
out of other systems.

We have a general registry of "systems" and the files that must be loaded
in order to load the system.  Thus one would not normally supply a file
name when demanding the loading of a system, but would simply let the
general registry figure it out.  There is a directory with one file for
each system, the name of the file being derived in an obvious way from
the name of the system.  This file contains a Lisp form that specifies
where the files of the system reside (sometimes using logical pathnames);
this includes the file that contains the definition of the internal
structure of the system, i.e. its inter-module dependencies and
its package "set up".  Other implementations would choose to do this
in somewhat different ways.  But Common Lisp can quite reasonably
require every implementation to provide some primitive "library"
mechanism of this type, so that one can call some function with a name
like REQUIRE and the name of "a program", and be assured that that
program is present in the Lisp environment.

+++++++

Summary:

Flush include-package.
Keep use-package the way it is.
Flush declare-package.
Keep the provide/require stuff from the laser manual.
Write documentation on how to use all this stuff, for both
 simple cases and complex cases.

∂14-May-83  2308	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	New Error Proposal: suggestions to be incorporated 
Received: from MIT-MC by SU-AI with TCP/SMTP; 14 May 83  23:08:10 PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Sun 15-May-83 01:15:32-EDT
Date: Sunday, 15 May 1983, 02:06-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: New Error Proposal: suggestions to be incorporated
To: Scott E. Fahlman <Fahlman%CMU-CS-C@SU-DSN>
Cc: Common-Lisp@SU-AI
In-reply-to: The message of 15 May 83 01:28-EDT from Scott E. Fahlman <Fahlman at CMU-CS-C>

I will mail out an updated version of my error proposal tomorrow, or maybe Monday.

∂15-May-83  1137	KMP@MIT-MC 	Keywords, :Keywords, &More-Keywords   
Received: from MIT-MC by SU-AI with TCP/SMTP; 15 May 83  11:37:46 PDT
Date: 15 May 1983 14:40 EDT
From: Kent M. Pitman <KMP @ MIT-MC>
Subject: Keywords, :Keywords, &More-Keywords
To: Moon @ SCRC-TENEX
cc: Common-Lisp @ SU-AI, JWalker @ SCRC-TENEX

I don't have a strong opinion on the ECASE vs keyworded-CASE. I just
wanted to make sure the alternatives were looked on. The tension is
basically one of an extended function name space vs a keyworded syntax;
Common Lisp has tended to prefer keywords, so I figured it was best to
at least review the keyword alternative.

The issue you bring up about OTHERWISE is an interesting one. I wonder
if OTHERWISE -should- be (or "should have been") a keyword. I have
always disliked its being a global symbol just so it could be used in
this peculiar case. Also, users may believe it is keyword-like in nature
and be very confused by the fact that :OTHERWISE doesn't work! Already
there is a big problem with users not understanding why we've chosen
&keywords and :keywords. The way keywords are currently defined, making
the words in the bvl be :keywords would not be incompatible since it
should be an error to bind a symbol in the keyword package anyway!  I am
not really proposing a change; just thinking aloud. We will some day be
subject to a lot of flack from users who claim that the spec is
cluttered by more layers of syntax than it need be. Consider that a
novice might find
 (DEFUN FOO (X :OPTIONAL Y Z :REST W) ...)
significantly easier to learn. And even
 (SELECTQ FOO ((A B) 3) ((C) 4) (:OTHERWISE 5))
has a certain appeal... I suppose the :OPTIONAL change might really
throw LispM Lisp through a loop during any transition ... On the other
hand, I bet changing all OTHERWISEs, &RESTs, &OPTIONALs, etc. would be
as simple as a single Tags Query Replace ... And once you release the
language, a change like that will never be so easy again ... Oh well.
I think if someone else did take this discussion seriously that I 
probably would too...
--kmp

∂15-May-83  1256	@MIT-MC:KMP@MIT-MC 	[Griss@UTAH-20: Forwarded]    
Received: from MIT-MC by SU-AI with TCP/SMTP; 15 May 83  12:56:25 PDT
Date: Sunday, 15 May 1983, 15:57-EDT
From: KMP@MIT-MC
Sender: kbe@MIT-OZ
Subject: [Griss@UTAH-20: Forwarded]
To: "Common-Lisp%SU-AI"@MIT-MC
Cc: JWalker@SCRC-TENEX

    Date: 15 May 1983 1310-MDT
    From: Martin.Griss <Griss@UTAH-20>
    Subject: Re: Keywords, :Keywords, &More-Keywords
    To: KMP@MIT-MC
    cc: Griss@UTAH-20
    In-Reply-To: Your message of 15-May-83 1440-MDT
    
    That certainly has a LOT of appeal to me! 
    M
    -------

∂15-May-83  2205	FAHLMAN@CMU-CS-C 	issues 
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 15 May 83  22:05:26 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 16 May 83 01:05:28 EDT
Date: Mon, 16 May 1983  01:05 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   common-lisp@su-ai
Subject: issues


The next edition of the manual is nearing final-assembly-and-test.  It
is my belief that we have more or less converged on Moon's proposals for
DEFSETF and for the ERROR chapter.  At least, several key people have
endorsed this proposal and nobody has raised major objections.  Unless
someone objects soon and violently (and I hope nobody does), Guy plans
to put these into the next edition of the manual, for final review by
the critics' gallery.

With a little luck, maybe we will have converged sufficiently on the new
package proposal to get that in too, though we're not there as of right
now, but maybe my latest proposal will make it.

-- Scott

∂15-May-83  2154	FAHLMAN@CMU-CS-C 	packages, yet again   
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 15 May 83  21:48:38 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 16 May 83 00:48:32 EDT
Date: Mon, 16 May 1983  00:48 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   common-lisp@su-ai
Subject: packages, yet again


One more try.  I guess if people always knew what they were getting
into, nobody would ever try to do anything interesting.

Major new features of this proposal:

1. The old "package augmenting" DECLARE-PACKAGE is gone.  Flexible, but
deemed to be too dangerous, since it allows users of a package to mess
with that package's external symbols.

2. INCLUDE-PACKAGE is gone.  If you want to do what INCLUDE-PACKAGE used
to do, you call USE-PACAKGE on the other package, then explictly EXPORT
all of the symbols that you want to pass along.  Deemed to make your
intentions clearer and to be less confusing overall.

3. If IMPORT or USE-PACAKGE creates a name conflict between one or more
of the imported symbols and some distinct symbol available in the
current package, a correctable error is signalled.  Each package keeps a
list of symbols that have been explicitly declared to be present and to
shadow other symbols (SHADOW and SHADOWING-INPUT add symbols to this
list) and these symbols always win any conflicts without signalling an
error.

4. A package must be created and all its externals must be set up before
any other package uses it.  If a package is being used by any other
package, an error is signalled if you try to change its set of external
symbols in any way.

5. The PROVIDE and REQUIRE functions from the Laser edition are
suggested as a way for the user to load complicated things without
having to worry about complicated order-of-load restrictions.  A few
changes are proposed in these functions.  They probably want to be moved
into this section, since there is a strong interaction with packages.
(Do we really want to keep these separate, or would a merger of modules
and packages make sense?)

The new version is relatively simple, fairly safe, and probably more
restrictive than it needs to be.  At this point it seems better to go
for something simple and restricitve that might conceivably survive the
onslaught of the critics.  We can always pass the user more rope later.

Here we go again:

***************************************************************************

@chapter [Packages]

@section [Overview]

One problem with earlier 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.  Common Lisp addresses this problem through the @i[package
system], derived from an earlier package system developed for Lisp
Machine Lisp.  In addition to preventing name-space conflicts, the
package system makes the modular structure of large Lisp systems more
explicit.

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'' machinery of earlier Lisp systems.  At any given time one
package is current, and this package is used by the reader in
translating strings into symbols.  The current package is always the
value of the global variable @b[*package*].  It is possible to refer to
symbols in packages other than the current one through the use of
@i[package qualifiers] in the symbol reference.  For example @b[foo:bar]
refers to the symbol whose name is @b[bar] in the package whose name is
@b[foo].

The string-to-symbol mappings available in a given package are divided
into two classes, @i[external] and @i[internal].  We refer to the
symbols accessible via these mappings as being @i[external] and
@i[internal] symbols of the package in question, though really it is the
mappings that are different and not the symbols themselves.  Within a
given package, a name refers to one symbol or to none; if it does refer
to a symbol, that symbol is either external or internal in that
package, but not both.

External symbols are part of the package's public interface to other
packages.  These are supposed to be chosen with some care and are
advertised to users of the package.  Internal symbols are for internal
use only, and these symbols are normally hidden from other packages.
Most symbols are created as internal symbols; they become external only
if they appear explicitly in some package's @b[export] command.

A symbol may appear in many packages.  It will always have the same
print name wherever it appears, but it may be external in one package
and internal in another.  A name may refer to different symbols in
different packages.

Packages may be built up in layers.  From the point of view of a
package's user, the package is a single collection of mappings from
strings into internal and external symbols.  However, some of these
mappings may be established within the package itself, while other
mappings are inherited from other packages via the @b[use-package]
construct.  (The mechansims responsible for this inheritance are
described below.)  In what follows, we will refer to a symbol as being
"accessible" in a package if it can be referred to in that package
without a qualifier, regardless of whether the mapping occurs within
that package or via inheirtance; we will refer to a symbol as being
"present" in a package if the mapping is in the package itself and is
not inherited from somewhere else.

@section [Consistency Rules]

Package-related bugs can be very subtle and confusing: things are not
what they appear to be.  The Common Lisp package system is designed with
a number of safety features to prevent most of the common bugs that
would otherwise occur in normal use.  This may seem over-protective, but
experience with earlier package systems has shown that such safety
features are needed.

In dealing with the package system, it is useful to keep in mind the
following consistency rules, which remain in force as long as the value
of @b[*package*] is not changed by the user or his code:

@begin [itemize]
@b[Read-Read consistency:] Reading the same print name always gets you
the same (EQ) symbol.

@b[Print-Read consistency:] An interned symbol always prints as a
sequence of characters which, when read back in, yields the same (EQ)
symbol.

@b[Print-Print consistency:] If two interned symbols are not EQ, then
their printed representations will not be the same sequence of
characters.
@end [itemize]

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:
changing the value of @b[*package*], forcing some action by continuing
from an error, or calling one of the ``dangerous'' functions:
@b[unintern], @b[shadow], or @b[shadowing-import].

In general, an error is signalled if the user takes any action that
would replace one symbol available in a package with a different symbol of
the same name.  Such "implicit shadowing" is usually an error.  However,
the user can explictily ask for such shadowing to occur with the @b[shadow]
and @b[shadowing-import] functions.  These functions indicate that certain
symbols are to be directly present in a package and that they are to take
precedence over any symbol of the same name that would otherwise be
inherited by that package.  Each package keeps a list of such shadowing
symbols, so that subsequent calls to @b[use-package] or @b[import]
will not interfere with the user's declared intentions.

@section [Package Names]

Each package has a name (a string) and perhaps some nicknames.  These
are assigned when the package is created, though they can be changed
later.  A package's name should be something long and self-explanatory
like "editor"; there might be a nickname that is shorter and easier to
type, like "ed".  Package name strings retain whatever mixture of upper
and lower case characters the user supplies, but the translation from
names to packages is case-insensitive, so users can generally refer to
packages without worrying about case.

There is a single name space for packages.  The function
@b[find-package] translates a package-name or nickname into the
associated package.  The function @b[package-name] returns the name of a
package.  The function @b[package-nicknames] returns a list of all
nicknames for a package.  The function @b[rename-package] removes a
package's current name and nicknames and replaces them with new ones
specified by the user.  Package renaming 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.

@section [Translating Strings to Symbols]

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], and their package cell contains NIL.)

Often it is desirable to refer to an external symbol in some package
other than the current one.  This is done through the use of a
@i[qualified name], consisting of a package name, then a colon, then 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 external symbol named ``@b[buffer]''
available in the package named ``@b[editor]'', regardless of whether
there is a symbol named ``@b[buffer]'' in the current package.  If there
is no package named ``@b[editor]'', or if no symbol named ``@b[buffer]''
is available in ``@b[editor]'' or if ``@b[buffer]'' is an internal
symbol in ``@b[editor]'', a correctable error is signalled to ask the
user what he really wants to do.

On rare occasions, a user may need to refer to an @b[internal] symbol of
some package other than the current one.  It is illegal to do this with
the colon qualifier, since accessing an internal symbol of some other
package is usually a mistake.  However, this operation is legal if you
use ``@b[#:]'' as the separator in place of the usual colon.  If
``@b[editor#:buffer]'' is seen, the effect is exactly the same as
reading ``@b[buffer]'' with @b[*package*] temporarily rebound to the
package whose name is ``@b[editor]''.  This special-purpose qualifier
should be used with caution.

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 provides a special reader syntax for them:
any symbol preceded by a colon but no package name (for example
``@b[:foo]'') is added to (or looked up in) the @b[keyword] package as
an @i[external] symbol.  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.  As a matter of style, keywords should always be accessed using
the leading-colon convention; you never want to import or inherit
keywords into any other package.

Each symbol contains a package slot that is used to record the home
package of the symbol, or NIL if the symbol is uninterned.  When an
interned symbol is printed, if it is an external symbol in the keyword
package then it is printed with a preceding colon; otherwise, if it is
available (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, using ``@b[:]'' as the
separator if the symbol is external and ``@b[#:]'' if not.

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 has no recorded home package, but that in fact is
interned in some package.  The system does not check for this.

In summary, the following four cases are defined:

@Begin[describe]
@b[foo:bar] @\Look up "bar" among the external symbols available in the
package named "foo".

@b[foo#:bar] @\Look up "bar" among the external and internal symbols
available in the package named "foo".

@b[:bar] @\The symbol named "bar" is a self-evaluating keyword.

@b[#:bar] @\The symbol named "bar" is uninterned.
@End[describe]

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.

@section [Exporting and Importing Symbols]

Symbols from one package may be made available in another package in
two ways.

First, any individual symbol may be added to a package by use
of the @b[import] function.  The form @b[(import 'editor:buffer)] takes
the external 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 importing 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.  Once imported, a symbol is @i[present] in the
importing package and can only be removed by calling @b[unintern].

If the symbol is already present in the importing package, @b[import]
has no effect.  If a distinct symbol with the name @b[buffer] is
available in the importing package (directly or by inheritance) a
correctable error is signalled.  The user will then be offered a choice
of whether or not the importation of this symbol is to proceed.

If the user really wants to do a shadowing import without getting an
error, he should use the @b[shadowing-import] function.  This inserts
the symbol into the specified package as an internal symbol, regardless
of whether another symbol of the same name will be shadowed by this
action.  The symbol is also added to the package's shadowing-symbols list.
@b[Shadowing-import] may create confusing situations which violate the
consistency rules, so it should be used with caution.

The second mechanism is provided by the @b[use-package] function.  This
causes a package to inherit all of the external symbols of some other
package.  These symbols become available as @i[internal] symbols of the
using package.  That is, they can be referred to without a qualifier
while this package is current, but they are not passed along to any
other package that uses this package.

Often a user, working by default in the @b[user] package, will
load a number of packages into his Lisp to provide an augmented working
environment; then he will call @b[use-package] on each of these packages
so that he can easily access their external symbols.

When @b[use-package] is called, it checks the external symbols of the
package being used against the set of symbols already available in the
using package.  If there is a conflict -- that is, if one of the
imported symbols has the same name as a distinct symbol already present
in the package -- then a correctable error is signalled asking the user
whether the imported or the existing symbol is to be retained in the
package.  This error does not occur if the existing symbol is on the
package's shadowing-symbols list; in that case, the existing symbol wins
and continues to be available in that package, shadowing the symbol from
the package being used.  Thus, if the user wants to use a package, minus
a few of its external symbols (for which he has local versions), he can
avoid any error by explictly shadowing those symbols before calling
@b[use-package].

@b[Unuse-package] undoes the effects of a previous @b[use-package].  The
external symbols of the used package are no longer inherited.  However,
any symbols that have been imported into the using package continue to
be present in that package.

There is no way to inherit the @i[internal] symbols of another package;
to refer to an internal symbol, you must either make that symbol's home
package current, use a qualifier, or import that symbol into the current
package.

When @b[intern] or some other function wants to look up a symbol in a
given package, it first looks for the symbol among the external and
internal symbols of the package itself; then it looks through the
external symbols of the used packages in some unspecified order.  The
order does not matter; according to the rules above if conflicting
symbols appear in two or more packages inherited by package X, a symbol
of this name must also appear in X itself as a shadowing symbol.  Of
course, implementations are free to choose other, more efficient ways of
implementing this search, as long as the user-visible behavior is
equivalent to what is described here.

The @b[export] function takes a symbol that is available in some package
and makes it an external symbol of that package.  If the symbol is
already available as an external symbol in the package, @b[export] has
no effect.  If the symbol is directly present in the package as an
internal symbol, it is simply changed to external status.  If it is
available as an internal symbol via @b[use-package], the symbol is first
imported into the package, then exported.  (It is now present in this
package whether or not it continues to use the symbol's original
package.)  If the symbol is not available at all in the specified
package, a correctable error is signalled which, upon continuing, asks
the user whether the symbol should be imported.

The @b[unexport] function is provided mainly as a way to undo erroneous
calls to @b[export].  It works only on symbols that are directly present
in the current package, switching them back to internal status.  If
@b[unexport] is given a symbol that is already available as an internal
symbol in the current package, it does nothing; if it is given a symbol
that is not available in the packge at all, it signals an error.

@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 use @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 uses 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 external symbols in the this package.  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[system]@\This package name is reserved to the implementation.
Normally this is used to contain names of implementation-dependent
system-interface functions.  This package uses @b[lisp] and has the
nickname @b[sys]. 
@end[description]

@Section[Package System Functions and Variables]

Some of the following have been described earlier, but are included here
for completeness.  Note that the following functions are meant to be
used at top-level in files, and should only be used at top-level if you
want to guarantee proper compilation across all Common Lisp
implemenations: @b[in-package], @b[import], @b[export], @b[unexport],
@b[shadow], @b[use-package], and @b[unuse-package].

For the functions described here, all optional arguments named
@i[package] default to the current value of @b[*package*].  Where a
function takes an argument that is either a symbol or a list of symbols,
an argument of NIL is treated as an empty list of symbols.

@Defvar[Var {*package*}]
The value of this variable must be 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] @key @i[nicknames]
@i[use]}]
Creates and returns a new package with the specified package name.  The
@b[:nicknames] argument must be a list of strings to be used as
alternative names for the function.  These names must not conflict with
any existing package names; if they do, a correctable error is
signalled.

The @b[:use] argument is a list of packages or package names whose
external symbols are to be inherited by the new package.  These package
must already exist, and their external symbols must already have been
exported.  If not supplied, @i[:use] defaults to a list of one package,
the @b[lisp] package.
@Enddefun

@Defun[Fun {in-package}, Args {@i[package-name] @key @i[nicknames] @i[use]}]
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 to @b[make-package], except that after the
new package is created, @b[*package*] is set 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.
@enddefun

@Defun[Fun {find-package}, Args {@i[name]}]
The @i[name] must be a string that is the name or nickname for a
package.  Returns the corresponding package, or NIL if no such package
exists.  This match ignores case (as in @b[string-equal]).
@Enddefun

@Defun[Fun {package-name}, Args {@i[package]}]
The argument must be a package.  This function returns the string that
names that package.
@Enddefun

@Defun[Fun {package-nicknames}, Args {@i[package]}]
The argument must be a package.  This function returns the list of
nickname strings for that package, not including the primary name.
@Enddefun

@Defun[Fun {package-use-list}, Args {@i[package]}]
Returns the list of other packages used by the argument package.
@Enddefun

@Defun[Fun {package-used-by-list}, Args {@i[package]}]
Returns the list of other packages that use the argument package.
@Enddefun

@Defun[Fun {package-shadowing-symbols}, Args {@i[package]}]
Returns the list of symbols in that have been declared as shadowing
symbols in this package by @b[shadow] or @b[shadowing-import].  All
symbols on this list are present in the specified package.
@Enddefun

@Defun[Fun {list-all-packages}, Args {}]
This function returns a list of all packages that currently exist in the
Lisp system.
@Enddefun

@Defun[Fun {intern}, Args {@i[string] @optional @i[package]}]
@i[Package], which defaults to the current package, 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.
@Incompatibility{Conceptually, @b[intern] translates a
string to a symbol.  In Maclisp and several other Lisps, @b[intern] can
take either a string or a symbol as its argument; in the latter case,
the symbol's print name is extracted and used as the string.  However,
this leads to some confusing issues about what to do if
@b[intern] finds a symbol that is not @b[eq] to the argument symbol.  To
avoid such confusion, we require the argument to be a string.}
@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 if it is internal.  If the symbol is not found in the specified package,
@b[find-symbol] returns NIL for all three values.
@Enddefun

@Defun[Fun {find-external-symbol}, Args {@i[string] @optional @i[package]}]
This is identical to @b[find-symbol], but it does not look for internal
symbols even in @i[package] itself.  This is the type of search done by
the reader for symbols qualified with a package name and a colon.  The
return values are the same as for @b[find-symbol], with the third return
value always being T (external symbol) if a symbol is found.
@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, and also from the package's shadowing-symbols
list if it is present there.  Moreover, if @i[package] is the home
package for the symbol, the symbol is made to have no home package.
@b[Unintern] returns T if it actually removed a symbol, and NIL otherwise.
Note that @i[unintern] should be used with caution, since it can produce
confusing situations that violate the consistency rules listed above.
@Incompatibility{The equivalent of this in @maclisp is @f[remob].}
@Enddefun

@Defun[Fun {export}, Args {@i[symbols] @optional @i[package]}]
The @i[symbols] argument should be a list of symbols, or possibly a single
symbol.  These symbols become available as external symbols in the
current package.  (See the previous section for details.)  If
@i[package] is currently used by another package, any use of @i[export]
signals a correctable error.  Returns T.

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
mentioned the file are intended to be used by other programs.
@Enddefun

@Defun[Fun {unexport}, Args {@i[symbols] @optional @i[package]}]
The argument should be a list of symbols, or possibly a single symbol.
These symbols become internal symbols in @i[package].  (See the
previous section for details.)  If @i[package] is currently used by
another package, any use of @i[unexport] signals a correctable error.
Returns T.
@Enddefun

@Defun[Fun {import}, Args {@i[symbols] @optional @i[package]}]
The argument should be a list of symbols, or possibly a single symbol.
These symbols become internal symbols in @i[package], and can therefore
be referred to without a colon qualifier.  @b[Import] signals a
correctable error if any of the imported symbols has the same name as
some distinct symbol already available in the package.  (See the previous
section for details.)  Returns T.
@Enddefun

@Defun[Fun {shadowing-import}, Args {@i[symbols] @optional @i[package]}]
This is like import, but it does not signal an error even if the
importation of a symbol would shadow some symbol already available in
the package.  In addition to being imported, the symbol is placed on the
shadowing-symbols list of @i[package].  (See the previous section for
details.)  Note that @i[shadowing-import] should be used with caution,
since it can produce confusing situations that violate the consistency
rules listed above.  Returns T.
@Enddefun

@Defun[Fun {shadow}, Args {@i[symbols] @optional @i[package]}]
The argument should be a list of symbols, or possibly a single symbol.
The print-name of each symbol is extracted, and the current package is
searched for a symbol of that name.  If such a symbol is present in this
package (directly, not by inheritance) then nothing is done.  Otherwise,
a new symbol is created with this print name, and it is inserted in the
current package as an internal symbol.  The symbol is also placed on the
shadowing-symbols list of @i[package].  Note that @i[shadow] should be
used with caution, since it can produce confusing situations that
violate the consistency rules listed above.  Returns T.
@Enddefun

@Defun[Fun {use-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
the package's use-list if they are not there already.  All external
symbols in the argument packages become available in the current package
as internal symbols.  (See the previous section for details.)  Returns T.
@enddefun

@Defun[Fun {unuse-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 use-list.  Returns T.
@enddefun

@Defun[Fun {find-all-symbols}, Args {@i[string-or-symbol]}]
Searches every package in the Lisp system for symbols whose print-name is the
specified string, and returns a list of such symbols.  This search is
case-sensitive.  If the argument is a symbol, its print-name supplies
the string to be searched for.
@enddefun

@Defmac[Fun {do-symbols}, Args {(@i[var] @Mopt<@i[package]> @Mopt<@i[result-form]>) @Mstar<@i[declaration]> @mstar<@i[tag] @mor @i[statement]>}]
@b[Do-symbols] provides straightforward iteration over the symbols of a
package.  The body is performed once for each symbol available in the
@i[package], in no particular order, with the variable @i[var] bound to
the symbol.  Then @i[resultform] (a single form, @i[not] an implicit
@b[progn]) is evaluated, and the result is the value of the
@b[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 NIL.  @b[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 @b[unintern],
the effects are unpredictable.
@Enddefmac

@Defmac[Fun {do-external-symbols}, Args {(@i[var] @Mopt<@i[package]> @Mopt<@i[result-form]>) @Mstar<@i[declaration]> @mstar<@i[tag] @mor @i[statement]>}]
@b[Do-external-symbols] is just like @b[do-symbols], except that only
the external symbols of the specified package are scanned.
@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 @b[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

@Section[Modules]

A @i[module] is a Common Lisp subsystem that is loaded from one or more
files.  A module is normally loaded as a single unit, regardless of how
many files are involved.  A module may consist of one package or several
packages.  The file-loading process is necessarily
implementation-dependent, but Common Lisp provides some very simple
portable machinery for naming modules, keeping track of which modules
have been loaded, and for loading modules as a unit.

@Defvar[Var {*modules*}]
@Defun[Fun {provide}, Args {@i[module-name]}]
@Defun1[Fun {require}, Args {@i[module-name] @optional @i[pathname]}]

Each module has a unique name (a string).  If the module consists of a
single package, it is customary for the package and module names to be
the same.  The variable @b[*modules*] is a list of names of the modules
that have been loaded into the Lisp system so far.  The @b[provide]
function adds a new module name to this list, thereby indicating that
the module in question has been loaded.

The @b[require] function tests whether a module is already present
(using a case-insensitive comparison) and, if not, loads the appropriate
file or set of files.  The pathname argument, if present, is a single
pathname or a list of pathenames whose files are to be loaded in order,
left to right.  If the pathname argument is NIL or is not provided, the
system will attempt to determine which files to load in some
system-dependent manner.  This will typically involve some central
registry of module names and the associated file-lists.

@section [An Example]

Most users will want to load and use packages but will never need to
build one.  Often, a user will load a number of packages into the
@b[user] package whenever he uses Common Lisp.  Most implementations
will provide some sort of "init file" mechanism to make such setup
automatic when the Lisp starts up.  Init files are not normally
compiled.

@begin [Lisp]
;;; Lisp init file for I. Newton.

;;; Set up the USER package the way I like it.

;;; Calculus is used a lot.  Get easy access to all its symbols.
(require "calculus")
(use-package "calculus")

;;; Same for Newtonian mechanics.
(require "newtonian-mechanics")
(use-package "newtonian-mechanics")

;;; I just want a few thing from here, and other things conflict.
;;; Import just what I need into the USER package.
(require "relativity")
(import '(relativity:speed-of-light
	  relativity:ignore-small-errors))

;;; These are worth loading, but I will use qualifiers to get at any
;;; symbols I need.
(require "phlogiston.lsp")
(require "alchemy.lsp")
@end [Lisp]		

When each of two files uses some symbols from the other, we must be
careful to put the contents of the file in the file in the proper order.
Typically each file contains a single package that is a complete module.
The contents of such a file should include the following items, in
order:

@Begin[enumerate]
A @b[provide] call that announces the module name.

An @b[in-package] call that establishes the package.

A @b[shadow] call that establishes any local symbols that will shadow
symbols that would otherwise be inherited from packages that this
package will use.

An @b[export] call that establishes all of this package's external
symbols.

Any number of @b[require] calls to load other modules which the
contents of this file might want to use or refer to.  By placing these
@b[requires] calls here, we make it possible for the packages being
loaded to refer to external symbols in this package.

Any number of @b[use-package] and @b[import] calls, to make it the
symbols from other packages available in this package.

Finally, the definitions making up the contents of this package/module.
@End[enumerate]

<< Anybody got a good mnemonic for the sequence "PISERIUC"?  All I can
come up with is "Please insert seven extra rubles in user consultant."
Not too good. >>

Now, suppose that the @b[phlogiston] and @b[alchemy] packages are
single-file, single-package modules as described above.  Phlogiston
wants to use the alchemy package, and alchemy wants to use several
external symbols from phlogiston.  The following definitions allow the
user to supply @b[require] statement for either of these modules, or for
both of them in either order.

The file "alchemy.lisp":

@begin [lisp]
;;; Alchemy functions, written and maintained by Merlin, Inc.

;;; Both the module and the package are named "alchemy".
(provide "alchemy")
(in-package "alchemy")

;;; Nothing to shadow.

;;; Here is our external interface.
(export '(lead-to-gold gold-to-lead antimony-to-zinc elixir-of-life))

;;; This file uses some functions from the phlogiston package/module.
(require "phlogiston")

;;; We use this a lot, so import it.  It's external in phlogiston package.
(import '(phlogiston:make-fire-bottle))

;;; Now for the real contents of this file.

(defun lead-to-gold (x)
  "Takes a quantity of lead, returns gold."
  (when (> (phlogiston:heat-flow x) 3)	        ; Using a qualified symbol.
	(make-fire-bottle x))			; Using an imported symbol.
  (gild x))

;;; And so on ...
@end [lisp]

The file "phlogiston.lisp":

@begin [lisp]
;;; Phlogiston functions, written and maintained by Thermofluidics, Ltd.

;;; Both the module and the package are named "phlogiston".
(provide "phlogiston")
(in-package "phlogiston")

;;; Nothing to shadow.

;;; Here is our external interface.
(export '(heat-flow cold-flow mix-fluids separate-fluids
	  burn make-fire-bottle))

;;; This file uses some functions from the alchemy package/module.
(require "alchemy")

;;; We use alchemy functions a lot, so use the package.
(use-package "alchemy")

;;; The real contents of this package/module.

(defun heat-flow (amount x y)
  "Make some amount of heat flow from x to y."
  (when feeling-weak
	(quaff (elixir-of-life)))		; No qualifier needed.
  (push-heat amount x y))

;;; And so on ...
@end [lisp]

For very large packages whose contents are spread over several files
(the @b[lisp] package is an example), it is recommended that the author
create the package and declare all of the shadows and external symbols
in a separate file, so that this can be loaded before anything which
might use symbols from this package.

∂16-May-83  0040	@MIT-MC:MOON@SCRC-TENEX 	Keywords, :Keywords, &More-Keywords
Received: from MIT-MC by SU-AI with TCP/SMTP; 16 May 83  00:39:53 PDT
Date: Monday, 16 May 1983  02:47-EDT
From: MOON at SCRC-TENEX
To:   Kent M. Pitman <KMP at MIT-MC>
Cc:   Common-Lisp at SU-AI, JWalker at SCRC-TENEX
Subject: Keywords, :Keywords, &More-Keywords
In-reply-to: The message of 15 May 1983 14:40 EDT from Kent M. Pitman <KMP @ MIT-MC>

OTHERWISE is not a keyword for the same reason that DECLARE and
LAMBDA are not keywords.  While it isn't a function, and it isn't
a variable, it's still a syntactic word of the Lisp language.  Or
maybe it just would look ugly with a colon.

Whether it should be &OPTIONAL or :OPTIONAL is an entirely unrelated
issue.  Certainly the reasons why these are different are historical.
I can't defend the choice of &OPTIONAL except to say that if you
were serious about changing this you should have brought it up two
years ago, not a week or two before the final first version of the
manual comes out.

Guy certainly chose the quotation at the front of the manual rather well.

∂16-May-83  0101	KMP@MIT-MC
Received: from MIT-MC by SU-AI with TCP/SMTP; 16 May 83  01:01:15 PDT
Date: 16 May 1983 04:04 EDT
From: Kent M. Pitman <KMP @ MIT-MC>
To: Moon @ SCRC-TENEX
cc: Common-Lisp @ SU-AI, JWalker @ SCRC-TENEX

I did in fact propose that :keywords be used in lambda lists years ago
and at that time there was a good argument against it: such variables
could be bound and so it wasn't fair to special case them. Only with
the decision last August of making :keywords self-evaluate has this
been a possible course of action.

George Carrette mentioned to me today that the NIL interpreter has to go
checking the pnames of symbols to see if they start with "&" every time
you bind a symbol. That seems pretty gross. Checking the package cell
for EQness would be slightly faster or at least more elegant.

In fact, the argument about :OTHERWISE-ERROR and COND was slightly false
in that it's not inconsistent to allow keywords in COND now that you can
know what they will EVAL to. eg,
 (COND (FOO X) (:OTHERWISE Y))
 (COND (FOO X) (:OTHERWISE-ERROR Y))
would be specially recognized syntaxes. You'd case on the surface syntax,
not on what FOO evaluates to, so if FOO evaluted to :OTHERWISE or
:OTHERWISE-ERROR, that'd just mean true. It's a plausible model of the
world. It would be more regular and would unify a lot of concepts that
Common Lisp has been drifting toward.

But I've had my say and didn't really want to slow down anyone's work.
As I said, I was just thinking aloud. I'll consider the issue closed
for now unless someone else re-opens it...

∂16-May-83  1611	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	error.proposal.9
Received: from MIT-MC by SU-AI with TCP/SMTP; 16 May 83  16:01:25 PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Mon 16-May-83 19:04:59-EDT
Date: Monday, 16 May 1983, 19:02-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: error.proposal.9
To: Common-Lisp@su-ai

This is probably the final version of my error proposal.  Unless there
are objections it is ready to convert to Scribe, render style-compatible
with the Common Lisp manual, and adopt.

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.  There should be no indentation after a
carriage return in the middle of an error message.  If the debugger in
a particular implementation displays error messages indented (e.g. indented
by 7 spaces because they are prefixed by "Error: ") then it should take
care of inserting the appropriate amount of indentation into a multi-line
error message.  Similarly, a debugger that prefixes error messages with
semicolons should take care of inserting a semicolon at the beginning of
each line in a multi-line error message.  Note that even within a single
implementation, there may be more than one program that presents error
messages to the user, and they may use different styles, so the caller
of ERROR cannot provide for this in advance.

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 error-format-string continue-format-string &rest args
Signal an error, with the message constructed by applying FORMAT to
error-format-string and args.  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.

A message describing what will happen if the error is continued will be
constructed by applying FORMAT to continue-format-string and args.  This
message should be a one-line description of the effect of continuing.
It should be phrased as an English sentence in the imperative mood, just
like the documentation of a command or a function.  Typically it would
be used by an interactive debugger as the documentation of its
"continue" command.  The message supplied with CERROR should not include
any statement of how the "continue" command is given, since this may be
different for each debugger.  The debugger will insert this into the
message, according to its own particular user-interface style.

Examples:
	(UNLESS (= (LIST-LENGTH FORM) 3)
	  (CERROR "Wrong number of arguments in ~S"
		  (IF (< (LIST-LENGTH FORM) 3) "Assume 0 for missing args."
					       "Ignore extra args.")
		  FORM)
	  (SETQ FORM (APPEND FORM '(0 0))))
	Error: Wrong number of arguments in (F X)
	Error signalled by function EXAMPLE.
	If continued: Assume 0 for missing args.
	>

	(DO () ((KNOWN-WORDP X) X)
	  (CERROR "~S is unknown, probably misspelled."
		  "Replace ~S 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).

In complex cases where the error message uses some of the args and the
continue message uses others of the args, it may be necessary to use the
~G or ~* operators of FORMAT to skip over unwanted arguments in one of the
FORMAT control strings.

[The Lisp machine calls this FSIGNAL, except that it returns :NO-ACTION
rather than NIL and it fails to distinguish between the error message
and the continue message.]


WARN format-string &rest args
Print an error message constructed by applying FORMAT to the arguments,
but don't go into the debugger.  WARN returns NIL.  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-ON-WARNINGS*					Special Variable
If non-NIL, WARN prints its message and then goes to the debugger.  Continuing
causes WARN to return NIL.  If *BREAK-ON-WARNINGS* is NIL (the default),
then WARN just prints its message and returns NIL.  This flag is intended
for use when debugging programs that issue warnings and would not be turned
on in normal "production."


BREAK &optional format-string &rest args
Print the message and go directly into the debugger, without allowing
any possibility of interception by programmed 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.  When continued, BREAK returns NIL.  It is permissible to
call BREAK with no arguments; it will supply some default message.

BREAK is presumed to be used as a way of inserting temporary debugging
"breakpoints" in a program, not as a way of signalling errors.  Thus
continuing from a BREAK would never do anything special, and it does not
take the second FORMAT control-string argument that CERROR takes.  This
and the lack of any possibility of interception by programmed
error-handling are the only program-visible differences 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.

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)

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 decided, perhaps by fiat    (last chance to change our minds!)

Error messages and continue messages are complete sentences starting
with a capital letter, thus you can't embed them in the middle of other
sentences.  No attempt is made to exploit the lack of conjugation of
verbs in English; this wouldn't work for other natural languages anyway.
Thus we don't say that a continue message could be printed by itself,
prefixed by "The continue command will", or prefixed by "Type continue
to" in different implementations.

*BREAK-ON-WARNINGS* is in.

The syntax of ASSERT depends on the use of the error message string as
a delimiter, rather than putting an extra level of parentheses around
the references.

We say (ECASE X (FOO ...) (BAR ...)) rather than
(CASE X (FOO ...) (BAR ...) (OTHERWISE-ERROR)) or
(CASE X (FOO ...) (BAR ...) OTHERWISE-ERROR).

Subforms of the references in CHECK-TYPE, ASSERT, CTYPECASE, and CCASE may
be evaluated multiple times, depending on what the implementation wants to do.


- 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.  Some of these things
exist already as Symbolics extensions to Common Lisp and will be proposed
for standardization when things settle down a bit.  Should the manual
include this list, which may provide some rationale for what is in this
first version of the language?

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.

Formalization of the notion of "aborting a program," and provision of
mechanisms to define where control will be thrown to when the program is
aborted, as well as a function to abort the program.  This is more
complex than it seems because of interaction with the interactive
debugger and the condition system.

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.

A way to define the default description string for a user-defined type,
used when CHECK-TYPE is called with only two subforms.  This can of
course be a function of the type's parameters when the type is not
simply a symbol.

∂16-May-83  1647	@USC-ECL:GSB@MIT-ML 	args to error, cerror, & warn
Received: from USC-ECL by SU-AI with TCP/SMTP; 16 May 83  16:47:34 PDT
Received: from MIT-ML by USC-ECL; Mon 16 May 83 16:45:34-PDT
Date: 16 May 1983 19:46 EDT
From: Glenn S. Burke <GSB @ MIT-ML>
Subject: args to error, cerror, & warn
To: Common-Lisp @ SU-AI

I think we should require a first argument of NIL there now for
a place-holder since we are not going to define the extension yet.
Optional first arguments are a pain for both implementation and
documentation.
(Many of us have been doing this for years with FERROR in maclisp
anyway, where it was never really well-defined what a non-null
first argument meant.)

∂16-May-83  2016	KMP@MIT-MC 	error.proposal.9  
Received: from MIT-MC by SU-AI with TCP/SMTP; 16 May 83  20:15:59 PDT
Date: 16 May 1983 20:43 EDT
From: Kent M. Pitman <KMP @ MIT-MC>
Subject: error.proposal.9
To: Moon @ SCRC-TENEX
cc: Common-Lisp @ SU-AI

How literally do you mean that BREAK should enter the debugger?
On Maclisp and even now on the LispM, when you type Break, you are at a place
where you type s-expressions, not commands. On the LispM, you have a wide
enough character set to be able to merge the break facility with the debugger
and still win, but in ASCII land, this will be a lot tougher. I, for one,
will be unhappy with BREAK putting me somewhere where the first thing I have
to type is a command to get me to a vanilla read eval print loop style 
debugging environment. I suggest that the wording should be weakened so that
BREAK is constrained only to pause and allow you access to debugging state
of some sort, but it should be up to the implementation whether a debugger
or read eval print loop is entered. I think this is in the domain of error
handling and is something and should at this point be left to individual
implementations.

Alternatively, I would not mind (I would even prefer) two similar commands,
like DBG and BREAK on the Lisp Machine, so I could call the one which was
appropriate for the kind of debugging I am doing. I will almost always know
in advance which of these debugging environments I want. If they happen to
be different entry points to the same program (as I suspect will eventually
be the case with the LispM), that's fine. It's just a question of intent.

The former suggestion is probably most practical at this point.

Other than that, I think error.proposal.9 looks fine.
--kmp

∂16-May-83  2032	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	args to error, cerror, & warn  
Received: from MIT-MC by SU-AI with TCP/SMTP; 16 May 83  20:32:46 PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Mon 16-May-83 21:01:50-EDT
Date: Monday, 16 May 1983, 20:59-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: args to error, cerror, & warn
To: Common-Lisp@SU-AI
In-reply-to: The message of 16 May 83 19:46-EDT from Glenn S. Burke <GSB at MIT-ML>

    Date: 16 May 1983 19:46 EDT
    From: Glenn S. Burke <GSB @ MIT-ML>
    Subject: args to error, cerror, & warn

    I think we should require a first argument of NIL there now for
    a place-holder since we are not going to define the extension yet.
    Optional first arguments are a pain for both implementation and
    documentation.

I don't think it would be a good idea to require that NIL be written
when the first argument is omitted, since all naive users will be
omitting the first argument.  The implementation pain is negligible
since there is no reason for these functions to be fast (anyway, they
call FORMAT!).  The documentation pain is real, but I think it is
outweighed by the convenience of having conditions be invisible to naive
users.

If the concensus of the committee is that we can't have optional first
arguments, then I will insist that the future extension to conditions be
made by introducing three new functions so that the basic functions don't
have to be called with an extraneous argument.

∂16-May-83  2040	FAHLMAN@CMU-CS-C 	args to error, cerror, & warn   
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 16 May 83  20:39:59 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 16 May 83 23:39:40 EDT
Date: Mon, 16 May 1983  23:39 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Cc:   Common-Lisp@SU-AI
Subject: args to error, cerror, & warn
In-reply-to: Msg of 16 May 1983 20:59-EDT from David A. Moon <Moon%SCRC-TENEX%MIT-MC at SU-DSN>


I'm sort of on the fence about whether a place-holder for the condition
name would be a good idea.  However, given Moon's strong feelings on the
subject, I think we would prefer an optional first argument to three new
functions.

-- Scott

∂16-May-83  2048	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	packages, yet again  
Received: from MIT-MC by SU-AI with TCP/SMTP; 16 May 83  20:48:04 PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Mon 16-May-83 20:53:24-EDT
Date: Monday, 16 May 1983, 20:51-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: packages, yet again
To: common-lisp@su-ai
In-reply-to: The message of 16 May 83 00:48-EDT from Scott E. Fahlman <Fahlman at CMU-CS-C>

I am quite happy with this version of the package proposal.  There are
still some minor nits to pick:

It doesn't say explicitly what happens if MAKE-PACKAGE is done twice with
the same name.  Is this an error?  Is it an error for IN-PACKAGE, too?  Is
there any attempt to detect two people independently choosing the same package
name, or is that expliclitly considered impractical to detect?  I'd suggest
that duplicate package name be an error for MAKE-PACKAGE, a primitive, but
not for IN-PACKAGE, since you'd like to be able to load a program twice
(presumably after changing it to fix something).

I hope you realize that IN-PACKAGE is incompatible with incremental
re-compilation of portions of files (after editing them), a Lisp machine
productivity feature that users are uniformly enthusiastic about.  I
would think that this would be something that Spice Lisp would definitely
want, too, once you have a compiler that runs natively in your Lisp.
I'm not sure yet whether we will strongly discourage people from using
IN-PACKAGE, or whether we will provide a kludgey way for the editor to
know that it must parse the beginning of the file looking for IN-PACKAGE
in order to determine in what package to read forms from the file.

Say somewhere that the accessor function for the home package of a symbol
is SYMBOL-PACKAGE.

It isn't clear from the description whether SHADOWING-IMPORT will call
UNINTERN if the symbol being shadowed is directly in the package (rather
than inherited with USE-PACKAGE).  Surely this must be what was intended.
Also SHADOWING-IMPORT should be in the list of functions that should be
used at top level.

The writeup doesn't say why certain functions should be used at top
level.  One reason is that if changes are being made to *package* with
the expectation that they will affect how forms later in the file are
read, then those changes had better happen at compile time before
further forms are read from the file.  The other reason is that in many
implementations the output from the compiler is designed so that the
loader can look symbols up once, rather having to call INTERN every time
a symbol is referenced.  This means that the compiler must know when the
package state is changing (i.e. the read-read consistency rule doesn't
apply).  It would probably be best to include an Implementation Note
pointing out the restrictions this places on the compiler/loader
implementation: the compiler may not read the whole file before compiling
any of it (as the Lisp machine used to do in order to improve virtual
memory locality); the loader may not do all its INTERNs before evaling
any of the top-level forms (as Multics Maclisp does).

The writeup should say explicitly which functions get an automatic
(eval-when (compile) ...) wrapped around them when they are seen at
top level by the compiler.  The example at the end is assuming this
implicitly.

I can find no justification in the previous discussion for the suddenly
introduced restriction that EXPORT and UNEXPORT are not allowed in
packages that have been USE-PACKAGE'd, unless this is a Solomonian
attempt to resolve the copy vs reference issue.  If this is trying to
deal with the case of exporting a symbol too late, after someone who
thought they were getting it via USE-PACKAGE made an internal symbol
instead, the naming conflict checks I suggested earlier detect this and
are able to tell you exactly what happened.  If this is trying to deal
with the case where exporting a new symbol, that people using
USE-PACKAGE didn't expect to see exported, causes what was expected to
be two distinct symbols, internal in different packages, to become one
(external) symbol, it doesn't deal with it.  That can just as well
happen if all the EXPORTs are done before all the USE-PACKAGEs, and is
basically indetectable.  This screw case is really a lot like someone
changing what a function does without telling everyone who uses it.

The writeup says that SHADOW and SHADOWING-IMPORT "can produce confusing
situations that violate the consistency rules."  This is misleading.
They are a change of package state, just like setting *PACKAGE*, so there
isn't consistency between the world before calling SHADOW and the world
after calling it.  But the world after calling SHADOW is consistent with
itself.

The &optional package argument to USE-PACKAGE and UNUSE-PACKAGE is missing.

Why does it say init files are not usually compiled?  This is a non-sequitur
where it appears, and also is untrue in some implementations, ours for instance.

Why do two of the modules in Newton's init file have ".lsp" in their names?

∂16-May-83  2103	@MIT-MC:Moon%SCRC-TENEX%MIT-MC@SU-DSN 	error.proposal.9
Received: from MIT-MC by SU-AI with TCP/SMTP; 16 May 83  21:03:47 PDT
Received: from SCRC-EUPHRATES by SCRC-TENEX with CHAOS; Mon 16-May-83 21:08:25-EDT
Date: Monday, 16 May 1983, 21:06-EDT
From: David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Subject: error.proposal.9
To: Kent M. Pitman <KMP%MIT-MC@SU-DSN>
Cc: Common-Lisp@SU-AI
In-reply-to: The message of 16 May 83 20:43-EDT from Kent M. Pitman <KMP at MIT-MC>

    Date: 16 May 1983 20:43 EDT
    From: Kent M. Pitman <KMP @ MIT-MC>
    How literally do you mean that BREAK should enter the debugger?
Quite literally.

    On Maclisp and even now on the LispM, when you type Break, you are at a place
    where you type s-expressions, not commands.
The BREAK function and the Suspend key (labelled Break on old keyboards)
are not the same.  Indeed I propose to change the BREAK function
incompatibly with Maclisp and Zetalisp.  The name of the function would
have been changed, too, but no one liked any alternative names.

If other implementations want BREAK to go into a read-eval-print loop, I
am amenable to weakening the wording in the manual.  But I think it
would be much better to provide a function specifically for doing a
read-eval-print loop.  BREAK isn't really such a good name for that
function, since if BREAK means anything at all, it means "breakpoint"
which is historically associated with debuggers.

∂17-May-83  0822	GRISS%UTAH-20.ARPA@SUMEX-AIM 	Debug vs Break 
Received: from SUMEX-AIM by SU-AI with PUP; 17-May-83 08:18 PDT
Received: from UTAH-20 by SUMEX-AIM.ARPA with TCP; Tue 17 May 83 05:37:40-PDT
Date: 17 May 1983 0633-MDT
From: Martin.Griss <Griss@UTAH-20>
Subject: Debug vs Break
To: common-lisp@SU-AI
cc: griss@UTAH-20

I'm not entirely familiar with LispM debug vs Break. In PSL, the Break loop
IS a read-eval-print loop; it has a distinguished prompt, and a few
characters/ids are enabled as aliases for functions. E.g.,

Q -> (BREAK-QUIT)
T -> (BREAK-BACK-TRACE)
C -> (BREAK-CONTINUE)
R -> (BREAK-RETRY)

etc. We could envision that the single stepper is also present, and
off, but ready to be invoked in a retry mode, by say S, or some such.

In an environment that we are developing using a multi-window EMACS
like editor (NMODE), we have experimented with a "pop-up"
window/buffer in which the single chars above are present and ready to
be pointed at and executed (a "menu"). Normal editing and execution of
s-expressions can proceed. The Break/Debug commands can also be bound
to appropriate CNTRL-keys (e.g. LISP-Q, LISP-A), via an appropriate
dispatch table for BREAK-MODE, a modified LISP-MODE.

Various  combinations of these techniques can gracefully merge
a "read-eval-print" break loop, with a Debug loop.

Martin
-------

∂17-May-83  1917	FAHLMAN@CMU-CS-C 	Break  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 17 May 83  19:17:14 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 17 May 83 22:16:19 EDT
Date: Tue, 17 May 1983  22:16 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   common-lisp@su-ai
Subject: Break


How about if we just say that BREAK enters the debugger or a recursive
read/eval/print loop at the implementation's discretion?  Attempting to
nail down exactly what happens here is probably a bad idea, given the
variety of user-interface styles that we will want to support.  I find
it pretty hard to believe that people are worried about the one
keystroke that it ought to take to get from one kind of loop to the
other in any event.  Can anyone NOT live with this?

-- Scott

∂17-May-83  2109	FAHLMAN@CMU-CS-C 	Conservation of nits  
Received: from CMU-CS-C by SU-AI with TCP/SMTP; 17 May 83  21:09:04 PDT
Received: ID <FAHLMAN@CMU-CS-C>; 18 May 83 00:08:23 EDT
Date: Wed, 18 May 1983  00:08 EDT
From: Scott E. Fahlman <Fahlman@CMU-CS-C>
To:   David A. Moon <Moon%SCRC-TENEX%MIT-MC@SU-DSN>
Cc:   common-lisp@su-ai
Subject: Conservation of nits
In-reply-to: Msg of 16 May 1983 20:51-EDT from David A. Moon <Moon%SCRC-TENEX%MIT-MC at SU-DSN>


Fahlman's Law of Package Systems: Nits can neither be created nor
destroyed.  It is occasionally possible to smash big ones into a whole
lot of little ones.

    I'd suggest
    that duplicate package name be an error for MAKE-PACKAGE, a primitive, but
    not for IN-PACKAGE, since you'd like to be able to load a program twice
    (presumably after changing it to fix something).

OK.  That's the way I had it originally, before our go-round about
IN-PACKAGE augmenting the externals of the package in question.

    I hope you realize that IN-PACKAGE is incompatible with incremental
    re-compilation of portions of files (after editing them), a Lisp machine
    productivity feature that users are uniformly enthusiastic about.  I
    would think that this would be something that Spice Lisp would definitely
    want, too, once you have a compiler that runs natively in your Lisp.
    I'm not sure yet whether we will strongly discourage people from using
    IN-PACKAGE, or whether we will provide a kludgey way for the editor to
    know that it must parse the beginning of the file looking for IN-PACKAGE
    in order to determine in what package to read forms from the file.

I don't completely understand this.  I looked for incremental
compilation in the Confederate edition of the Chine Nual and couldn't
find anything about it.  What exactly do you folks do?  I would have
assumed that if you do incremental re-compilation on an ASCII file, you
take some notice of the -*-Package:foo-*- business, no?  IN-PACKAGE
would have the same set of problems as that.  I would hate to have you
tell users not to use IN-PACKAGE.  Do you have a specific proposal?

    Say somewhere that the accessor function for the home package of a symbol
    is SYMBOL-PACKAGE.

OK

    It isn't clear from the description whether SHADOWING-IMPORT will call
    UNINTERN if the symbol being shadowed is directly in the package (rather
    than inherited with USE-PACKAGE).  Surely this must be what was intended.
    Also SHADOWING-IMPORT should be in the list of functions that should be
    used at top level.

OK

    The writeup doesn't say why certain functions should be used at top
    level.  One reason is that if changes are being made to *package* with
    the expectation that they will affect how forms later in the file are
    read, then those changes had better happen at compile time before
    further forms are read from the file.  The other reason is that in many
    implementations the output from the compiler is designed so that the
    loader can look symbols up once, rather having to call INTERN every time
    a symbol is referenced.  This means that the compiler must know when the
    package state is changing (i.e. the read-read consistency rule doesn't
    apply).  It would probably be best to include an Implementation Note
    pointing out the restrictions this places on the compiler/loader
    implementation: the compiler may not read the whole file before compiling
    any of it (as the Lisp machine used to do in order to improve virtual
    memory locality); the loader may not do all its INTERNs before evaling
    any of the top-level forms (as Multics Maclisp does).

    The writeup should say explicitly which functions get an automatic
    (eval-when (compile) ...) wrapped around them when they are seen at
    top level by the compiler.  The example at the end is assuming this
    implicitly.

Well, both of the above comments assume that the compiler represents
symbols and their packages internally just by reading them into the
right package.  Certainly the compiler has to keep track of what
packages the various symbols want to end up in, but this might be done
by some more complex mechanism if the compiler wanted to keep its guts
somewhat separate from the stuff it is reading.  I'll see if I can say
something sufficient about this without over-specifying the mechanism.

    I can find no justification in the previous discussion for the suddenly
    introduced restriction that EXPORT and UNEXPORT are not allowed in
    packages that have been USE-PACKAGE'd, unless this is a Solomonian
    attempt to resolve the copy vs reference issue.  If this is trying to
    deal with the case of exporting a symbol too late, after someone who
    thought they were getting it via USE-PACKAGE made an internal symbol
    instead, the naming conflict checks I suggested earlier detect this and
    are able to tell you exactly what happened.  If this is trying to deal
    with the case where exporting a new symbol, that people using
    USE-PACKAGE didn't expect to see exported, causes what was expected to
    be two distinct symbols, internal in different packages, to become one
    (external) symbol, it doesn't deal with it.  That can just as well
    happen if all the EXPORTs are done before all the USE-PACKAGEs, and is
    basically indetectable.  This screw case is really a lot like someone
    changing what a function does without telling everyone who uses it.

I was just trying to do something simple and safe that might end the
debate.	 I figured that I could get this "package locking" rule right on
the first try, and that some tricky rule to signal an error only in the
case of a conflict with some symbol in the inferior package that is not
on that package's shadow list would lead to N more rounds of revision.

You seem to understand this better than I do.  How about if you propose
the exact wording for the error-checking rule you would like to see here
(both for EXPORT and for UNEXPORT)?  That would be the quickest way to
converge, I think.

    The writeup says that SHADOW and SHADOWING-IMPORT "can produce confusing
    situations that violate the consistency rules."  This is misleading.
    They are a change of package state, just like setting *PACKAGE*, so there
    isn't consistency between the world before calling SHADOW and the world
    after calling it.  But the world after calling SHADOW is consistent with
    itself.

OK, good point, sloppy wording.

    The &optional package argument to USE-PACKAGE and UNUSE-PACKAGE is missing.

OOPS.

    Why does it say init files are not usually compiled?  This is a
    non-sequitur where it appears, and also is untrue in some
    implementations, ours for instance.

Weinreb and Greenberg sent me a message pointing out that Newton's init
file would not work if compiled, and that it needed some (eval-when
(compile ..)) stuff added.  Since this was supposed to the simple part
of the example (the sort of interaction that naive users might have with
the package system), I didn't want to hair it up that way, so I just
mentioned that you don't want to compile these things.  Actually, I
guess with the recent changes, and if we put in the comment about
implicit EVAL-WHENs, we don't need to worry about this.

Just out of curiosity, why in the world would anyone compile an INIT
file?

    Why do two of the modules in Newton's init file have ".lsp" in their names?

OOPS, again.

I'll try to get this fixed up tomorrow.

-- Scott