From: Gail Zacharias
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <233@spt.entity.com>
Common Lisp does provide a number of ways to portably request type checking
at run time, such as CHECK-TYPE and ASSERT, etc.  But it doesn't specify the
behavior of incorrect programs (such as programs in which declarations are
false).  Basically, the debugging environment is up to the implementation.  I
don't think that's a major shortcoming of the Common Lisp standard.  The
important thing is that once your program is debugged, it should run in any
Common Lisp implementation.

(Btw, if by Allegro Common Lisp you meant the Macintosh one, i.e. Coral
Common Lisp, then here's a hint: turn off *compile-definitions*!  The CCL
evaluator does indeed signal an error on incorrect THE forms.  The reason you
didn't get an error in your example is that TST was running compiled.)

-------
·············@eddie.mit.edu	  ··@entity.com		{backbone}!spt!gz

From: Ross Miller
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <2126@ulowell.cs.ulowell.edu>
In article <···@spt.entity.com> ··@spt.entity.com (Gail Zacharias) writes:
>Common Lisp does provide a number of ways to portably request type checking
>at run time, such as CHECK-TYPE and ASSERT, etc.  But it doesn't specify the
>behavior of incorrect programs (such as programs in which declarations are
>false).  Basically, the debugging environment is up to the implementation.  I
>don't think that's a major shortcoming of the Common Lisp standard.  The
>important thing is that once your program is debugged, it should run in any
>Common Lisp implementation.

Wrong.  Crreeeeaaaak, sound of Common lisp tomb being opened yet again, I
have read and read, and reread that section looking for a way out.  An
implementation is free to ignore type checking and not return any errors,
but it must except the code that declares type checking.  That is not a
quote, but it is the jist.  Here is a case where a program could be perfectly
debugged and still fail.
	What if we had an implemenation of GKS for lisp.  This is being worked
on by X3H3.4 of ANSI.  The lisp is actually an interface to another language
that the GKS is really written in.  The GKS is perfect passes all the test
suites etc.  But now an application programmer sits down to actually use
this beast.  By accident he sends a float to polyline when an integer
was expected.  Lisp then passes the 32bit word down to say C, machine size
may vary, and C blithly trys to write out a few million polylines, or some
other random number or worse a negative array reference, and the OS 
informs us of an array overflow.  Please keep in mind the actual error
could vary greatly depending on what the final GKS spec looks like and
what the implentation actually does but you get the idea.
	If the GKS is actually implemented in lisp, then lisp will return
an error eventually from such garbage being passed to it, and again the
applications programmer is going to have to intuitivly figure out what
is wrong.  Worse, nothing is wrong the GKS is perfect only his program is
wrong but he will get errors unrelated to what is wrong because data with
garbage types will be being passed around.
	In fact the resolution of the committee was garbage in garbage out.
An implentation is free to check the types manually upon invokation of
the function but is not required to do so.  This was resolved so that
code could continue to be portable across GKS applications in different
lisps.
	On another subject have I missed the argument on why arrays are not 
always passed by value?

								Ross




-- 
csnet: ····@ulowell.cs.ulowell.edu
uucp:  ····@ulowell.cs.ulowell.edu || ...harvard!ulowell!ross

Trust the computer.	The computer is your friend.
From: Cesar Quiroz
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <5208@sol.ARPA>
In article <····@ulowell.cs.ulowell.edu>, Ross Miller offers to show
an example of a `debugged' program that stills fails.  I emphasized
`debugged', because that wasn't the issue.  Here the problem is
whether the program is correct or not, not whether it has been
debugged, whatever that means.  Miller's program was in error, so
his objection is moot. (I hope I am not quoting his posting out of
context due to my heavy editing):

: ... Here is a case where a program could be perfectly
:debugged and still fail.
:	What if we had an implemenation of GKS for lisp.  ...
:...  The GKS is perfect passes all the test suites etc. ...
:By accident he sends a float to polyline when an integer
:was expected...

The scenario involves at least this incorrection.  Then, the program
is not correct, never mind how energetically debugged.  Never mind
CL does not specify how to pass things to a C program, etc.  These
latter questions are of the highest practical importance, see below,
but shouldn't cloud our judgement as to the fact that the program
was in error and whatever happens was deserved.)

:	If the GKS is actually implemented in lisp, then lisp will return
:an error eventually from such garbage being passed to it, and again the
:applications programmer is going to have to intuitivly figure out what
:is wrong.  Worse, nothing is wrong the GKS is perfect only his program is
:wrong but he will get errors unrelated to what is wrong because data with
:garbage types will be being passed around.

I feel reasonable sympathy for such programmer.  It is still true
that `only his program is wrong'.  And that is all that is needed to
render the objection moot.

On the issue of interfacing with other languages, I think it is
clear there is no way to legislate a solution.  Good ideas should be
tried, in the hopes that almost de-facto standards for specific
combinations of languages and architectures eventually emerge.  If
Lispers want to carve a nice niche for their favorite language in
the numeric community, such interfaces will be needed.  (But CL
already has a better defined arithmetic than many other languages,
just improving the Lisp compilers might be a better idea.  Burn
those dusty decks :-)


-- 
Cesar Augusto  Quiroz Gonzalez
Department of Computer Science     ...allegra!rochester!quiroz
University of Rochester            or
Rochester,  NY 14627               ······@cs.rochester.edu
From: Ritchey Ruff
Subject: Correctness (was Re: Common Lisp lacks portability)
Date: 
Message-ID: <1547@orstcs.CS.ORST.EDU>
I think I see the basic point of dissent in this discussion (but when
I posted the original I never thought it would come to this ;-).

The main difference in opinion seems to be what we "feel" the definition
of "A CORRECT PROGRAM" is, right?

I tend to come from a software engineering viewpoint, so I'll make my
bast stab at it -

	A correct program is one that -
		- has a specification of correct behavour for both
		  correct *and* *incorrect* input;
		- will give the correct output for *ANY* possible input
		  (using above specifiaction for validation).

This means -
	(1) common lisp IS correct (it is following its definition ;-), but
	(2) it makes it VERY hard for programmers to write "portable"
	    correct code because Steele et.al. underspecified the
	    definition of the language.  You are FORCED to either use
	    a subset of the whole language or validate it on every
	    CL implementation  (and even version) you will run it on.

This get right back to my original conclusion - *IF* you follow
my definition of "correct", *AND* you want to have "portable" code,
YOU CAN'T USE STATEMENTS THAT EFFECT THE SEMANTICS OF THE PROGRAM 
BUT THAT CAN BE IGNORED because then (by definition) you will not have
a program that you can be sure is "correct" when running under CL
implementations that you have not validated it on.  *This* was my
original gripe!

Comments? (Just a sec while I don my welding goggles and gloves and
	   my aspestos suit ;-)

--ritchey ruff			········@cs.orst.edu -or-
"Lisp is the best way to	····················@relay.cs.net -or-
 abuse a computer." -anon.	{ hp-pcd | tektronix }!orstcs!ruffwork
From: Andy Freeman
Subject: Re: Correctness (was Re: Common Lisp lacks portability)
Date: 
Message-ID: <859@rocky.STANFORD.EDU>
In article <····@orstcs.CS.ORST.EDU> ········@CS.ORST.EDU (Ritchey Ruff) writes:
>I tend to come from a software engineering viewpoint, so I'll make my
>bast stab at it -

>	A correct program is one that -
>		- has a specification of correct behavour for both
>		  correct *and* *incorrect* input;
>		- will give the correct output for *ANY* possible input
>		  (using above specifiaction for validation).

>This means -
>	(1) common lisp IS correct (it is following its definition ;-), but
>	(2) it makes it VERY hard for programmers to write "portable"
>	    correct code because Steele et.al. underspecified the
>	    definition of the language.  You are FORCED to either use
>	    a subset of the whole language or validate it on every
>	    CL implementation  (and even version) you will run it on.

(2) is false.  Ruff's program was incorrect by his definition.

Others have covered Ruff's misunderstanding of what common lisp
declarations are.  His (unstated) specification required code
that he didn't write; I'll sketch an appropriate PORTABLE defintion.

The original program was something like

(defun silly (a b)
  (declare (integer a b))
  (loop i from a to b do (print i)))

Silly does not handle illegal input - its definition promises that
its input is well-formed.  Safe-silly handles illegal input.

(defun safe-silly (a b)
  <Put code here that tests whether the input is legal and takes
   appropriate action if it isn't.  Note that competent CL programmers
   know how to return a value from safe-silly without executing the
   remainder of this function.>
  (let ((a a) (b b))
    (declare (integer a b))
    (loop i from a to b do (print i))))

[Insert some sarcastic comments here.]

This is the same sort of thing one must do in every language.
For example, one must test input to pascal programs.  [I don't
feel like explaining this so insert more sarcasm here.]

-andy
-- 
Andy Freeman
UUCP:  {arpa gateways, decwrl, sun, hplabs, rutgers}!sushi.stanford.edu!andy
ARPA:  ····@sushi.stanford.edu
(415) 329-1718/723-3088 home/cubicle
From: Barry Margolin
Subject: Re: Correctness (was Re: Common Lisp lacks portability)
Date: 
Message-ID: <13975@think.UUCP>
In article <···@rocky.STANFORD.EDU> ····@rocky.UUCP (Andy Freeman) writes:
>The original program was something like
>
>(defun silly (a b)
>  (declare (integer a b))
>  (loop i from a to b do (print i)))

Actually, I think he said that the program was something like

(defun silly (a b)
  (sloop for i from a to b do (print i)))

and the SLOOP macro expands into code that contains somwething like
(declare (integer i a b)), but it doesn't check whether A and B
actually are integers at runtime.

Something is incorrect here, the question is whether it is SILLY or
SLOOP, and it depends on SLOOP's documentation.  If the documentation
for the FROM/TO keyword says "the arguments must evaluate to integers"
then it becomes SILLY's responsibility to check its arguments.  If the
documentation doesn't say this then SLOOP should include type-checking
code in its expansion or should expand into code that doesn't assume a
particular type.

>Silly does not handle illegal input - its definition promises that
>its input is well-formed.  Safe-silly handles illegal input.
[omitted]
>This is the same sort of thing one must do in every language.
>For example, one must test input to pascal programs.  [I don't
>feel like explaining this so insert more sarcasm here.]

Well, yes and no.  In traditional Algol-derived languages the compiler
will not let you pass incorrect data types.  The type of all
expressions can be determined at compile time, the types of arguments
expected by subroutines are declared, so argument type checking can be
done.  You can't execute a Pascal program in which a floating point
value is passed to a routine expecting an integer.

If you have argument constraints that go beyond what the language's
type grammar allows you to specify (for example, if a routine requires
that its argument be an even integer) then you are correct that the
routine must do its own input checking.  However, since the type
specification doesn't let you say this, it is not a case of a
redundant check.


---
Barry Margolin
Thinking Machines Corp.

······@think.com
seismo!think!barmar
From: John Diamant
Subject: Re: Correctness (was Re: Common Lisp lacks portability)
Date: 
Message-ID: <6950004@hpfclp.HP.COM>
> (defun silly (a b)
>   (declare (integer a b))
>   (loop i from a to b do (print i)))
> 
> Silly does not handle illegal input - its definition promises that
> its input is well-formed.  Safe-silly handles illegal input.

I agree with your example about safe-silly versus silly, but I'd like
to point out that safe-silly needn't be as ugly as you wrote in your
example.  Below your example, see a complete, correct implementation
of safe-silly that doesn't require that bizarre (though quite correct)
let.  Note, that I am not attempting to criticize your understanding
of Common Lisp -- you clearly understand it.  I only wish to point out the
the safe program can be very clean (more so than in your example).
> 
> (defun safe-silly (a b)
>   <Put code here that tests whether the input is legal and takes
>    appropriate action if it isn't.  Note that competent CL programmers
>    know how to return a value from safe-silly without executing the
>    remainder of this function.>
>   (let ((a a) (b b))
>     (declare (integer a b))
>     (loop i from a to b do (print i))))

(defun safe-silly (a b)
	(check-type a integer)
	(check-type b integer)
	(loop i from (the integer a) to (the integer b) do (print i)))

Note that check-type is part of CL and provides an optional string
argument to provide your own error message, and that with the use of the
special form "the," no extra storage is needed.  Clearly, in this example,
the efficiency isn't that significant, but in heavy calculations, it may
well make a big difference.  In a much larger main body, the use of the let
as above may well be worth it (if a and b appear several times).


John Diamant			UUCP:  {hplabs,hpfcla}!hpfclp!diamant
Hewlett Packard Co.		ARPA Internet: ··············@hplabs.HP.COM
Fort Collins, CO
From: Stanley T. Shebs
Subject: Re: Correctness (was Re: Common Lisp lacks portability)
Date: 
Message-ID: <5179X@utah-cs.UUCP>
In article <····@orstcs.CS.ORST.EDU> ········@CS.ORST.EDU (Ritchey Ruff) writes:

>	A correct program is one that -
>		- has a specification of correct behavour for both
>		  correct *and* *incorrect* input;
>		- will give the correct output for *ANY* possible input
>		  (using above specifiaction for validation).
>
>This means -
>	(1) common lisp IS correct (it is following its definition ;-), but
>	(2) it makes it VERY hard for programmers to write "portable"
>	    correct code because Steele et.al. underspecified the
>	    definition of the language.  You are FORCED to either use
>	    a subset of the whole language or validate it on every
>	    CL implementation  (and even version) you will run it on.
>
>This get right back to my original conclusion - *IF* you follow
>my definition of "correct", *AND* you want to have "portable" code,
>YOU CAN'T USE STATEMENTS THAT EFFECT THE SEMANTICS OF THE PROGRAM 
>BUT THAT CAN BE IGNORED because then (by definition) you will not have
>a program that you can be sure is "correct" when running under CL
>implementations that you have not validated it on.  *This* was my
>original gripe!

In other words, you want a language definition that requires all
implementations to detect mistakes in the program.  Presumably you're
going to be generous and not require that implementations detect
infinite loops that are due, say, to misuse of counters...  Even
given that,  there are other situations, such as memory exhaustion,
that a system is unlikely to deal with gracefully.  Getting back to
type declarations, it's surely unreasonable to expect a Common Lisp
system to take an expression like

	(the fixnum (+ (the fixnum x) (the fixnum y))

and analyze all the possible values for x and y to make sure that their
sum doesn't exceed the range of fixnums.  The only truly safe choice for
the compiler is to not opencode the addition, but of course that defeats
the whole purpose of declarations.  Instead, the CL spec says that this
sort of thing "is an error", and implementations are free to do anything
up to and including the erasure of your home directory :-) if the program
causes such an error.  The alternative is Lisp system performance that you
would not like at all...

Lower-level languages like Pascal can be more portable because they are
more restrictive and can therefore be statically checked better.

I'd say that although you do have something to gripe about, it comes with
the territory, and you should plan to acquire lots of CL implementations
if you want to write portable code... 1/2 :-)
From: Alex S. Crain
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <640@umbc3.UMD.EDU>
In article <····@ulowell.cs.ulowell.edu> ····@swan.cs.ulowell.edu (Ross Miller) writes:
>	What if we had an implemenation of GKS for lisp.

  [much deleted about how programs that use incorrect data give poor results]

[Lessee, I think I got a match here somewhare...there we go]
I think that the problem here is that the wrong language is being used. Might
I suggest VAX/VMS Pascal? VAX Pascal offers a multitude of idiot-proofing
schemes to protect incompetant programmers from themselves, includeing run
time bounds checking and full checking of types, use checking of variables,
etc. True, all that extra work causes the code to run at about 1/2 speed at
best, but it seems to supply what you want.

	I play consultant at the first-aide desk in the computer center
a few hours a week, for the sake of the distraction, and I get mutitudes
of people (more seniors than I would like) with the attitude that the 
language is responsibe for detection of programmer stupidity. My answer
to them is the same as the one above. If you can't hack working without
a net, get a net and suffer the consiquences of poor run time performance
and code restriction. But don't blame the language for your mistakes.

[flame off]

	There is a valid point here though, in that it is in general difficult
to find obscure semantic errors in an interpreted environment. I was thinking
is what I really want is lint for lisp. I was tracing through some code (mine)
recently and found..

	(prog						(progn
	   (arf narf snarf)      as opposed to		   (arf narf snarf)
		...						...
	   )						    )

which didn't cause major problems, but the variable scoping was wrong and
(arf ...) was never evaled. I would have rather had something major.

	I would guess that lint for lisp wouldn't be too far fetched,
a utility that would complain about unused variables and wrong # of arguments,
etc. My compiler does this but that is so much overhead that its a bit
extreme. Has anyone ever seen such an animal? Realizing that it would
have to be tuned for each dialect, source for such a thing in any form that
could be modified for use with CL would certainly be a help.

					:alex.


····@umbc3.umd.edu
From: Rob MacLachlan
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <523@PT.CS.CMU.EDU>
>Wrong.  Crreeeeaaaak, sound of Common lisp tomb being opened yet again,

Eeeeee-hah!  What fun!  Even MMister JJacobs has crawled back on the net, 
dragging his odious slime-trail behind him.  But I won't lower myself by
responding to his message.  Instead I will flame about compilers and
declarations in Common Lisp, which Common Lisp fans know is one of my
favorite topics.

First of all, I point out that Common Lisp is a standard for writing
portable programs.  It is possible to write programs that run in particular
Common Lisp implementation, yet are not Common Lisp programs.

The declaration mechanism in Common Lisp provides a way to make many
interesting assertions about a program.   As a special case, it allows
programmers to make untrue assertions.

There are a number of areas in which "Common Lisp the Langauge" is vague
about what constitutes a correct Common Lisp program, but the aspect of type
declarations currently under discussion is not one of them.

I think the real complaint here is:
  "Common Lisp has features that support unsafe (and efficient) compilation."

This is true, but it should be up to the programmer to decide whether he
wants to risk unsafe compilation.  This is why Common Lisp proves the
OPTIMIZE declaration -- to allow the programmer to tell the compiler how to
evaluate speed/space/safety/compilation-speed tradeoffs.

In the abstract, the Common Lisp OPTIMIZE declaration provides better
control over these tradeoffs than any other Lisp dialect I know of.
Unfortunately, as realized by existing implementations, this capability is
largely lacking.

The most unfortunate property of existing Common Lisp compilers is their
assumption that a type declaration implies the generation of unsafe code.
There is nothing in Common Lisp that suggests this: it is merely an evil 
vestiage of traditional Lisp compilation.  I believe that a Common Lisp
compiler should have some mode in which it actually emits extra code to
verify all type declarations.  This is a policy decision, controlled by the
OPTIMIZE declaration, and not an issue of language semantics.

Even without full type checking, the Common Lisp programmer is no worse off
than the programmer in any other dialect.  He can avoid the risk of
incorrect type assertions by not making any.

The real reason that people flame about Common Lisp portability is a
paradoxical one: Common Lisp is the first Lisp dialect that has been
implemented many different times.  People move their "Common Lisp" programs
from one implementation to another, expecting them to run without a hitch.
When they hit a snag, they snivel and whine.  They never had this problem
with XYZZYLisp (of course, it only ran on one machine).

I won't argue that it is impossible (or even difficult) to come up with a
Lisp dialect that makes it harder to write non-portable code.  Type
declarations are an obvious source of non-portability; they were included in
Common Lisp because efficiency was also a major goal.  

If anyone has suggestions for ways to make Common Lisp more portable without
serious adverse effects on other design goals, then we would be glad to hear
them.  It is not acceptable to either require declarations to be checked or
to forbid declarations, since both would cause serious efficiency problems.

Common Lisp can strongly suggest that the compiler offer a mode which does
full type checking, but it would be inconsistent with the language design
philosophy to require it.  In Common Lisp terms, this is an "environment
issue".  A given implementation can do whatever it wants to help programmers
write correct programs, but once written, these programs should run in an
environment that implmements only the features described in the manual.

    Rob MacLachlan (···@c.cs.cmu.edu)
    CMU Common Lisp  --  Making the world safe for symbolic computing.
From: Jeff Dalton
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <216@aiva.ed.ac.uk>
In article <····@ulowell.cs.ulowell.edu> ····@swan.cs.ulowell.edu (Ross Miller) writes:
>An implementation is free to ignore type checking and not return any errors,
>but it must except the code that declares type checking.  That is not a
>quote, but it is the jist.  Here is a case where a program could be perfectly
>debugged and still fail.

Here is a way to think about type checking in Common Lisp:

 * Assume there is no type checking unless you explicitly code it
   by writing calls to CHECK-TYPE or your own tests and error calls.
   This assumption may well be correct for compiled code in some
   implementations.

   Note that CHECK-TYPE is a way to signal an error, not a declaration.
   An implementation is not free to ignore it.

 * Write your code with enough explicit checks so that users cannot
   confuse it with incorrect data.  Use any additional internal checks
   that you feel are needed.

   Here I am assuming that only certain routines will be part of the
   external interface.  You can enforce this by using packages (yes, I
   know one *can* still call internal procedures) or by using FLET
   and LABELS to keep internal routines local.
 
 * In cases where you are sure the types are correct, and where the
   speed of the compiled code is important, add declarations to inform
   the compiler of the types involved.  It may then generate type-specific
   but more efficient code.

   Since you have actually checked the types somewhere, and have done
   a bit of type inference, you can be confient that the declarations
   are safe.

Code of this sort will be portable.

>On another subject have I missed the argument on why arrays are not 
>always passed by value?

Are they sometimes not passed by value?  Note that in Lisp objects,
such as arrays, aren't copied when passed as parameters: in another
language, they would be pointers.

Jeff Dalton,                      JANET: ········@uk.ac.ed             
AI Applications Institute,        ARPA:  ·················@nss.cs.ucl.ac.uk
Edinburgh University.             UUCP:  ...!ukc!ed.ac.uk!J.Dalton
From: Robert Stanley
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <2004@cognos.UUCP>
In article <····@ulowell.cs.ulowell.edu> ····@swan.cs.ulowell.edu
	   (Ross Miller) writes:

>Wrong.  Crreeeeaaaak, sound of Common lisp tomb being opened yet again, I
>have read and read, and reread that section looking for a way out.  An
>implementation is free to ignore type checking and not return any errors,
>but it must except the code that declares type checking.  That is not a
             ^  ^
	     |  `-  EXCEPT, meaning make an exception == not accept?
	     `----  ACCEPT, indicating text is a misprint?
>quote, but it is the jist.  Here is a case where a program could be perfectly
>debugged and still fail.

Sorry, it's Christmas eve, I'm waiting for the compiler guys to finish printing
86 separate source files, and I read the above statement several times before
admitting that I couldn't discriminate.
>-- 
>csnet: ····@ulowell.cs.ulowell.edu
>uucp:  ····@ulowell.cs.ulowell.edu || ...harvard!ulowell!ross

>Trust the computer.	The computer is your friend.
Yah, computers never fai
-- 
R.A. Stanley  - ·······@cognos.uucp
uucp: decvax!utzoo!dciem!nrcaer!cognos!roberts       Compuserve: 76174,3024
baud, bawd, bard, bared, bored, bore, bode, bade, bare, bar, boar, board
intelligence at 1200 bps!
From: Stanley T. Shebs
Subject: Re: Common Lisp lacks portability
Date: 
Message-ID: <5173X@utah-cs.UUCP>
In article <····@ulowell.cs.ulowell.edu> ····@swan.cs.ulowell.edu (Ross Miller) writes:

>[...] By accident he sends a float to polyline when an integer
>was expected.  Lisp then passes the 32bit word down to say C, machine size
>may vary, and C blithly trys to write out a few million polylines, or some
>other random number or worse a negative array reference, and the OS 
>informs us of an array overflow. [...]

If anybody is surprised by all this, mail me and I'll send you a catalog
of palaces in England I've been handling.

There has been talk of doing "safe" interfaces between Lisp and C, but as
long as I can do *(12345) in the address space of my Lisp system, nothing
is safe.  I can get a little help by using an interface that checks types,
but it's going to be a dog, no way around it.

>	On another subject have I missed the argument on why arrays are not 
>always passed by value?

Oh yeah, I like making copies of million-byte arrays every time I pass them
to a function.  Just think, I would get a copy with every call to AREF!
That would show those purely functional weenies what *real* storage allocation
is like!  :-) :-)

							stan shebs
							·····@cs.utah.edu