Front page | perl.perl6.language |
Postings from September 2005
Exceptuations
Thread Next
From:
Yuval Kogman
Date:
September 25, 2005 07:28
Subject:
Exceptuations
Message ID:
20050925142818.GT5797@woobling.org
Hi,
Suppose I'm writing a file browser, with a pane on the left to
display the filesystem hierarchy, and a frame on the right to
preview the file.
Suppose I have a convenience function, preview_file which takes a
path and returns a value that the frame display view knows to
render.
Let's define this for HTML files, where the desired preview is a
summary of the text:
use Text::Summarize;
use HTML::ToAscii;
multi sub preview_file ($filename where /\.html$/ ) {
my $handle = open($filename, :r); # might fail if $filename is unreadable
return summarize(html2ascii(=$handle)); # might fail if HTML is invalid
}
And this code is called when the user clicks on a file in the pane:
class NiftyUI {
use fatal;
method handl_some_click ($file) {
$.right_frame.display(preview_file($file.name));
}
method handle_event ($event) {
$?SELF.dispatch_event($event);
CATCH {
when NiftyBackend::Exception {
$?SELF.display_error_box($!);
}
default { die $! };
}
}
}
With the current shape of the code if any of the possible failures
in the backend code happen, they are reported in a message dialog.
Now, let's say we would like to add a feature, that lets the user
change the mode of the file if it's unreadable.
Several approaches to doing this:
* give the backend an abstract object, a Frontend of sorts:
$frontend.ask_user("do you want to make the file readable?")
* throw internal exceptions, and let the frontend handle the
exception and retry the action:
method handle_some_click ($file) {
$.right_frame.display(preview_file($file.name));
CATCH {
when IO::Errors::PERMISSION_DENIED {
if ($?SELF.ask_user_to_chmod_file($file)) {
make_readable($file);
$?SELF.handle_some_click($file); # retry the event
} else { die $! }
}
}
}
I propose a new model - each exception has a continuation that
allows it to be unfatalized.
The exception object has info on whether the fatality of the
exception was due to a die, or a use fatal, and lets the exception
handler decide accordingly.
Then we have code that looks like this:
method handle_some_click ($file) {
$.right_frame.display(preview_file($file.name));
CATCH {
when IO::Errors::PERMISSION_DENIED {
if ($?SELF.ask_user_to_chmod_file($file)) {
make_readable($file);
$!.continue(open($file, :r)); # the return value of the failed open is
# overridden by the return value of this (hopefully successful) open.
} else { die $! }
}
when HTML::ToAscii::Exception { # badly formed
$!.continue("The HTML file contained a syntax error");
# this string is passed to summarize instead of the undef exception object
}
}
}
The value this has is in handler cascading... If, for example,
make_readdable($file) failed too, then an exception handler around
handle_some_click could handle display a sudo box, to try it again,
and eventually continue back into the make_readable($file) call,
which will then continue into the failed open.
--
() Yuval Kogman <nothingmuch@woobling.org> 0xEBD27418 perl hacker &
/\ kung foo master: /me tips over a cow: neeyah!!!!!!!!!!!!!!!!!!!!!!
Thread Next
-
Exceptuations
by Yuval Kogman