source: project/gazette/src/issues/18.wiki @ 22534

Last change on this file since 22534 was 22534, checked in by ckeen, 8 years ago

gazette #18: yesterdays tomorrow is now so fix the date

File size: 23.4 KB
Line 
1((title . "Issue 18")
2 (authors  "Christian Kellermann" "Moritz Heidkamp")
3 (date . 1295989550.0))
4
5== 0. Introduction
6
7Welcome to issue 18 of the Chicken Gazette.
8
9== 1. The Hatching Farm
10
11The last two weeks have been busy times in our egg repository. The
12following eggs have been updated:
13
14* [[user:peter-bex|Peter Bex]]
15** [[egg:epeg|epeg]] released v2.4
16** [[egg:imlib|imlib]] released v0.13
17** [[egg:slatex|slatex]] released 20090928.1
18** [[egg:wmiirc|wmiirc]] released 0.5
19** [[egg:svn-client|svn-client]] released v0.16
20* [[user:thomas-chust|Thomas Chust]]
21** [[egg:openssl|openssl]] released version 1.5.1
22* [[user:moritz-heidkamp|Moritz Heidkamp]]
23** [[egg:remote-mailbox-threads|remote-mailbox-threads]] released version 0.0.1
24** [[egg:char-set-literals|char-set-literals]] tag version 0.1
25** [[egg:pool|pool]] tag version 0.2
26** [[egg:hyde|hyde]] tag version 0.14
27* [[user:kon-lovett|Kon Lovett]]
28** [[egg:bloom-filter|bloom-filter]] released 1.1.1
29* [[user:ivan-raikov|Ivan Raikov]]
30** [[egg:flsim|flsim]] has initial support for Octave code generation now
31* [[user:jim.-ursetto|Jum Ursetto]]
32** [[egg:sql-de-lite|sql-de-light]] released 0.4.3
33* [[user:felix-winkelmann|Felix Winkelmann]]
34** [[egg:unix-sockets|unix-sockets]] tagged v1.5
35** [[egg:bind|bind]] released 0.93^W0.94
36** [[egg:coops|coops]] released v1.3
37
38New eggs in our farm:
39
40* Moritz created [[egg:validator|validator]]
41* [[user:nick-gasson|Nick Gasson]] released [[egg:slime|Slime]] v1.0,
42 now that it is in an egg, you don't need to go through the git
43 install hoop to get it. Thanks Nick!
44
45Egg tickets fixed:
46
47* [[ticket:480|Ticket #480]] utf8 egg noop->void in experimental branch.
48* [[ticket:476|Ticket #476]] unix-sockets missing (require-library posix)
49* [[ticket:477|Ticket #477]] unix-sockets using obsolete pointer type
50* [[ticket:471|Ticket #471]] (message-digest tests fail
51* [[ticket:470|Ticket #470]] locale egg should rename getenv calls
52* [[ticket:468|Ticket #468]] MAGIC-LIMIT is undefined in lookup-table
53
54Ongoing stuff
55
56* [[user:peter-bex|Peter Bex]] worked hard on [[egg:crypt|crypt]] the
57  last weeks
58* [[user:alyn.post|Alan Post]] put tremendous effort into bug fixes in
59  [[egg:genturfahi|genturfahi]].
60* [[user:alaric-blagrave-snellpym|Alaric Snell-Pym]] worked on [[egg:ugarit]],
61  adding as he says "...just a few more unit tests. [P]rogress is slow
62  but steady though."
63
64== 2. Core development
65
66We part from the following bugs:
67
68* [[ticket:484|Ticket #484]] -scrutinize not properly expanding match macro, reported by Alan Post.
69* [[ticket:479|Ticket #479]] bind egg should support ___blob
70* [[ticket:466|Ticket #466]] csc -gui broken (OS X)
71
72But also the core has been busy:
73
74[[ticket:439|CR439]] has been added by [[user:peter-bex|Peter Bex]] as
75voting time is up and no one spoke (against it).
76
77A Bug related ##sys#unblock-threads-for-i/ has been reported by
78[[user:jim-ursetto|Jim Ursetto]] and fixed in experimental.
79
80A new function called ''condition->list'' has been added to the
81library. This allows conversion and handling of conditions without
82knowledge of the inner structure of conditions.
83
84Of course some entries have been missing again from the types.db,
85reported by [[user:kon-lovett|Kon Lovett]].
86
87''(compile-file)'' now returns ''#f'' on error.
88
89The default ''trace-buffer'' size is now 16.
90
91[[user:sven-hartrumpf|Sven Hartrumpf]] provided a patch to the
92''make-dist'' helper scripts fixing the deprecated ''getenv''
93procedure, the new one is named ''get-environment-variable''.
94
95''__byte_vector'' has been marked deprecated. ''__blob'' has been
96added to bind.
97
98The ''-gui'' option has been fixed, as it tried to link with
99chicken.rc.o on all platforms. Thanks to ddp for reporting that.
100
101Taylor Venable has reported serious breakage in the accumulated
102profiling code, thanks!
103
104[[user:christian-kellermann|Christian Kellermann]] spotted a problem
105in the newly changed equal? patch.
106
107Kon also spotted inefficient type checks for the 64 bit
108integers. Felix fixed it, then Sven provided a patch for broken
109integer64 type checks.
110
111[[user:felix-winkelmann|Felix Winkelmann]] appeased some compiler
112warnings in the runtime code, apart from being busy applying all the
113patches :)
114
115Jules Altfas spotted that ''vector-copy!'' was missing from
116''types.db''. Good catch!
117
118== 3. Chicken Talk
119
120Christian Kellermann
121[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00055.html|announced]]
122that he has set up a [[egg:salmonella|salmonella]] instance for
123Chicken's experimental branch
124[[http://pestilenz.org/~ckeen/salmonella-report/index.html|on his server]]. If
125you are an egg maintainer and would like to know whether your eggs
126will break with the upcoming Chicken, check out the reports. Christian
127is going to move the installation over to call-cc.org once the
128configuration has stabilized.
129
130
131David Dreisigmeyer had a nice surprise for the mailing list last
132week. After
133[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00064.html|asking]]
134a few suspicious
135[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00080.html|questions]]
136about embedding Chicken he came out with
137[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00103.html|a Chicken REPL embedded in a Python REPL]]. Now
138that's nice!
139
140Sandro Schugk
141[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00099.html|kicked off a discussion]]
142about the type relationship of lists and pairs, featuring insightful
143comparisons with Common Lisp's view of this affair as well as an
144[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00119.html|ASCII art type diagram]]
145by [[user:thomas-chust|Thomas Chust]].
146
147Vilson Vieira
148[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00120.html|found a shortcoming]]
149in [[egg:bind|bind]]'s typedef parsing. Felix Winkelmann announced to
150implement the missing functionality as soon as he gets
151[[http://www.quantumenterprises.co.uk/roundtuitimages/padded_case2_L.jpg|around to it]]. Judging
152by [[http://automata.cc/|Vilson's site]] we can probably hold our
153breaths for something really cool to come out of this!
154
155Finally, [[user:alyn.post|Alan Post]] (again)
156[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00122.html|uncovered a problem]]
157while working on his infamous parser [[egg:genturfahi|genturfahi]]. It
158turned out to be
159[[http://lists.nongnu.org/archive/html/chicken-users/2011-01/msg00138.html|caused by a bug]]
160in [[egg:matchable|matchable]]'s recently added tail-pattern
161support. [[user:alex-shinn|Alex Shinn]] has promised to fix it as soon
162as possible. Thanks Alan for shaking out yet another bug and thanks
163Alex for your continued great job on your Scheme libraries!
164
165
166Meanwhile elsewhere on the internets... Mario has found these gems:
167
168[[http://automata.cc/|Vilson Vieira]] started coding Chicken bindings
169to PortAudio in his
170[[http://github.com/automata/chicken-portaudio|github repo]].  He's
171got some help from Moritz via #chicken.
172
173On a [[http://www.reddit.com/r/scheme/comments/f5kxh/can_you_produce_programs_as_fast_in_scheme_as_in/|reddit
174thread]], Chris Targett mentioned he started
175[[https://github.com/xlevus/chicken-stuff/blob/master/inotify|binding
176inotify]] to Chicken. Chris has also got his repository of Chicken
177stuff on [[https://github.com/xlevus/chicken-stuff/|github]].
178
179After seeing a very silly
180[[http://call-with-hopeless-continuation.blogspot.com/2010/03/lies-damn-lies-and-benchmarks.html|benchmark]]
181performed by Mario Domenech Goulart,
182[[http://www.math.purdue.edu/~lucier/|Bradley Lucier]] started
183[[https://mercure.iro.umontreal.ca/pipermail/gambit-list/2011-January/004770.html|a
184thread]] on Gambit's mailing list showing some results which indicate
185that "Chicken really smokes Gambit" on this femtobenchmark. The
186question is, should it?"  Marc Feeley follows up with the reassuring
187[[https://mercure.iro.umontreal.ca/pipermail/gambit-list/2011-January/004774.html|statement]]:
188''The x86 back-end runs fib_scm about 2.5 times faster than when using
189the C back-end.  That's faster than Chicken, and also Larceny and
190Ikarus (which have x86 back-ends).  The Gambit x86 back-end supports
191both x86-32 and x86-64.'' So we guess all is well again.
192
193[[http://cesarbs.notapipe.org/|C'esar L. B. Silveira]] translated the
194C code for [[http://incise.org/tinywm.html|tinywm]] to Chicken.  The
195resulting code can be found at
196[[http://cesarbs.notapipe.org/tinywm-scheme.html]].
197
198
199== 4. Omelette Recipes
200
201Today I will introduce you to a much asked for topic of Chicken Scheme
202on our IRC channel last week: Exception handling in Chicken Scheme.
203
204=== These are our conditions
205
206A newsgroup posting once had this quote:
207
208 To err is human to restart divine
209
210which relates to Common Lisp being able to do so called ''restarts''
211on error conditions. In Chicken Scheme there are no restarts but it
212does come with a condition system that allows programmers to recover
213from exceptional conditions. Before I start, let me introduce a bit of
214vocabulary:
215
216; exception : A situation that needs special attention. Often used synonymously with condition.
217; condition : An object representing a current exceptional event.
218; exception-handler : A procedure that gets called with a ''condition'' object
219; signal : A procedure that "raises" a condition by invoking the condition-handler with a condition object.
220; abort : A procedure that also raises a condition but ensures that the condition handler cannot return without raising another error. See below.
221
222Conditions should be raised whenever the program encounters a
223situation where it cannot go on without interaction with the calling
224code. Typical situations are: Operations on closed file descriptors,
225broken sockets, non existing files, memory allocation failures, syntax
226or type errors.
227
228As some of these conditions might be corrected in the handler and then
229be allowed to continue, Chicken Scheme's condition system
230distinguishes between two types of conditions: ''continuable'' and
231''non-continuable'' conditions. As the name suggests non-continuable
232conditions are such severe events that the code cannot possibly
233continue at the location where the condition has been raised.  Type
234errors fall in this category, i/o errors as well as others.
235Continuable conditions on the other hand ''can'' continue where they
236have been signaled if the handler decides to do so. It may be
237possible to correct the error in the handler and have the code go
238along with it.
239
240=== Condition objects
241
242A condition object is a distinct data type that consists of a
243condition ''kind'' and of ''property'' / ''value'' pairs. These are
244also called ''property-conditions'' and therefore the constructing
245procedure is
246
247  (make-property-condition kind-key prop-key value ...)
248
249Where ''kind-key'' and ''prop-key'' are symbols. The constructor
250accepts any number of key / value pairs. The most basic condition
251signalled by the Chicken Scheme system is the ''exn'' condition kind.
252All ''exn'' conditions do have three properties:
253
254; message : Textual message explaining the error.
255; arguments : The arguments passed to the condition handler.
256; location : The name of the procedure which raised the condition.
257
258To access properties in your code there are a couple of helper
259procedures defined in SRFI-12: ''condition-predicate'',
260''condition-property-accessor'' and ''get-condition-property''.  The
261''condition-predicate'' procedure generates a predicate function that
262can be used to decide whether the condition kind is interesting to
263you:
264
265<enscript highlight="scheme">
266 (let ((exn (make-property-condition 'all-my-fault 'message "I have failed, master")))
267     (if ((condition-predicate 'all-my-fault) exn)
268         (print "He has failed again!")
269         (print "Something else is rotten.")))
270; Prints "He has failed again!"
271</enscript>
272
273The ''condition-property-accessor'' allows us to inspect the exception a
274bit more closely if we know what we are looking for:
275
276<enscript highlight="scheme">
277 (let ((exn (make-property-condition 'all-my-fault 'message "I have failed, master")))
278     (if ((condition-predicate 'all-my-fault) exn)
279         (print ((condition-property-accessor 'all-my-fault 'message "No message.") exn))
280         (print "Something else is rotten.")))
281; Prints "I have failed, master!"
282</enscript>
283
284Note the ''"No message"'' argument, it is an extension to the SRFI-12
285procedure. It will serve as a default in case your exception does not
286provide the property you've asked for. If you omit the default and the
287property is not available an error will be raised (yes, another
288exception).
289
290An easier form of ''condition-property-accessor'' is
291''get-condition-property'' which corresponds to it like this:
292
293<enscript highlight="scheme">
294 (define (get-condition-property EXN KIND PROPERTY [DEFAULT])
295   ((condition-property-accessor KIND PROPERTY [DEFAULT]) EXN))
296</enscript>
297
298So it can save you a bit of typing parentheses.
299
300To be able to generate more complex condition objects it is possible
301to combine conditions to so called ''composite-conditions''. The
302constructing procedure is called
303
304 (make-composite-condition condition ...)
305
306and accepts property conditions objects and combines their kind keys
307together in the order of the arguments. Properties are associated with
308their conditions, meaning that more conditions can have the same
309property names and those will not get mixed up. The Chicken Scheme
310system provides these possible exceptions:
311
312;(exn arity) : Signaled when a procedure is called with the wrong number of arguments.
313;(exn type) : Signaled on type-mismatch errors, for example when an argument of the wrong type is passed to a built-in procedure.
314;(exn arithmetic) : Signaled on arithmetic errors, like division by zero.
315;(exn i/o) : Signaled on input/output errors.
316;(exn i/o file) : Signaled on file-related errors.
317;(exn i/o net) : Signaled on network errors.
318;(exn bounds) : Signaled on errors caused by accessing non-existent elements of a collection.
319;(exn runtime) : Signaled on low-level runtime-system error-situations.
320;(exn runtime limit) : Signaled when an internal limit is exceeded (like running out of memory).
321;(exn match) : Signaled on errors raised by failed matches (see the section on match).
322;(exn syntax) : Signaled on syntax errors.
323
324These are also the system conditions raised by the Chicken Scheme
325conditions system.
326
327Now let's have a look what handlers look like.
328
329=== Condition handling forms
330
331The exception-handler that is in charge at the time of rise of the
332exception is determined by the parameter
333
334 (current-exception-handler procedure)
335
336which holds a procedure with unary arity expecting the condition
337object as argument. SRFI-12, the enhancement document to R5RS that
338Chicken Scheme took its condition system from suggests three forms
339that can implement condition handling. From lower to higher level they
340are:
341
342 (with-exception-handler handler thunk)
343
344Sets the ''current-exception-handler'' to ''handler'' for the
345invocation of ''thunk'' and resets it afterwards.  '''Warning:''' This
346procedure is very low level and should not be used in most cases, as
347you can create infinite loops with it.
348
349 (handle-exceptions var handle-expression expr1 expr2 ...)
350
351This macro calls all the expressions with a special exception handler
352installed:
353
354<enscript highlight ="scheme">
355((call-with-current-continuation
356   (lambda (k)
357     (with-exception-handler
358       (lambda (var)
359         (k (lambda ()
360              handle-expression)))
361       (lambda ()
362         (call-with-values
363           (lambda() expr1....)
364           (lambda args
365             (k (lambda () (apply values args))))))))))
366</enscript>
367
368This is a full expansion of the ''handle-exceptions'' macro. It
369transforms your code into a ((call/cc ..)) block, which will cause
370evaluation of itself later. As you can see it fetches the current
371continuation of the macro first to continue where it left off. Then it
372builds the exception handling function which binds the condition
373object to the name ''var'' as specified in the macro and calls the
374continuation ''k'' with the result of ''handle-expression''.
375
376The expressions are called in order, returning the result of the last
377expression.
378
379 (condition-case expression clause ...)
380
381The most high level of the three. It allows running ''expression'' (a
382thunk) and then deal with the condition objects in a case like
383manner. Each clause has the form
384
385 ([variable] (kind1 kind2 ...) BODY ...)
386
387Where the optional ''variable'' provides a binding to the condition
388object in ''BODY''. The kind clause is matched against the kind key of
389the condition object. So to simply catch ''exn'' conditions have a
390clause ''((exn) (display "Oooh an exn condition!"))'', to filter out a
391file exception use ''((exn file) (display "I see, something's wrong
392with a file!"))''. The clauses are, like cond, matched in the order of
393appearance so be sure to place more special clauses first, general
394clauses next and an all catch ''exn ()'' clause (optionally) last. If
395the catch all clause is omitted the exception is re-raised by
396condition-case.
397
398As condition-case also captures the continuation as 'handle-exception'
399does re-raising the condition causes this continuation's exception
400handler to get called, so that the unhandled condition is handed over
401to the next handler. If no handler does handle the exception, the
402toplevel handler will finally abort the program and prints an call
403chain as well as the exn properties OR an unhandled exception message.
404
405=== How to summon the beast
406
407Now that we know how to handle exceptions we would like to raise them
408ourselves. There are two basic procedures that raise conditions,
409''signal'' and ''abort''. ''Signal'' will be the most commonly used
410procedure for raising an exception. It's signature looks like
411
412 (signal condition-object)
413
414and it calls ''(current-exception-handler)'' with
415''condition-object''. The other procedure ''abort'' does a little bit
416more than that: It calls the ''current-condition-handler'' with the
417''condition-object'' then when the handler returns calls itself with a
418condition object signaling that the handler returned. Why?
419
420=== To continue or not continue -- That's the question
421
422As I wrote above there are now two ways to handle the conditions as
423they occur. The handler can decide to return any value it chooses or
424it can jump off somewhere else for example back to the top level of
425the REPL printing a call chain and the error message. This behavior is
426implemented in the primordial condition handler as it is installed by
427the Chicken Scheme system from the start.
428
429Depending on the application it might be also sensible to continue the
430computation with a corrected value instead of halting the process
431altogether.
432
433This different treatment after a condition is raised distinguishes
434''continuable'' conditions (that continue in the handler) from
435''non-continuable'' conditions that have to do something else, usually
436aborting the current computation.
437
438So with this distinction in mind it becomes clear that ''signal''
439should be used for raising continuable exceptions whereas ''abort''
440should be used to raise non-continuable exceptions.
441
442=== Making continuable exceptions
443
444However one needs to be careful with constructing continuable
445exceptions for a couple of reasons:
446
447You need to do it yourself. Since the higher level constructs
448handle-exceptions as well as condition-case will always jump to the
449continuation where they have been called themselves, you will always
450jump "out" of your desired expression.
451
452Abort will call the handler again. Whenever in your code some system
453exception is raised with ''abort'' you will end up in an infinite
454loop. This code for example does loop infinitely:
455''(with-exception-handler (lambda (e) 1) (lambda () (+ 1 (/ 1 0))))''
456Despite the author's intention to just carry on with a bogus result
457this will call abort, which then will call the
458''(current-exception-handler)'' again as we have seen.
459
460A cure for this would be to check if it is an exception you are
461expecting (from your own code) or an exception raised by someone else
462which could mean jumping out to the old handler:
463
464<enscript highlight="scheme">
465(define (handle-input i)
466  (if (even? i)
467      (signal (make-property-condition
468               'my-condition
469               'message "Wrong input"
470               'arguments (list i)))
471      i))
472
473(define (test l)
474  (let ((old-handler (current-exception-handler)))
475    (with-exception-handler
476     (lambda (exn)
477       (cond (((condition-predicate 'my-condition) exn)
478              (printf "called.~%~!") #f)
479             (else (old-handler exn))))
480     (lambda () (map handle-input l)))))
481</enscript>
482
483The results are
484
485 #;1> (test '(1 2 3 4))
486 called.
487 called.
488 (1 #f 3 #f)
489 #;2> (test '(1 2 y a))
490 called.
491 
492 Error: (even?) bad argument type: y
493 
494    Call history:
495 
496    <eval>    [test] (map handle-input l)
497    <eval>    [handle-input] (even? i)
498    <eval>    [handle-input] (even? i)
499    <eval>    [handle-input] (signal (make-property-condition (quote my-condition) ...
500    <eval>    [handle-input] (make-property-condition (quote my-condition) ...
501    <eval>    [handle-input] (list i)
502    <eval>    [test] ((condition-predicate (quote my-condition)) exn)
503    <eval>    [test] (condition-predicate (quote my-condition))
504    <eval>    [test] (printf "called.~%~!")
505    <eval>    [handle-input] (even? i)      <--
506
507
508=== Non-continuable exceptions or business as usual
509
510Non-continuable exceptions really are easier to understand due to
511their 1:1 mapping to other languages with exception systems. They come
512close to the Java ''try {} catch (Exception e){}'' block.
513
514From the lessons learned above, always use ''condition-case'' if you
515just want to handle your exceptional state.
516
517An example with handle-exceptions (from the SRFI-12 docs):
518
519<enscript highlight="scheme">
520(define (try-car v)
521 (let ((orig (current-exception-handler)))
522   (with-exception-handler
523    (lambda (exn)
524      (orig (make-composite-condition
525      (make-property-condition
526       'not-a-pair
527       'value
528       v)
529      exn)))
530    (lambda () (car v)))))
531
532(try-car '(1))
533;=> 1
534
535(handle-exceptions exn
536            (if ((condition-predicate 'not-a-pair) exn)
537                (begin
538                 (display "Not a pair: ")
539                 (display
540                  ((condition-property-accessor 'not-a-pair 'value) exn))
541                 (newline))
542                (ABORT exn))
543  (try-car 0))
544; displays "Not a pair: 0"
545
546</enscript>
547
548And with ''condition-case'':
549
550<enscript highlight="scheme">
551(define (check thunk)
552  (condition-case (thunk)
553    [(exn file) (print "file error")]
554    [(exn) (print "other error")]
555    [var () (print "something else")] ) )
556
557(check (lambda () (open-input-file "")))   ; -> "file error"
558(check (lambda () some-unbound-variable))  ; -> "othererror"
559(check (lambda () (signal 99)))            ; -> "something else"
560
561(condition-case some-unbound-variable
562  ((exn file) (print "ignored")) )      ; -> signals error
563</enscript>
564
565In my opinion condition-case makes it easier for 90% of your
566programming needs to catch explicitly certain types of exceptions in
567your code. If you need continuable exceptions you may resort to a more
568manual approach as outlined above.
569
570=== Conclusion
571
572I hope I have been able to shed some light on the usage of exceptions
573in Chicken Scheme. I am grateful for any kind of comments and
574criticism to this piece. In the long term a merge of the results of
575this experimental article and the SRFI-12 docs in Chicken could
576benefit all.
577
578I am also thankful to Alaric, Felix and Peter who have read through
579drafts of this article.
580
581So long, may your code be exceptionally well guarded from now on.
582
583== 5. About the Chicken Gazette
584
585The Gazette is produced bi-weekly by a volunteer from the Chicken
586community. The latest issue can be found at
587[[http://gazette.call-cc.org]] or you can follow it in your feed
588reader at [[http://gazette.call-cc.org/feed.atom]]. If you'd like to
589write an issue, [[http://wiki.call-cc.org/gazette|consult the wiki]]
590for the schedule and instructions!
Note: See TracBrowser for help on using the repository browser.