From: Vassil Nikolov
Subject: Summing up: when type mismatch can be legal
Date:
Message-ID: <76350.vnikolov@math.acad.bg>
Dear Readers,
In a previous article, I asked:
Is the compiler justified in refusing to compile
(declare (number x))
(if (numberp x) (1+ x) (cdr x))
because of the apparent application of CDR to a non-cons?
The answer seems to be negative; a warning may be fine,
but not an error. I thank Barry Margolin for his explanation.
(Somewhat to my dismay, this issue was linked to the
halting problem by a subsequent post.)
Please note that without the declaration there would
be nothing to discuss. A more realistic situation
would be one where the declaration comes from one
part of the program and the branching statement
from another part, possibly from a macro, so
perhaps I should explain how the question arose.
A friend had a problem running DEFSYSTEM. (I have
summed up his description below.) While he easily
fixed it, I began wondering which was the culprit.
Apparently, the compiler is to blame, but now
I wish the description of the Common Lisp language
was a little more explicit on this point.
(Of course, I wouldn't really insist on that,
since a language description cannot possibly
be explicit in all respects.)
Best regards,
Vassil.
- - - - -
DEFSYSTEM ver. Mar-95
CMU CL ver. 17f (SunOS 5.4)
The source contains the following definition:
(defsetf component-load-time (component) (value)
`(when ,component
(etypecase ,component
(string ...)
(pathname ...)
(component
(ecase (component-type ,component)
(:defsystem ...)
((:file :private-file) ...) )))
,value))
and, later on:
(defun find-system ...
...
(setf (component-load-time path) (file-write-date path))
...)
Now the PATH variable here is known at compile time to be
a pathname and therefore unsuitable as an argument to
COMPONENT-TYPE (in the ECASE form above). So the compiler
objects, although that branch of the ETYPECASE would never
be executed to begin with,---compiling the above produces:
In: DEFUN FIND-SYSTEM
(SETF (COMPONENT-LOAD-TIME PATH) (FILE-WRITE-DATE PATH))
--> LET* MULTIPLE-VALUE-BIND LET WHEN COND IF PROGN ETYPECASE LET COND IF COND
--> IF COND IF PROGN ECASE LET COMPONENT-TYPE
==>
#:G8
Warning: Result is a PATHNAME, not a COMPONENT.
Here #:G8 comes from the macroexpansion
(SETF (COMPONENT-LOAD-TIME PATH) ...) ->
(LET* ((#:G8 PATH))
...
(ETYPECASE #:G8
(STRING ...)
(PATHNAME ...)
(COMPONENT (ECASE (COMPONENT-TYPE #:G8) ...) ...) ...))
The compiler detects type inconsistency and does not compile
the form. (It substitutes it with a stub that calls ERROR at
runtime instead.)
(An obvious remedy that worked was to define a function
whose body was the body of the long form of DEFSETF, and
then use the short form of DEFSETF with the name of the
function.)
- - - - -
Vassil Nikolov <········@bgearn.acad.bg> (+359-2) 713-3813
Department of Information Research
Institute of Mathematics and Informatics fax: (+359-2) 9713649
Acad. G. Bonchev, block 8, Sofia 1113, Bulgaria
>>>>> "Vassil" == Vassil Nikolov <········@math.acad.bg> writes:
Vassil> DEFSYSTEM ver. Mar-95
Vassil> CMU CL ver. 17f (SunOS 5.4)
[snip]
Vassil> In: DEFUN FIND-SYSTEM
Vassil> (SETF (COMPONENT-LOAD-TIME PATH) (FILE-WRITE-DATE PATH))
--> LET* MULTIPLE-VALUE-BIND LET WHEN COND IF PROGN ETYPECASE LET COND IF COND
--> IF COND IF PROGN ECASE LET COMPONENT-TYPE
Vassil> ==>
Vassil> #:G8
Vassil> Warning: Result is a PATHNAME, not a COMPONENT.
Vassil> Here #:G8 comes from the macroexpansion
Vassil> (SETF (COMPONENT-LOAD-TIME PATH) ...) ->
Vassil> (LET* ((#:G8 PATH))
Vassil> ...
Vassil> (ETYPECASE #:G8
Vassil> (STRING ...)
Vassil> (PATHNAME ...)
Vassil> (COMPONENT (ECASE (COMPONENT-TYPE #:G8) ...) ...) ...))
Vassil> The compiler detects type inconsistency and does not compile
Vassil> the form. (It substitutes it with a stub that calls ERROR at
Vassil> runtime instead.)
Why is this a problem? As you state above, and the compiler warns,
PATH is a PATHNAME at this point, so the COMPONENT part of etypecase
would never be executed. So the compiler could have put
(blow-up-my-computer) for the COMPONENT case and you couldn't tell at
run time. (Assuming an error-free compiler, of course!)
Of course, it seems the compiler is a bit deficient since it could
have replaced all of the code for the etypecase with just the
code for the PATHNAME part.
Ray
From: Barry Margolin
Subject: Re: Summing up: when type mismatch can be legal
Date:
Message-ID: <5v3itk$kq8@tools.bbnplanet.com>
In article <··············@rtp.ericsson.se>,
Raymond Toy <···@rtp.ericsson.se> wrote:
>Why is this a problem? As you state above, and the compiler warns,
>PATH is a PATHNAME at this point, so the COMPONENT part of etypecase
>would never be executed. So the compiler could have put
>(blow-up-my-computer) for the COMPONENT case and you couldn't tell at
>run time. (Assuming an error-free compiler, of course!)
I think you're misunderstanding which form got replaced with the stub.
Judging from the original post in the thread, I believe it's the entire
ETYPECASE or LET that's being replaced, not just the COMPONENT clause of
the ETYPECASE. And that's the whole problem -- the compiler detected a
type mismatch, but doesn't recognize the guards surrounding it.
--
Barry Margolin, ······@bbnplanet.com
GTE Internetworking, Powered by BBN, Cambridge, MA
Support the anti-spam movement; see <http://www.cauce.org/>
Please don't send technical questions directly to me, post them to newsgroups.
>>>>> "Barry" == Barry Margolin <······@bbnplanet.com> writes:
Barry> In article <··············@rtp.ericsson.se>,
Barry> Raymond Toy <···@rtp.ericsson.se> wrote:
>> Why is this a problem? As you state above, and the compiler warns,
>> PATH is a PATHNAME at this point, so the COMPONENT part of etypecase
>> would never be executed. So the compiler could have put
>> (blow-up-my-computer) for the COMPONENT case and you couldn't tell at
>> run time. (Assuming an error-free compiler, of course!)
Barry> I think you're misunderstanding which form got replaced with the stub.
Barry> Judging from the original post in the thread, I believe it's the entire
Barry> ETYPECASE or LET that's being replaced, not just the COMPONENT clause of
Barry> the ETYPECASE. And that's the whole problem -- the compiler detected a
Barry> type mismatch, but doesn't recognize the guards surrounding it.
If that is true, then that is definitely a bug in CMUCL.
However, I've been running this defsystem for quite a while and, while
I have seen the warnings mentioned above, I have not noticed any thing
broken. A short test with some print statements around the offending
code shows that the etypecase or let is not replaced by error; it
works as expected.
Perhaps a newer version of CMUCL will help. I did the test with an
almost but not quite 18a release of CMUCL.
Ray