Re: small issue in get-multipart-header
Steve Haflich <[email protected]> Wed, 22 Feb 2006 15:02:14 -0800
| Newsgroups | gmane.lisp.web |
|---|---|
| Message-ID | <12530.1140649334@bach> |
From: Kamen TOMOV <[email protected]> Now that mention it, I wonder what is the proper way to find out what kind of signals throws a particular black-boxed function without studying its code? Well, only documentation and source reading can reveal what the code _might_ signal, but you can easily see what it actually does signal on any particular execution. You can't do it with handler-case because when a handler-case clause is executed it has already thrown out of the protected code body. (See the ANS pages for handler-case and handler-bind where is this explained pretty well). But you can examine signals promiscuously using handler-bind, provided your handler(s) don't actually "handle" the signals by making a nonlocal exit. Here's a minimal demonstration: cl-user(40): (handler-bind ((t #'describe)) (warn "Pie") pi) #<simple-warning @ #x1001f0e172> is an instance of #<standard-class simple-warning>: The following slots have :instance allocation: format-control "~1@<Pie~:@>" format-arguments nil plist nil #<excl::advance-warning @ #x1000258f92> is an instance of #<standard-class excl::advance-warning>: The following slots have :instance allocation: format-control <unbound> format-arguments nil plist nil Warning: Pie 3.141592653589793d0 cl-user(41): For example can I find out (with programming means) what kind of signals this form (get-multipart-header req) can throw? You've missed the point entirely! It is none of your business whether some body of code signals any conditions that are disjoint with the documented set of condition classes (error, warn, any implementration extensions) because they are the implementation's machinery. In some fanciful implementation the cdr function might compute addresses using floating point arithmetic. That's why you are not allowed to redefine or overload internal implementation functions. Similarly, you are not allowed to mess with unexported condition classes. You have good reason for wanting to know the full set of subclasses of the cl:error condition, and perhaps also cl:warning. (Some people might consider the required transitive specification of exceptions in Java code a positive feature of the language. Or perhaps not, but it does seem to make Java programmers more sensitive to considering and classifying exceptions while we Lisp programmers seem to do it only as a casual afterthought.) But if you need to know, or even think you need to know, about other condition classes that are disjoint from these, and not a documented part of siome subprogram interface, then something is wrong. You may have noticed the excl::advance-warning condition signalled above. The cl:warn in ACL first signals the normal warning, and if no one handles it (typically with muffle-warning) it signals an excl::advance-warning condition. Programs like the file compiler use this to print those nice "While compiling function foo in file bar" messages without having to print functions that geenrate no warnings, and without the wasting stream real estate if multiple warnings occur within a single function. There is a handler bind around the file compiler suppressing the "While compiling" message if the file and function are the same as the previous announcemen. The point of this condition class is that since it is disjoint from all documented condition classes except condition itself, no other code should ever notice it (because signal of an unhandled condition class is a nop) and certainly no other code should handle it. There is no need to document that this machinery is being used by the compiler any more than it is necessary to document whether the compiler uses bit vectors. As for get-multipart-header, it probably signals a variety of error subclasses. Do you need to categorize them further? For that you might need to read the code, and even so, specific errors signalled by routines called by that code could still be missed. This is one aspect of Java that is arguably superior, although in practice most code just handles generic errors by transfering to some outer restart point.