-- http://parenteses.org/mario
-- You received this message because you are subscribed to the Google Groups "Lisp-br" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/lisp-br?hl=en.
--- Begin Message ---Dear Fans, after a two week resting phase I am proud to give you issue 18. Thanks to Moritz for writing the Chicken Talk section, Peter providing support and listen to me whine, Mario for being the net reporter, rien_ for proofreading and the other nice people on #chicken. Enough now, enjoy! _/_/_/ _/ _/ _/ _/ _/_/_/ _/_/_/ _/ _/ _/_/ _/_/_/ _/ _/ _/ _/ _/ _/_/ _/_/_/_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/_/_/ _/ _/ _/ _/_/_/ _/ _/ _/_/_/ _/ _/ --[ Issue 18 ]------------------------------------- G A Z E T T E brought to you by the Chicken Team == 0. Introduction Welcome to issue 18 of the Chicken Gazette. == 1. The Hatching Farm The last two weeks have been busy times in our egg repository. The following eggs have been updated: * Peter Bex * epeg released v2.4 * imlib released v0.13 * slatex released 20090928.1 * wmiirc released 0.5 * svn-client released v0.16 * Thomas Chust * openssl released version 1.5.1 * Moritz Heidkamp * remote-mailbox-threads released version 0.0.1 * char-set-literals tag version 0.1 * pool tag version 0.2 * hyde tag version 0.14 * Kon Lovett * bloom-filter released 1.1.1 * Ivan Raikov * flsim has initial support for Octave code generation now * Jum Ursetto * sql-de-light released 0.4.3 * Felix Winkelmann * unix-sockets tagged v1.5 * bind released 0.93^W0.94 * coops released v1.3 New eggs in our farm: * Moritz created validator * Nick Gasson released Slime v1.0, now that it is in an egg, you don't need to go through the git install hoop to get it. Thanks Nick! Egg tickets fixed: * Ticket #480 utf8 egg noop->void in experimental branch. * Ticket #476 unix-sockets missing (require-library posix) * Ticket #477 unix-sockets using obsolete pointer type * Ticket #471 (message-digest tests fail * Ticket #470 locale egg should rename getenv calls * Ticket #468 MAGIC-LIMIT is undefined in lookup-table Ongoing stuff * Peter Bex worked hard on crypt the last weeks * Alan Post put tremendous effort into bug fixes in genturfahi. * Alaric Snell-Pym worked on egg:ugarit, adding as he says "...just a few more unit tests. [P]rogress is slow but steady though." == 2. Core development We part from the following bugs: * Ticket #484 -scrutinize not properly expanding match macro, reported by Alan Post. * Ticket #479 bind egg should support ___blob * Ticket #466 csc -gui broken (OS X) But also the core has been busy: CR439 has been added by Peter Bex as voting time is up and no one spoke (against it). A Bug related ##sys#unblock-threads-for-i/ has been reported by Jim Ursetto and fixed in experimental. A new function called /condition->list/ has been added to the library. This allows conversion and handling of conditions without knowledge of the inner structure of conditions. Of course some entries have been missing again from the types.db, reported by Kon Lovett. /(compile-file)/ now returns /#f/ on error. The default /trace-buffer/ size is now 16. Sven Hartrumpf provided a patch to the /make-dist/ helper scripts fixing the deprecated /getenv/ procedure, the new one is named /get-environment-variable/. /__byte_vector/ has been marked deprecated. /__blob/ has been added to bind. The /-gui/ option has been fixed, as it tried to link with chicken.rc.o on all platforms. Thanks to ddp for reporting that. Taylor Venable has reported serious breakage in the accumulated profiling code, thanks! Christian Kellermann spotted a problem in the newly changed equal? patch. Kon also spotted inefficient type checks for the 64 bit integers. Felix fixed it, then Sven provided a patch for broken integer64 type checks. Felix Winkelmann appeased some compiler warnings in the runtime code, apart from being busy applying all the patches :) Jules Altfas spotted that /vector-copy!/ was missing from /types.db/. Good catch! == 3. Chicken Talk Christian Kellermann announced (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00055.html) that he has set up a salmonella instance for Chicken's experimental branch on his server (http://pestilenz.org/~ckeen/salmonella-report/index.html). If you are an egg maintainer and would like to know whether your eggs will break with the upcoming Chicken, check out the reports. Christian is going to move the installation over to call-cc.org once the configuration has stabilized. David Dreisigmeyer had a nice surprise for the mailing list last week. After asking (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00064.html) a few suspicious questions (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00080.html) about embedding Chicken he came out with a Chicken REPL embedded in a Python REPL (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00103.html). Now that's nice! Sandro Schugk kicked off a discussion (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00099.html) about the type relationship of lists and pairs, featuring insightful comparisons with Common Lisp's view of this affair as well as an ASCII art type diagram (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00119.html) by Thomas Chust. Vilson Vieira found a shortcoming (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00120.html) in bind's typedef parsing. Felix Winkelmann announced to implement the missing functionality as soon as he gets around to it (http://www.quantumenterprises.co.uk/roundtuitimages/padded_case2_L.jpg). Judging by Vilson's site (http://automata.cc/) we can probably hold our breaths for something really cool to come out of this! Finally, Alan Post (again) uncovered a problem (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00122.html) while working on his infamous parser genturfahi. It turned out to be caused by a bug (http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00138.html) in matchable's recently added tail-pattern support. Alex Shinn has promised to fix it as soon as possible. Thanks Alan for shaking out yet another bug and thanks Alex for your continued great job on your Scheme libraries! Meanwhile elsewhere on the internets... Mario has found these gems: Vilson Vieira (http://automata.cc/) started coding Chicken bindings to PortAudio in his github repo (http://github.com/automata/chicken-portaudio). He's got some help from Moritz via #chicken. On a reddit thread (http://www.reddit.com/r/scheme/comments/f5kxh/can_you_produce_programs_as_fast_in_scheme_as_in/), Chris Targett mentioned he started binding inotify (https://github.com/xlevus/chicken-stuff/blob/master/inotify) to Chicken. Chris has also got his repository of Chicken stuff on github (https://github.com/xlevus/chicken-stuff/). After seeing a very silly benchmark (http://call-with-hopeless-continuation.blogspot.com/2010/03/lies-damn-lies-and-benchmarks.html) performed by Mario Domenech Goulart, Bradley Lucier (http://www.math.purdue.edu/~lucier/) started a thread (https://mercure.iro.umontreal.ca/pipermail/gambit-list/2011-January/004770.html) on Gambit's mailing list showing some results which indicate that "Chicken really smokes Gambit" on this femtobenchmark. The question is, should it?" Marc Feeley follows up with the reassuring statement (https://mercure.iro.umontreal.ca/pipermail/gambit-list/2011-January/004774.html): /The x86 back-end runs fib_scm about 2.5 times faster than when using the C back-end. That's faster than Chicken, and also Larceny and Ikarus (which have x86 back-ends). The Gambit x86 back-end supports both x86-32 and x86-64./ So we guess all is well again. C'esar L. B. Silveira (http://cesarbs.notapipe.org/) translated the C code for tinywm (http://incise.org/tinywm.html) to Chicken. The resulting code can be found at http://cesarbs.notapipe.org/tinywm-scheme.html. == 4. Omelette Recipes Today I will introduce you to a much asked for topic of Chicken Scheme on our IRC channel last week: Exception handling in Chicken Scheme. === These are our conditions A newsgroup posting once had this quote: To err is human to restart divine which relates to Common Lisp being able to do so called /restarts/ on error conditions. In Chicken Scheme there are no restarts but it does come with a condition system that allows programmers to recover from exceptional conditions. Before I start, let me introduce a bit of vocabulary: - exception: A situation that needs special attention. Often used synonymously with condition. - condition: An object representing a current exceptional event. - exception-handler: A procedure that gets called with a /condition/ object - signal: A procedure that "raises" a condition by invoking the condition-handler with a condition object. - abort: A procedure that also raises a condition but ensures that the condition handler cannot return without raising another error. See below. Conditions should be raised whenever the program encounters a situation where it cannot go on without interaction with the calling code. Typical situations are: Operations on closed file descriptors, broken sockets, non existing files, memory allocation failures, syntax or type errors. As some of these conditions might be corrected in the handler and then be allowed to continue, Chicken Scheme's condition system distinguishes between two types of conditions: /continuable/ and /non-continuable/ conditions. As the name suggests non-continuable conditions are such severe events that the code cannot possibly continue at the location where the condition has been raised. Type errors fall in this category, i/o errors as well as others. Continuable conditions on the other hand /can/ continue where they have been signaled if the handler decides to do so. It may be possible to correct the error in the handler and have the code go along with it. === Condition objects A condition object is a distinct data type that consists of a condition /kind/ and of /property/ / /value/ pairs. These are also called /property-conditions/ and therefore the constructing procedure is (make-property-condition kind-key prop-key value ...) Where /kind-key/ and /prop-key/ are symbols. The constructor accepts any number of key / value pairs. The most basic condition signalled by the Chicken Scheme system is the /exn/ condition kind. All /exn/ conditions have three properties: - message: Textual message explaining the error. - arguments: The arguments passed to the condition handler. - location: The name of the procedure which raised the condition. To access properties in your code there are a couple of helper procedures defined in SRFI-12: /condition-predicate/, /condition-property-accessor/ and /get-condition-property/. The /condition-predicate/ procedure generates a predicate function that can be used to decide whether the condition kind is interesting to you: (let ((exn (make-property-condition 'all-my-fault 'message "I have failed, master"))) (if ((condition-predicate 'all-my-fault) exn) (print "He has failed again!") (print "Something else is rotten."))) ;;; Prints "He has failed again!" The /condition-property-accessor/ allows us to inspect the exception a bit more closely if we know what we are looking for: (let ((exn (make-property-condition 'all-my-fault 'message "I have failed, master"))) (if ((condition-predicate 'all-my-fault) exn) (print ((condition-property-accessor 'all-my-fault 'message "No message.") exn)) (print "Something else is rotten."))) ;;; Prints "I have failed, master!" Note that the /"No message"/ argument is an extension to the SRFI-12 procedure. It will serve as a default in case your exception does not provide the property you've asked for. If you omit the default and the property is not available an error will be raised (yes, another exception). An easier form of /condition-property-accessor/ is /get-condition-property/ which corresponds to it like this: (define (get-condition-property EXN KIND PROPERTY [DEFAULT]) ((condition-property-accessor KIND PROPERTY [DEFAULT]) EXN)) So it can save you a bit of typing parentheses. To be able to generate more complex condition objects it is possible to combine conditions to create so-called /composite-conditions/. The constructing procedure is called (make-composite-condition condition ...) and accepts property conditions objects and combines their kind keys together in the order of the arguments. Properties are associated with their conditions, meaning that more conditions can have the same property names and those will not get mixed up. The Chicken Scheme system provides these possible exceptions: - (exn arity): Signaled when a procedure is called with the wrong number of arguments. - (exn type): Signaled on type-mismatch errors, for example when an argument of the wrong type is passed to a built-in procedure. - (exn arithmetic): Signaled on arithmetic errors, like division by zero. - (exn i/o): Signaled on input/output errors. - (exn i/o file): Signaled on file-related errors. - (exn i/o net): Signaled on network errors. - (exn bounds): Signaled on errors caused by accessing non-existent elements of a collection. - (exn runtime): Signaled on low-level runtime-system error-situations. - (exn runtime limit): Signaled when an internal limit is exceeded (like running out of memory). - (exn match): Signaled on errors raised by failed matches (see the section on match). - (exn syntax): Signaled on syntax errors. These are also the system conditions raised by the Chicken Scheme conditions system. Now let's have a look what handlers look like. === Condition handling forms The exception-handler that is in charge at the time of rise of the exception is determined by the parameter (current-exception-handler procedure) which holds a procedure with unary arity expecting the condition object as argument. SRFI-12, the enhancement document to R5RS that Chicken Scheme took its condition system from suggests three forms that can implement condition handling. From lower to higher level they are: (with-exception-handler handler thunk) Sets the /current-exception-handler/ to /handler/ for the invocation of /thunk/ and resets it afterwards. _Warning:_ This procedure is very low level and should not be used in most cases, as you can create infinite loops with it. (handle-exceptions var handle-expression expr1 expr2 ...) This macro calls all the expressions with a special exception handler installed: ((call-with-current-continuation (lambda (k) (with-exception-handler (lambda (var) (k (lambda () handle-expression))) (lambda () (call-with-values (lambda() expr1....) (lambda args (k (lambda () (apply values args)))))))))) This is a full expansion of the /handle-exceptions/ macro. It transforms your code into a ((call/cc ..)) block, which will cause evaluation of itself later. As you can see it fetches the current continuation of the macro first to continue where it left off. Then it builds the exception handling function which binds the condition object to the name /var/ as specified in the macro and calls the continuation /k/ with the result of /handle-expression/. The expressions are called in order, returning the result of the last expression. (condition-case expression clause ...) The most high level of the three. It allows running /expression/ (a thunk) and then deal with the condition objects in a case like manner. Each clause has the form ([variable] (kind1 kind2 ...) BODY ...) Where the optional /variable/ provides a binding to the condition object in /BODY/. The kind clause is matched against the kind key of the condition object. So to simply catch /exn/ conditions have a clause /((exn) (display "Oooh an exn condition!"))/, to filter out a file exception use /((exn file) (display "I see, something's wrong with a file!"))/. The clauses are, like cond, matched in the order of appearance so be sure to place more special clauses first, general clauses next and an catch-all /exn ()/ clause (optionally) last. If the catch all clause is omitted the exception is re-raised by condition-case. Because condition-case captures the continuation just as 'handle-exception' does, re-raising the condition causes this continuation's exception handler to get called, so that the unhandled condition is handed over to the next handler. If no handler does handle the exception, the toplevel handler will finally abort the program and prints a call chain as well as the exn properties OR an unhandled exception message. === How to summon the beast Now that we know how to handle exceptions we would like to raise them ourselves. There are two basic procedures that raise conditions, /signal/ and /abort/. /Signal/ will be the most commonly used procedure for raising an exception. It's signature looks like (signal condition-object) and it calls /(current-exception-handler)/ with /condition-object/. The other procedure /abort/ does a little bit more than that: It calls the /current-condition-handler/ with the /condition-object/ then when the handler returns it calls itself with a condition object signaling that the handler returned. Why? === To continue or not continue -- That's the question As I wrote above there are now two ways to handle the conditions as they occur. The handler can decide to return any value it chooses or it can jump off somewhere else for example back to the top level of the REPL printing a call chain and the error message. This behavior is implemented in the primordial condition handler as it is installed by the Chicken Scheme system from the start. Depending on the application it might be also sensible to continue the computation with a corrected value instead of halting the process altogether. This different treatment after a condition is raised distinguishes /continuable/ conditions (that continue in the handler) from /non-continuable/ conditions that have to do something else, usually aborting the current computation. So with this distinction in mind it becomes clear that /signal/ should be used for raising continuable exceptions whereas /abort/ should be used to raise non-continuable exceptions. === Making continuable exceptions However one needs to be careful with constructing continuable exceptions for a couple of reasons: You need to do it yourself. Since the higher level constructs handle-exceptions as well as condition-case will always jump to the continuation where they have been called themselves, you will always jump "out" of your desired expression. Abort will call the handler again. Whenever in your code some system exception is raised with /abort/ you will end up in an infinite loop. This code for example does loop infinitely: /(with-exception-handler (lambda (e) 1) (lambda () (+ 1 (/ 1 0))))/ Despite the author's intention to just carry on with a bogus result this will call abort, which then will call the /(current-exception-handler)/ again as we have seen. A cure for this would be to check if it is an exception you are expecting (from your own code) or an exception raised by someone else which could mean jumping out to the old handler: (define (handle-input i) (if (even? i) (signal (make-property-condition 'my-condition 'message "Wrong input" 'arguments (list i))) i)) (define (test l) (let ((old-handler (current-exception-handler))) (with-exception-handler (lambda (exn) (cond (((condition-predicate 'my-condition) exn) (printf "called.~%~!") #f) (else (old-handler exn)))) (lambda () (map handle-input l))))) The results are #;1> (test '(1 2 3 4)) called. called. (1 #f 3 #f) #;2> (test '(1 2 y a)) called. Error: (even?) bad argument type: y Call history: <eval> [test] (map handle-input l) <eval> [handle-input] (even? i) <eval> [handle-input] (even? i) <eval> [handle-input] (signal (make-property-condition (quote my-condition) ... <eval> [handle-input] (make-property-condition (quote my-condition) ... <eval> [handle-input] (list i) <eval> [test] ((condition-predicate (quote my-condition)) exn) <eval> [test] (condition-predicate (quote my-condition)) <eval> [test] (printf "called.~%~!") <eval> [handle-input] (even? i) <-- === Non-continuable exceptions or business as usual Non-continuable exceptions really are easier to understand due to their 1:1 mapping to other languages with exception systems. They come close to the Java /try {} catch (Exception e){}/ block. >From the lessons learned above, always use /condition-case/ if you just want to handle your exceptional state. An example with handle-exceptions (from the SRFI-12 docs): (define (try-car v) (let ((orig (current-exception-handler))) (with-exception-handler (lambda (exn) (orig (make-composite-condition (make-property-condition 'not-a-pair 'value v) exn))) (lambda () (car v))))) (try-car '(1)) ;=> 1 (handle-exceptions exn (if ((condition-predicate 'not-a-pair) exn) (begin (display "Not a pair: ") (display ((condition-property-accessor 'not-a-pair 'value) exn)) (newline)) (ABORT exn)) (try-car 0)) ; displays "Not a pair: 0" And with /condition-case/: (define (check thunk) (condition-case (thunk) [(exn file) (print "file error")] [(exn) (print "other error")] [var () (print "something else")] ) ) (check (lambda () (open-input-file ""))) ; -> "file error" (check (lambda () some-unbound-variable)) ; -> "othererror" (check (lambda () (signal 99))) ; -> "something else" (condition-case some-unbound-variable ((exn file) (print "ignored")) ) ; -> signals error In my opinion condition-case makes it easier for 90% of your programming needs to catch explicitly certain types of exceptions in your code. If you need continuable exceptions you may resort to a more manual approach as outlined above. === Conclusion I hope I have been able to shed some light on the usage of exceptions in Chicken Scheme. I am grateful for any kind of comments and criticism to this piece. In the long term a merge of the results of this experimental article and the SRFI-12 docs in Chicken could benefit all. I am also thankful to Alaric, Felix and Peter who have read through drafts of this article. So long, may your code be exceptionally well guarded from now on. == 5. About the Chicken Gazette The Gazette is produced bi-weekly by a volunteer from the Chicken community. The latest issue can be found at http://gazette.call-cc.org or you can follow it in your feed reader at http://gazette.call-cc.org/feed.atom. If you'd like to write an issue, consult the wiki (http://wiki.call-cc.org/gazette) for the schedule and instructions! [ --- End of this issue --- ] _______________________________________________ Chicken-users mailing list [email protected] http://lists.nongnu.org/mailman/listinfo/chicken-users
--- End Message ---
