[comp.ai] Common Lisp lacks portability

ruffwork@orstcs.CS.ORST.EDU (Ritchey Ruff) (12/08/87)

Would you use a language that can arbitrarily ignore some of your
code ???  Especially if different implementations ignored different
statements in the same code ???  Even if it didn't TELL you what
it was ignoring when ???

I have a bone to pick with Steele about something he left out of
the Common Lisp definition.  The above is *EXACTLY* what Common
Lisp *DOES* !!! In the sections about the
strong typing, "Common Lisp:The Language" says the compiler 
or interpreter can ignore many declarations.  It should also 
state that there be a standard way to find out WHAT the compiler/
interpreter is ignoring (or using).  Something like a compiler flag 
(":declares-ignored t/nil") or a global flag (*IGNORED-WARNINGS*) to 
force common lisp to show what it is ignoring.

Why, you ask???  First, principle (I kind of like that ;-):
when you put in strong typing statements (like "(the integer foo)")
do you REALLY want them ignored in different ways, at different times,
by different Common Lisps - and not even know which is ignoring
what when ??? 

Second, I've just spent weeks tracking bugs caused by 
compilers/interpreters ignoring different parts of my declarations.  Simply
because an interpreter/compiler can IGNORE strong typing (like 
"(the integer foo)"), optimizer statements (like safety=3), 
and declarations (like "(declare (integer foo))") I found that
code that ran ok on one version of Common Lisp would not even
compile under another, run but go into a break on another, and
run to completion but give wrong results on another !!!!

For example - lots of people use Bill Shelters' excellent SLOOP
looping macro package (thanks for all that work you put into an
excellent package, Bill!).  Its great, but because it tries to
optimize (by default it expands with declarations that give
type info on looping vars, etc.) it turns out to be non-portable.  
Here is a totally non-portable piece of code -

	(DEFUN TST (N M)
	       (SLOOP FOR I FROM N TO M COLLECT I))

This is quite simple, right?  When it expands N, M, and I get
declared of type integer, and the iteration var gets checked by 
the "THE" statement each time it's incremented to see that it
remains of type integer.  Below are results from several different
Common Lisps (all this was done with safety=3) ---

	----------------------------------------
	FranzExtendedCommonLisp> (tst 1 5)
		(1 2 3 4 5)

	FranzExtendedCommonLisp> (tst 1.0 5.0)

	Continuable Error: Object 2.0 is not of type FIXNUM.
	If continued with :continue, Prompt for a new object.
	[1c] <cl> ^D

	FranzExtendedCommonLisp> (compile 'tst)
	TST
	FranzExtendedCommonLisp> (tst 1.0 5.0)
		(1.0 2.0 3.0 4.0 5.0)

	FranzExtendedCommonLisp> (tst 1 5.0)
		(1 2 3 4 5)
	----------------------------------------
	KyotoCommonLisp> (tst 1 5)
		(1 2 3 4 5)

	KyotoCommonLisp> (tst 1.0 5.0)

		Error: 2.0 is not of type FIXNUM.
		Error signaled by THE.

		Broken at THE.  Type :H for Help.
	KyotoCommonLisp>> :q
	KyotoCommonLisp> (compile 'tst)
		End Pass1.
		End Pass2.

		TST
	KyotoCommonLisp> (tst 1.0 5.0)
		(0)
	KyotoCommonLisp> (tst 1 5.0)
		NIL
	----------------------------------------
	AllegroCommonLisp> (tst 1 5)
		(1 2 3 4 5)
	AllegroCommonLisp> (tst 1.0 5.0)
		(1.0 2.0 3.0 4.0 5.0)
	AllegroCommonLisp> (compile 'tst)
		TST
	AllegroCommonLisp> (tst 1.0 5.0)
		(1.0 2.0 3.0 4.0 5.0)
	AllegroCommonLisp> (tst 1 5.0)
		(1 2 3 4 5)
	----------------------------------------

So we have 3 different "Common Lisps" (and the quotes are intentional)
that give radically different results for the SAME code !!!  EVEN the
interpreter (Help me, Spock ;-) !!!  If the compiler and interpreter
gave warnings when they ignored code the reason for the bugs that this type
of behavior can cause would be so much easier to track down.
When you have your code debugged and are looking for raw speed, 
a global flag could be set to stop displaying warnings of this type.

MORAL OF THE STORY --- IF YOU WANT TRULY PORTABLE COMMON LISP CODE 
	THAT WORKS THE SAME INTERPRETED AS COMPILED, *DO* *NOT* PUT 
	STRONG TYPING OR OPTIMIZER STATEMENTS ANYWHERE IN YOUR CODE !!!
	IF *ANYTHING* *CAN* IGNORE A STATEMENT, *NEVER* USE THAT STATEMENT !!!

I've gone on too long, but I think I've made my point.
Thanks for the bandwidth,

--Ritchey Ruff				ruffwork@cs.orst.edu -or-
 "I haven't lost my mind,		ruffwork%oregon-state@relay-cs-net -or-
  its' backed up on tape somewhere..."	{ hp-pcd | tektronix }!orstcs!ruffwork

kers@otter.HP.COM (Christopher Dollin) (12/09/87)

Re:

> I have a bone to pick with Steele about something he left out of
> the Common Lisp definition.  The above is *EXACTLY* what Common
> Lisp *DOES* !!! In the sections about the
> strong typing, "Common Lisp:The Language" says the compiler
> or interpreter can ignore many declarations.  It should also
> state that there be a standard way to find out WHAT the compiler/
> interpreter is ignoring (or using).  Something like a compiler flag
> (":declares-ignored t/nil") or a global flag (*IGNORED-WARNINGS*) to
> force common lisp to show what it is ignoring.
[etc]

Doesn't Steel say that a program that violates type declarations "is in error"
and that an implementaion is "encouraged but not required to detect such an
error"?

Your program is in error. As such, all bets are off. The latitude Steele
permits to implementations is to allow them freedom to be efficient in their
different contexts.

Disclaimer: I HATE Common (Vulgar) Lisp. There are many worse things to 
complain about in it. In general, you need those type "declarations" (really
they're "promises") to get fast enough code.

By the way ... you, I, and most everyone else I know blames Steele for the
problems of VL. It's not *all* his fault, just because he edited The Book.
No single individual could make design a language *that* bad ...

Regards,
Kers                                |   "Why Lisp when you can speak Poperly?"