8 ms·
While this may seem absurdly naive, what is the CL condition system? Based on what I see (read) It seems like you need to know what it is before read the book.
by eismcc 6y ago
While this may seem absurdly naive, what is the CL condition system? Based on what I see (read) It seems like you need to know what it is before read the book.
- phoe-krk 6y agoLet me answer by posting an introduction to the condition system by Kent M. Pitman. It is the first subchapter of the book. ------ There have been many attempts to declare the Lisp family of languages dead, and yet it continues on in many forms. There are many explanations for this, but an obvious one is that it still contains ideas and features that aren't fully appreciated outside the Lisp community, and so it continues as both a refuge and an idea factory. Gradually, other languages see the light and these important features migrate to other languages. For example, the Lisp community used to be unusual for standing steadfastly by automatic memory management and garbage collection when many said it couldn't be trusted to be efficient or responsive. In the modern world, however, many languages now presume that automatic memory management is normal and natural, as if this had never been a controversy. So times change. But proper condition handling is something which other languages still have not figured out that they need. Java's try/catch and Python's try/except have indeed shown that these language appreciate the importance of representing exceptional situations as objects. However, in adopting these concepts, they have left out restarts --- a key piece of the puzzle. When you raise an exception in Python, or throw one in Java, you are still just performing an immediate and blind transfer of control to the innermost available handler. This leaves out the rich experience that Common Lisp offers to perform actual reasoning about where to return to. The Common Lisp condition system disconnects the ability to return to a particular place in the program from the necessity to do so, and adds the ability to "look before you leap." In other languages, if you create a possible place to return to, that is what will get used. There is no ability to say "If a certain kind of error happens, this might be a good place to return to, but I don't have a strong opinion ahead of time on whether or not it is definitely the right place." The Common Lisp condition system separates out three different activities: describing a problem, describing a possible solution, and selecting the right solution for the right problem. In other languages, describing a possible solution is the same as selecting that solution, so the set of things you can describe is necessarily less expansive. This matters, because in other languages such as Python or Java, by the time your program first notices a problem, it already will have "recovered" from it. The "except" or "catch" part of your "try" statement will have received control. There will have been no intervening time. To invoke the error handling process IS to transfer control. By the time any further application code is running, a stack unwind already will have happened. The dynamic context of the problem will be gone, and with it, any potential intervening options to resume operation at other points on the stack between the raising of the condition and the handling of an error. Any such opportunities to resume operation will have lost their chance to exist. "Well, too bad", these languages would say. "If they wanted a chance, they could have handled the error." But the thing is, a lot of the business of signaling and handling conditions is about the fact that you only have partial knowledge. The more uncertain information you are forced to supply, the more your system will make bad decisions. For best results, you want to be able to defer decisions until all information is available. Simple-minded exception systems are great if you know exactly how you want to handle things ahead of time. But if you don't know, then what are you to do? Common Lisp provides much better mechanisms for navigating this uncertain space than other languages do. So in Common Lisp you can say "I got an argument of the wrong type. Moreover, I know what I would do with an argument of the right type, I just don't happen to have one or know how to make one." Or you can say "Not only do I know what to do if I'm given an argument of the right type (even at runtime), but I even know how to store such a value so they won't hit this error over and over again." In other languages, if the program doesn't know this correctly-typed value, even if you (the user) do know it at runtime, you're simply stuck. In Common Lisp, you can specify the restart mechanism separately from the mechanism of choosing among possible restarts. Having this ability means that an outer part of the program can make the choice, or the choice can fall through to a human user to make. Of course, the human user might get tired of answering, but in such a case, they can wrap the program with advice that will save them from the need to answer. This is a much more flexible division of responsibility than other languages offer.
- eismcc 6y agoThanks! And wow this is cool.
- phoe-krk 6y agoTrivia: Kent M. Pitman (also known as kmp) is the father of the condition system as it exists nowadays. The code in the book is based on Portable Condition System - a library that I have created, and Portable Condition System itself is in turn based on the original implementation of the condition system available at http://www.nhplace.com/kent/CL/Revision-18.lisp http://www.nhplace.com/kent/CL/Revision-18.lisp After a wee bit of massaging that code to compile it on modern Lisp implemenations (the above code is CLtL1, which is an old version of Common Lisp from 1984), it still works!
- pierrebai 6y agoAm I allowed to think the described use case less than compelling? It's especially not compelling that the caller passed the wrong type, the called function would like a different type and somehow a different piece of code would know both end of the situation and fix it instead of the caller or callee. It all seems like an artificial and convoluted use case. Software design tend to know if they'd like to abort (throw) or report (callback) statically. Conditions may be general, but they seem to me to mostly allow unnecessary open-ended complex design. If the supposed gain is that a single system can do it all, I again don't feel it is a convincing argument. In fact, I tend to prefer a one-goal system, where different use case are easily differentiable because they are different. IOW, that throwing an exception, calling a callback, sending a signal or converting a value should look different is a plus. This is something I've noticed: one starts with a rigid design, then adds abstractions. But one reach a point over over-abstracting where the design becomes uncomprehensible because it is so generic that it becomes meaningless.
- wtetzner 6y agoIs this example a little better? http://www.gigamonkeys.com/book/beyond-exception-handling-conditions-and-restarts.html http://www.gigamonkeys.com/book/beyond-exception-handling-co...
- lonjil 6y agoIt is essentially an exception system, but more general and flexible. When you "throw an error", so to speak, rather than unwinding the stack until it finds a matching handler and then executing that, it looks at a list of handlers until it finds a match, and then calls it, right then and there. The handler can then run whatever code it wants, for example to unwind the stack, or it can return and let the search for a matching handler continue. It could also choose to invoke a restart. Restarts are basically code to handle a problem, but they don't catch any conditions. Instead, they can be invoked, usually from a condition handler. So you would have an error being signaled at the lowest level of your code, various recovery strategies defined at appropriate intermediate levels of code, and at the highest level of code you could have a condition handler defined which picks whichever restart is best for the high level situation. So a library author can provide many different restarts, signal errors very deep in the library, and then let the library user choose the recovery strategy that fits their requirements. If no matching handler is found, typically the debugger would be invoked, and when running with a suitable IDE like Emacs with Slime or Sly, a window with a stack trace will pop up. Here, if there were any available, restarts can be invoked directly by the programmer while they are debugging Finally, the condition system can be used to signal non-erroneous conditions, that can optionally be handled.