Re: how to compute

Steve Haflich <[email protected]> Tue, 16 May 2006 18:51:57 -0700
Newsgroups gmane.lisp.allegro
Message-ID <7668.1147830717@gemini>
   From: "Pierpaolo BERNARDI" <[email protected]>
   
   BTW, I think the following is a small bug in acl:
   
   CL-USER(153): 6042715942219502152353483497843569525253244555916134.0
   Error: This integer is too large to be converted to single float:
           343488630960564478300511837005615234375
      [condition type: SIMPLE-ERROR]
   
   (there's no integer in my code, and the value printed is bogus)
   
I'm curious why you think this is a bug, whether small or otherwise.
What did you expect to be the result of executing this form?  What do
you find wrong about the result?  That execution signaled error?  Or
that the error wasn't what you expected?

First, why do you think the integer value in the error message is
bogus?  It look likes the printed representation of a perfectly
reasonable integer.  (If that integer were truly bogus, then we would
be in danger of the sun stopping to shine and cracks appearing in the
sky. :-) Rather, you should have said that you don't understand where
that integer comes from.

When lisp execution signals an error and enters the debugger, the
intention is that you can use the debugger to find out that happened
and why.  It would be straightforward to wrap an error handler around
the read-eval-print loop such that any error signaled during
evaluation of a form would cause a straightforward "An error has
occurred."  message with no further information.  But surely this
would not be useful.

This is what I did after duplicating your error.  I've deleted some
binary characters from the stream input buffer to avoid confusing some
mail reading software.

  cl-user(12): 6042715942219502152353483497843569525253244555916134.0
  Error: This integer is too large to be converted to single float: 343488630960564478300511837005615234375
    [condition type: simple-error]

  Restart actions (select using :continue):
   0: Return to Top Level (an "abort" restart).
   1: Abort entirely from this (lisp) process.
  [1] cl-user(13): :zo :all t
  Evaluation stack:

  ... 4 more newer frames ...

     (excl::make-float
	#("6042715942219502152353483497843569525253244555916134.0 <binary text suppressed here>"
	  512 54 ...))
     (excl::read-token #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a> #\6)
     (excl::read2 #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a> t ...)
     (excl::read1 #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a> t ...)
   ->(read-preserving-whitespace #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a>)
     (tpl::read-top-level-command #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a>)
     (tpl::read-eval-print-one-command nil nil)
     (excl::read-eval-print-loop :level 0)
     (tpl::top-level-read-eval-print-loop1)

  ... more older frames ...
  [1] cl-user(14): :up 4
  Evaluation stack:

     (excl::internal-invoke-debugger "Error" #<simple-error @ #x71cc407a> ...)
     (error simple-error :format-control ...)
     (excl::.error "This integer is too large to be converted ~
			to single float: ~s" 343488630960564478300511837005615234375)
     (excl::integer-to-single-float 343488630960564478300511837005615234375)
   ->(excl::make-float
	#("6042715942219502152353483497843569525253244555916134.0 <binary text suppressed here>"
	  512 54 ...))
     (excl::read-token #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a> #\6)
     (excl::read2 #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a> t ...)
     (excl::read1 #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a> t ...)
     (read-preserving-whitespace #<terminal-simple-stream [initial terminal io] fd 0/1 @ #x71120c6a>)

  ... more older frames ...
  [1] cl-user(15): 

As you can see, the execution of make-float is indeed trying to coerce
that integer you found "bogus" into a float.  That is the immediate
error the code encountered, so that is what it is reporting to you.

It would be impossible to try find _all_ the places in the
implementation where an error might be encountered -- it is provably
impossible -- and wrap a restart around each point there user code
might call implementation code in order to report the error at the
point that user code called the implementation code.  This would hide
from the developer's delicate eyes the internal working of the code,
but it would also make debugging impossible in many cases.  For
example, suppose compile-file did the same thing, and when an error
occurs during compilation all the compiler tells you is would be "An
error occurred during the compilation of file foo.cl."  In addition,
wrapping these error handlers around every entry from user code to to
system code would impose significant overhead.

Lisp culture makes a debugger available so you, a code developer, can
use it.  The implementation was indeed trying to convert that "bogus"
integer to a float because that was what it needed to do in the
reader' algorithm for translating character sequences into floats.
You should be able to figure that out from the backtrace, including
the functions named read-token and make-float.  The debugger is there
because having it available (instead of "An error has occurred" or
"Core dumped") makes it easier and efficient for you to determine the
cause of an error.

As both a developer and user of ACL, I would not want to wrap an error
handler around make-float (or whatever) in order to be able to produce
a more explicit error message for an out-of-range float because I want
the reader to operate as fast as possible.  There is essentially
nothing gained by trying to create an error-signaling boundary at the
point user code calls implementation code, and a lot is lost if
developers and users cannot see the details of what the
implementation is trying to do.