Looking through the functions in the System module it looks like a big mix between throwing an exception on error or returning the errno from the function. Is there a good reason for this mix? Is this something that should be fixed (other than more documentation on which functions behaves how)?
I think the throws started to appear when the talk of an exception system was starting to grow...
I think that we should make an exception system with support in the syntax/semantics, then change all the functions to throw. :) But that's me.
/ Mirar
Previous text:
2003-10-01 00:24: Subject: throw or return
Looking through the functions in the System module it looks like a big mix between throwing an exception on error or returning the errno from the function. Is there a good reason for this mix? Is this something that should be fixed (other than more documentation on which functions behaves how)?
/ Martin Nilsson (saturator)
On Wed, Oct 01, 2003 at 12:25:02AM +0200, Martin Nilsson (saturator) @ Pike (-) developers forum wrote:
Looking through the functions in the System module it looks like a big mix between throwing an exception on error or returning the errno from the function.
In cases if we would have an exception model like in Java/C++ (where type of exception may be checked easily - say, catch only file system errors, etc) - it would make sense to use an exceptions.
But in current state, when exception returns human readable message, it makes a bit difficult task to identify the nature of exception.
Sure, in some cases exceptions would be logical ("file system is full"), but sometimes this is a bit too much, IMHO.
The ideal solution is to make it configurable - with #pragma or whatever, which model to use. Regular #defines wouldn work well in case of precompiled modules (since those will use symbols known during installation time only).
Regards, /Al
I kind of agree with Alexander - the current exception system is not useful as an error handling mechanism. Also I'm sure it's less efficient than using a return codes.
That said, I also wouldn't want Pike programming to become the nightmare Java is in terms of requiring try / catch for "all" system calls. One of the really annoying things when programming java IMHO. If a file fails to open when I call "open", return 0. If a file fails to open if I use Stdio.File("file"), there probably should be an exception thrown (since there is no other mechanism to signify an error in a constructor).
For methods requiring multiple error conditions, I much rather prefer integers to be returned. I.e:
switch(Stdio.format_filesystem("/dev/hda2", "ext5")) { case Stdio.EFILSYS: // invalid file system type break; case Stdio.EACCESS: case Stdio.EMOUNTED: // no permission or filesystem mounted break; }
etc. Similar to the concept of errno I suppose. _If_ we had a working exception system, and could write code such as this, it wouldn't be bad either:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch(Stdio.FileSystemTypeException e) { // invalid file system type } catch(Stdio.MountedException | Stdio.AccessException e) { // no permission or filesystem mounted }
If on the other hand we would have to write:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch(Stdio.FileSystemTypeException e) { // invalid file system type } catch(Stdio.AccessException e) { // no permission } catch(Stdio.MountedException e) { // filesystem mounted }
It'd be worse and we'd get the Java nightmare. If you can't handle two distinctly different exceptions in the same block of code, without resorting to some generic Exception, it's a broken system. Of course all this is purely hypothetical since we actually don't have a well defined exception system like this anyway. Given the current exceptions, I definitely vote for return codes whenever practical.
/ David Hedbor
Previous text:
2003-10-01 10:40: Subject: Re: throw or return
On Wed, Oct 01, 2003 at 12:25:02AM +0200, Martin Nilsson (saturator) @ Pike (-) developers forum wrote:
Looking through the functions in the System module it looks like a big mix between throwing an exception on error or returning the errno from the function.
In cases if we would have an exception model like in Java/C++ (where type of exception may be checked easily - say, catch only file system errors, etc) - it would make sense to use an exceptions.
But in current state, when exception returns human readable message, it makes a bit difficult task to identify the nature of exception.
Sure, in some cases exceptions would be logical ("file system is full"), but sometimes this is a bit too much, IMHO.
The ideal solution is to make it configurable - with #pragma or whatever, which model to use. Regular #defines wouldn work well in case of precompiled modules (since those will use symbols known during installation time only).
Regards, /Al
/ Brevbäraren
A better exception system has been on the wish list for a long time. I agree that changing the errno stuff to exceptions before we have that would be a mistake. Any takers to do something about it?
I think a more "pike:ish" way to implement it is to use recognition constants instead of type inference. That makes it simpler to fix correct exception objects in dynamic environments, and it follows the "looks-like" rather than "is-a" philosophy of type comparisons in Pike.
Anyway, the difference from your proposal would be mostly syntactic in practice:
try (Exception e) { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (e->invalid_file_system_type) { // invalid file system type } catch (e->no_permission || e->not_mounted) { // no permission or filesystem mounted }
Note that the exception variable is specified in the try clause, much like how foreach variables are specified or declared in foreach clauses. The catch clauses take normal expressions, which means full freedom in writing complex catch conditions.
One could perhaps support a shorthand syntax to avoid handling the exception object explicitly:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch invalid_file_system_type { // invalid file system type } catch no_permission, not_mounted { // no permission or filesystem mounted }
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 16:56: Subject: Re: throw or return
I kind of agree with Alexander - the current exception system is not useful as an error handling mechanism. Also I'm sure it's less efficient than using a return codes.
That said, I also wouldn't want Pike programming to become the nightmare Java is in terms of requiring try / catch for "all" system calls. One of the really annoying things when programming java IMHO. If a file fails to open when I call "open", return 0. If a file fails to open if I use Stdio.File("file"), there probably should be an exception thrown (since there is no other mechanism to signify an error in a constructor).
For methods requiring multiple error conditions, I much rather prefer integers to be returned. I.e:
switch(Stdio.format_filesystem("/dev/hda2", "ext5")) { case Stdio.EFILSYS: // invalid file system type break; case Stdio.EACCESS: case Stdio.EMOUNTED: // no permission or filesystem mounted break; }
etc. Similar to the concept of errno I suppose. _If_ we had a working exception system, and could write code such as this, it wouldn't be bad either:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch(Stdio.FileSystemTypeException e) { // invalid file system type } catch(Stdio.MountedException | Stdio.AccessException e) { // no permission or filesystem mounted }
If on the other hand we would have to write:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch(Stdio.FileSystemTypeException e) { // invalid file system type } catch(Stdio.AccessException e) { // no permission } catch(Stdio.MountedException e) { // filesystem mounted }
It'd be worse and we'd get the Java nightmare. If you can't handle two distinctly different exceptions in the same block of code, without resorting to some generic Exception, it's a broken system. Of course all this is purely hypothetical since we actually don't have a well defined exception system like this anyway. Given the current exceptions, I definitely vote for return codes whenever practical.
/ David Hedbor
I would favor a solution where "catch" didn't have to change semantics.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 18:09: Subject: Re: throw or return
A better exception system has been on the wish list for a long time. I agree that changing the errno stuff to exceptions before we have that would be a mistake. Any takers to do something about it?
I think a more "pike:ish" way to implement it is to use recognition constants instead of type inference. That makes it simpler to fix correct exception objects in dynamic environments, and it follows the "looks-like" rather than "is-a" philosophy of type comparisons in Pike.
Anyway, the difference from your proposal would be mostly syntactic in practice:
try (Exception e) { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (e->invalid_file_system_type) { // invalid file system type } catch (e->no_permission || e->not_mounted) { // no permission or filesystem mounted }
Note that the exception variable is specified in the try clause, much like how foreach variables are specified or declared in foreach clauses. The catch clauses take normal expressions, which means full freedom in writing complex catch conditions.
One could perhaps support a shorthand syntax to avoid handling the exception object explicitly:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch invalid_file_system_type { // invalid file system type } catch no_permission, not_mounted { // no permission or filesystem mounted }
/ Martin Stjernholm, Roxen IS
All the proposed syntaxes are easy to tell apart from the current catch expression, at least. But I guess you mean that "try" should be "catch" instead and some other keyword should be used for the catch clauses. I can't figure out any good keyword for that, though. Furthermore it would be more difficult to tell the old-style and new-style syntaxes apart if both began with the same keyword.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 18:12: Subject: Re: throw or return
I would favor a solution where "catch" didn't have to change semantics.
/ Martin Nilsson (saturator)
Perhaps you could make it look like a switch block (although fall through behaviour isn't ideal, in particular not when you introduce the label "finally :", so perhaps one shouldn't use "case" for this).
try { ... some code ... } catch (Exception e) { case invalid_file_system_type: ... break; case no_permission: case not_mounted: ... break; default: ... finally: ... }
I was trying to figure out if we have any current language constructs that takes two blocks of code, and the only I could think of was if () { ... } else { ... }.
/ Niels Möller (igelkottsräddare)
Previous text:
2003-10-01 18:18: Subject: Re: throw or return
All the proposed syntaxes are easy to tell apart from the current catch expression, at least. But I guess you mean that "try" should be "catch" instead and some other keyword should be used for the catch clauses. I can't figure out any good keyword for that, though. Furthermore it would be more difficult to tell the old-style and new-style syntaxes apart if both began with the same keyword.
/ Martin Stjernholm, Roxen IS
A finally clause ought to be another block afterwards. If it's a label then it leads, as you say, to odd semantics. It's not only the fall-through case that makes it questionable, but also the execution order when it isn't the last thing in the block. Furthermore, since a finally block is executed even when no error is thrown, one gets the question why the exception variable is in scope there and what value it would have then.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-06 07:56: Subject: Re: throw or return
Perhaps you could make it look like a switch block (although fall through behaviour isn't ideal, in particular not when you introduce the label "finally :", so perhaps one shouldn't use "case" for this).
try { ... some code ... } catch (Exception e) { case invalid_file_system_type: ... break; case no_permission: case not_mounted: ... break; default: ... finally: ... }
I was trying to figure out if we have any current language constructs that takes two blocks of code, and the only I could think of was if () { ... } else { ... }.
/ Niels Möller (igelkottsräddare)
On Wed, Oct 01, 2003 at 06:15:01PM +0200, Martin Nilsson (saturator) @ Pike (-) developers forum wrote:
I would favor a solution where "catch" didn't have to change semantics.
would it be better to return something more meaningful when throwing an error? Some universal object with methods to determine error type, error locus and exact error code (and suggested action perhaps)?
Like:
if ((err = catch(func())) && err->type != "user") throw(err); // Pass it on if we can't handle
Other methods:
err->locus -- may replace backtrace (or point to location like "filesystem" or "cpu" for divison by zero err->errno -- in case when type == "system" err->action -- may be "retry" (for transient errors), "abort" (for fatal errors), "ignore" (like file doesn't exist when unlinking or another safe-to-ignore error), etc err->code -- exact error code (if applicable and not OS related) Error types might be "os" or "system" (for system calls and related objects), "user" (classic throw() with custom message/code), "pike" (interpreter itself, like dereferencing a mapping which is NULL), and so on... In this case we don't need to change anything in syntax, not so much, at least.
Regards, /Al
You are absolutely right. The exception objects are an orthogonal issue to how to trap them. On the whole I think your suggestion looks fairly good. The compatibility implications of changing the current ({ "error", backtrace() }) de facto standard into an object based one is probably acceptable.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 18:40: Subject: Re: throw or return
On Wed, Oct 01, 2003 at 06:15:01PM +0200, Martin Nilsson (saturator) @ Pike (-) developers forum wrote:
I would favor a solution where "catch" didn't have to change semantics.
would it be better to return something more meaningful when throwing an error? Some universal object with methods to determine error type, error locus and exact error code (and suggested action perhaps)?
Like:
if ((err = catch(func())) && err->type != "user") throw(err); // Pass it on if we can't handle
Other methods:
err->locus -- may replace backtrace (or point to location like "filesystem" or "cpu" for divison by zero err->errno -- in case when type == "system" err->action -- may be "retry" (for transient errors), "abort" (for fatal errors), "ignore" (like file doesn't exist when unlinking or another safe-to-ignore error), etc err->code -- exact error code (if applicable and not OS related) Error types might be "os" or "system" (for system calls and related objects), "user" (classic throw() with custom message/code), "pike" (interpreter itself, like dereferencing a mapping which is NULL), and so on... In this case we don't need to change anything in syntax, not so much, at least.
Regards, /Al
/ Brevbäraren
Actually it has already been done in some cases. Try this, for instance:
Pike v7.4 release 29 running Hilfe v3.5 (Incremental Pike Frontend)
mixed err = catch (cpp ("#ifdef"));
-:1:#ifdef what? -:1:End of file while searching for #endif.
objectp (err);
(1) Result: 1
err;
(2) Result: cpp_error("Cpp() failed\n")
indices (err);
(3) Result: ({ /* 10 elements */ "is_cpp_error", "backtrace", "describe", "__backtrace", "__desc", "error_type", "_sprintf", "`[]", "cast", "is_generic_error" })
err->error_type;
(4) Result: "cpp_error"
err->backtrace();
(5) Result: ({ /* 9 elements */ backtrace_frame(/home/mast/Pike/frozen/build/linux-2.4.20-i686/master.pike:1911, _main(), Args: 2), backtrace_frame(Unknown file, StdinHilfe(), No args), backtrace_frame(/home/mast/Pike/frozen/lib/modules/Tools.pmod/Hilfe.pmod:2043, create(), No args), backtrace_frame(/home/mast/Pike/frozen/lib/modules/Tools.pmod/Hilfe.pmod:1270, add_input_line(), Args: 1), backtrace_frame(/home/mast/Pike/frozen/lib/modules/Tools.pmod/Hilfe.pmod:1319, add_buffer(), Args: 1), backtrace_frame(/home/mast/Pike/frozen/lib/modules/Tools.pmod/Hilfe.pmod:1681, parse_expression(), Args: 1), backtrace_frame(/home/mast/Pike/frozen/lib/modules/Tools.pmod/Hilfe.pmod:1368, add_hilfe_variable(), Args: 3), backtrace_frame(/home/mast/Pike/frozen/lib/modules/Tools.pmod/Hilfe.pmod:1890, hilfe_compile(), Args: 2), backtrace_frame(HilfeInput:1, __INIT(), No args) })
err->is_cpp_error;
(6) Result: 1
err->is_generic_error;
(7) Result: 1
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 18:50: Subject: Re: throw or return
You are absolutely right. The exception objects are an orthogonal issue to how to trap them. On the whole I think your suggestion looks fairly good. The compatibility implications of changing the current ({ "error", backtrace() }) de facto standard into an object based one is probably acceptable.
/ Martin Nilsson (saturator)
In this case we don't need to change anything in syntax, not so much, at least.
As Nilsson said, the syntax is a separate issue. I think a new syntax should be added. The main feature with the try/catch syntax of C++ and Java is that the rethrowing of unhandled errors is implicit. It's worth a lot to avoid clumsy code for handling that detail. It also avoids mistakes when people forget to write the rethrowing code; it's very frustrating to deal with code that doesn't do that and thus effectively hide all sorts of errors.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 18:40: Subject: Re: throw or return
On Wed, Oct 01, 2003 at 06:15:01PM +0200, Martin Nilsson (saturator) @ Pike (-) developers forum wrote:
I would favor a solution where "catch" didn't have to change semantics.
would it be better to return something more meaningful when throwing an error? Some universal object with methods to determine error type, error locus and exact error code (and suggested action perhaps)?
Like:
if ((err = catch(func())) && err->type != "user") throw(err); // Pass it on if we can't handle
Other methods:
err->locus -- may replace backtrace (or point to location like "filesystem" or "cpu" for divison by zero err->errno -- in case when type == "system" err->action -- may be "retry" (for transient errors), "abort" (for fatal errors), "ignore" (like file doesn't exist when unlinking or another safe-to-ignore error), etc err->code -- exact error code (if applicable and not OS related) Error types might be "os" or "system" (for system calls and related objects), "user" (classic throw() with custom message/code), "pike" (interpreter itself, like dereferencing a mapping which is NULL), and so on... In this case we don't need to change anything in syntax, not so much, at least.
Regards, /Al
/ Brevbäraren
Another alternative, closer to the switch syntax David proposed earlier:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission || e->not_mounted: // no permission or filesystem mounted break; }
The main feature with this is compared to "try (Exception e) {...} catch ..." is that it avoids the awkward question whether the variable e is visible inside the try block or not. The problem is that it also allows fall-through, which can be a source of mistakes.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 18:09: Subject: Re: throw or return
A better exception system has been on the wish list for a long time. I agree that changing the errno stuff to exceptions before we have that would be a mistake. Any takers to do something about it?
I think a more "pike:ish" way to implement it is to use recognition constants instead of type inference. That makes it simpler to fix correct exception objects in dynamic environments, and it follows the "looks-like" rather than "is-a" philosophy of type comparisons in Pike.
Anyway, the difference from your proposal would be mostly syntactic in practice:
try (Exception e) { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (e->invalid_file_system_type) { // invalid file system type } catch (e->no_permission || e->not_mounted) { // no permission or filesystem mounted }
Note that the exception variable is specified in the try clause, much like how foreach variables are specified or declared in foreach clauses. The catch clauses take normal expressions, which means full freedom in writing complex catch conditions.
One could perhaps support a shorthand syntax to avoid handling the exception object explicitly:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch invalid_file_system_type { // invalid file system type } catch no_permission, not_mounted { // no permission or filesystem mounted }
/ Martin Stjernholm, Roxen IS
If we make exceptions as expressful as Al suggests, then we would probably want normal if-expressions somehow.
keyword(Exception e) { Stdio.format_filesystem("/dev/hda2", "ext5"); } if(e->something==17 && sizeof(seamingly_unrelated)==3) { //handle this } else if(e->really_bad==1) { //handle that } else { //don't throw unknown exceptions }
I don't like this particular example though, since the if-statements are outside of the traditional range of the e variable.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 19:56: Subject: Re: throw or return
Another alternative, closer to the switch syntax David proposed earlier:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission || e->not_mounted: // no permission or filesystem mounted break; }
The main feature with this is compared to "try (Exception e) {...} catch ..." is that it avoids the awkward question whether the variable e is visible inside the try block or not. The problem is that it also allows fall-through, which can be a source of mistakes.
/ Martin Stjernholm, Roxen IS
I don't like this syntax very much. The one suggested in the message you commented is nice except that I would write it like this rather:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
/ David Hedbor
Previous text:
2003-10-01 20:23: Subject: Re: throw or return
If we make exceptions as expressful as Al suggests, then we would probably want normal if-expressions somehow.
keyword(Exception e) { Stdio.format_filesystem("/dev/hda2", "ext5"); } if(e->something==17 && sizeof(seamingly_unrelated)==3) { //handle this } else if(e->really_bad==1) { //handle that } else { //don't throw unknown exceptions }
I don't like this particular example though, since the if-statements are outside of the traditional range of the e variable.
/ Martin Nilsson (saturator)
I would prefer
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
and would think this to be even better
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 20:42: Subject: Re: throw or return
I don't like this syntax very much. The one suggested in the message you commented is nice except that I would write it like this rather:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
/ David Hedbor
I like that last one.
/ Fredrik (Naranek) Hubinette (Real Build Master)
Previous text:
2003-10-01 20:51: Subject: Re: throw or return
I would prefer
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
and would think this to be even better
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
/ Martin Nilsson (saturator)
Please no. It's way harder to distinguish that from the old syntax.
Anything wrong with try / catch? handle is probably used much more often than try in normal code, too.
/ Per Hedbor ()
Previous text:
2003-10-01 20:51: Subject: Re: throw or return
I would prefer
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
and would think this to be even better
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
/ Martin Nilsson (saturator)
For the latter syntax I see no gain in comparision to using:
Exception e = catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } if(e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
I.e there would really be no change from the current syntax at all, other than some minor syntax changes.
And perhaps all that is needed is catch to return something more useful than the current array. However I like the idea of being able to use a switch or switch-like statement for checking exceptions (for the simple reason that often it leads to nicer code).
Another question is how would you throw an exception like this?
Exception error = Exception(); // creates new exception with current backtrace error->invalid_file_system_type = 1; throw error;
This is clumpsy. So..
throw Exception("invalid_file_system_type");
This doesn't allow for inheritance. So..
Throw InvalidFileSystemTypeException();
Allows for inheritance and is just one line but could also possibly suffer from the java "too long names on classes" issue. What I don't think anyone wants is a case where throwing an exception becomes a multi-line problem, and I think we all want exception inheritance.
I still don't REALLY see the benefit of using:
e->some_obscure_string
rather than handling it by class name, i.e
SomeObscureException
then your own exception could inherit correctly from other exceptions and things would work ok. I.e
class MyFileSystemException { inherit Exception.FileSystem; ... }
class FileSystem { inherit IOException; ... }
class IOException { inherit Exception; ... }
this is one thing that actually does work well in Java. If you have som alternative idea how exceptions will work, please point that out. I think the basic issue of how exceptions are created greatly would affect how exceptions should be handled.
/ David Hedbor
Previous text:
2003-10-01 20:51: Subject: Re: throw or return
I would prefer
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
and would think this to be even better
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
/ Martin Nilsson (saturator)
I still don't REALLY see the benefit of using:
e->some_obscure_string
rather than handling it by class name, i.e
SomeObscureException
The benefit is that the catch conditions become normal expressions which are much more powerful than type dispatch. Most often they would only check for a constant, but they might do other stuff. E.g:
try { blabla(); } catch (Exception err) { case err->is_io_error && err->file == the_interesting_file: // There was some I/O error with the file we're interested in here. break; }
then your own exception could inherit correctly from other exceptions and things would work ok. I.e
Yes, we should have a class tree that uses inheritance to group errors together. The best way to get a suitable set of constants in the exception objects is actually to inherit them. The point with recognizing them through constants and not the inherit relations directly is
a) it's shorter to write e.g. err->is_foo_error rather than Program.inherits(object_program(err), FooException), and b) it's possible to define error classes even in cases where the errors they should be compatible with aren't available in the namespace at compile time.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 21:19: Subject: Re: throw or return
For the latter syntax I see no gain in comparision to using:
Exception e = catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } if(e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
I.e there would really be no change from the current syntax at all, other than some minor syntax changes.
And perhaps all that is needed is catch to return something more useful than the current array. However I like the idea of being able to use a switch or switch-like statement for checking exceptions (for the simple reason that often it leads to nicer code).
Another question is how would you throw an exception like this?
Exception error = Exception(); // creates new exception with current backtrace error->invalid_file_system_type = 1; throw error;
This is clumpsy. So..
throw Exception("invalid_file_system_type");
This doesn't allow for inheritance. So..
Throw InvalidFileSystemTypeException();
Allows for inheritance and is just one line but could also possibly suffer from the java "too long names on classes" issue. What I don't think anyone wants is a case where throwing an exception becomes a multi-line problem, and I think we all want exception inheritance.
I still don't REALLY see the benefit of using:
e->some_obscure_string
rather than handling it by class name, i.e
SomeObscureException
then your own exception could inherit correctly from other exceptions and things would work ok. I.e
class MyFileSystemException { inherit Exception.FileSystem; ... }
class FileSystem { inherit IOException; ... }
class IOException { inherit Exception; ... }
this is one thing that actually does work well in Java. If you have som alternative idea how exceptions will work, please point that out. I think the basic issue of how exceptions are created greatly would affect how exceptions should be handled.
/ David Hedbor
a) it's shorter to write e.g. err->is_foo_error rather than Program.inherits(object_program(err), FooException), and
If we decide to make the exception system inherit-based we would of course create a shorter way to perform that operation, so this is quite a non-argument.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 22:04: Subject: Re: throw or return
I still don't REALLY see the benefit of using:
e->some_obscure_string
rather than handling it by class name, i.e
SomeObscureException
The benefit is that the catch conditions become normal expressions which are much more powerful than type dispatch. Most often they would only check for a constant, but they might do other stuff. E.g:
try { blabla(); } catch (Exception err) { case err->is_io_error && err->file == the_interesting_file: // There was some I/O error with the file we're interested in here. break; }
then your own exception could inherit correctly from other exceptions and things would work ok. I.e
Yes, we should have a class tree that uses inheritance to group errors together. The best way to get a suitable set of constants in the exception objects is actually to inherit them. The point with recognizing them through constants and not the inherit relations directly is
a) it's shorter to write e.g. err->is_foo_error rather than Program.inherits(object_program(err), FooException), and b) it's possible to define error classes even in cases where the errors they should be compatible with aren't available in the namespace at compile time.
/ Martin Stjernholm, Roxen IS
Only if you actually specify what that shorter syntax would be. It's not that easy to come up with one that is so brief as an indexing.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 23:53: Subject: Re: throw or return
a) it's shorter to write e.g. err->is_foo_error rather than Program.inherits(object_program(err), FooException), and
If we decide to make the exception system inherit-based we would of course create a shorter way to perform that operation, so this is quite a non-argument.
/ Martin Nilsson (saturator)
'x > FooException', if we add a comparison operator to the exceptions.
/ Per Hedbor ()
Previous text:
2003-10-01 23:57: Subject: Re: throw or return
Only if you actually specify what that shorter syntax would be. It's not that easy to come up with one that is so brief as an indexing.
/ Martin Stjernholm, Roxen IS
For the latter syntax I see no gain in comparision to using:
You'll get an implicit throw, which is the problem today.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 21:19: Subject: Re: throw or return
For the latter syntax I see no gain in comparision to using:
Exception e = catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } if(e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
I.e there would really be no change from the current syntax at all, other than some minor syntax changes.
And perhaps all that is needed is catch to return something more useful than the current array. However I like the idea of being able to use a switch or switch-like statement for checking exceptions (for the simple reason that often it leads to nicer code).
Another question is how would you throw an exception like this?
Exception error = Exception(); // creates new exception with current backtrace error->invalid_file_system_type = 1; throw error;
This is clumpsy. So..
throw Exception("invalid_file_system_type");
This doesn't allow for inheritance. So..
Throw InvalidFileSystemTypeException();
Allows for inheritance and is just one line but could also possibly suffer from the java "too long names on classes" issue. What I don't think anyone wants is a case where throwing an exception becomes a multi-line problem, and I think we all want exception inheritance.
I still don't REALLY see the benefit of using:
e->some_obscure_string
rather than handling it by class name, i.e
SomeObscureException
then your own exception could inherit correctly from other exceptions and things would work ok. I.e
class MyFileSystemException { inherit Exception.FileSystem; ... }
class FileSystem { inherit IOException; ... }
class IOException { inherit Exception; ... }
this is one thing that actually does work well in Java. If you have som alternative idea how exceptions will work, please point that out. I think the basic issue of how exceptions are created greatly would affect how exceptions should be handled.
/ David Hedbor
The second alternative doesn't allow unmatched exceptions to be rethrown, at least not without heavy magic. That is the main point with a special syntax.
As for the first alternative, I think try/catch is better: It's known from other similar languages, and it's easier to tell apart from the current catch syntax. Actually, I'm not entirely sure there are no truly ambiguous cases if the first keyword is the same.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 20:51: Subject: Re: throw or return
I would prefer
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
and would think this to be even better
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
/ Martin Nilsson (saturator)
My idea was of course that if you don't exit "handle" with a "break" the exception is rethrown.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 21:25: Subject: Re: throw or return
The second alternative doesn't allow unmatched exceptions to be rethrown, at least not without heavy magic. That is the main point with a special syntax.
As for the first alternative, I think try/catch is better: It's known from other similar languages, and it's easier to tell apart from the current catch syntax. Actually, I'm not entirely sure there are no truly ambiguous cases if the first keyword is the same.
/ Martin Stjernholm, Roxen IS
On Wed, Oct 01, 2003 at 11:55:02PM +0200, Martin Nilsson (saturator) @ Pike (-) developers forum wrote:
My idea was of course that if you don't exit "handle" with a "break" the exception is rethrown.
I think that it must be rethrown explicitly, simply because it is handled, and only unhandled exceptions (in case if we would take a class concept) must be escalated to higher levels (unconditionally).
Regards, /Al
| catch { | ...->accept(); | } | handle (Exception e) | { | if (e->system_error && e->errno==EAGAIN) | continue; | }
;-)
I think this structure is the best, if you want to switch you could always do that.
/ Mirar
Previous text:
2003-10-01 20:51: Subject: Re: throw or return
I would prefer
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
and would think this to be even better
catch { Stdio.format_filesystem("/dev/hda2", "ext5"); } handle (Exception e) { if(e->invalid_file_system_type) { // invalid file system type break; } if(e->no_permission || e->not_mounted) { // no permission or filesystem mounted break; } }
/ Martin Nilsson (saturator)
Well, with the current switch statement you can't switch on error groups so it would very rarely be useful.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 22:33: Subject: Re: throw or return
| catch { | ...->accept(); | } | handle (Exception e) | { | if (e->system_error && e->errno==EAGAIN) | continue; | }
;-)
I think this structure is the best, if you want to switch you could always do that.
/ Mirar
Depends on if the group exist in the exception object,
switch (e->group) { case "bananer": ... }
I hope both type of exception and the actual exception will be in readable variables?
/ Mirar
Previous text:
2003-10-01 22:38: Subject: Re: throw or return
Well, with the current switch statement you can't switch on error groups so it would very rarely be useful.
/ Martin Stjernholm, Roxen IS
Ok, I'll change "very rarely" to "only sometimes": That approach doesn't work very well with subgroups. Say for instance that errors are classified as "os", "pike", etc and that "os" errors are further classified into "io", "memory", etc. How would you then write a switch that handles "io" and "pike" errors but not anything else?
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 22:40: Subject: Re: throw or return
Depends on if the group exist in the exception object,
switch (e->group) { case "bananer": ... }
I hope both type of exception and the actual exception will be in readable variables?
/ Mirar
Yes, I agree. But there needs to be a good design how to store and use those, anyway.
Actually, I think I would prefer a very clear and precise syntax, like
try <statement> catch [(Exception e)] { File_Error: ... break; Compile_Error: ... break; }
but I suspect it's not practical enough. And anyway, any good exception handling sugar is good enough for me...
/ Mirar
Previous text:
2003-10-01 22:48: Subject: Re: throw or return
Ok, I'll change "very rarely" to "only sometimes": That approach doesn't work very well with subgroups. Say for instance that errors are classified as "os", "pike", etc and that "os" errors are further classified into "io", "memory", etc. How would you then write a switch that handles "io" and "pike" errors but not anything else?
/ Martin Stjernholm, Roxen IS
It is indeed a very flexible structure. Combined with that only explicit continue statements would avoid rethrowing, I think it would work well.
As for keywords, I think "try" and "onerror" fit best. Some examples:
Catch only I/O errors and report them on stderr:
try { do_stuff(); } onerror (Error err) if (err->is_io_error) { werror ("I/O error on %O: %s\n", err->file, err->description); continue; // Avoid rethrow. }
Catch and handle application specific errors, and log but rethrow I/O errors:
try { do_stuff(); } onerror (Error err) if (err->is_my_app_error) { handle_my_app_error (err); continue; // Avoid rethrow. } else { my_app_log ("Interrupted by error: %s\n", err->description); }
Clean up a cache no matter what happens:
int id = session_id++; try { session_cache[id] = SessionObj(); do_stuff(); } onerror () { m_delete (session_cache, id); // All errors are rethrown here. } m_delete (session_cache, id);
The last case, to always do some cleanup, is common and it shows code duplication. To avoid that I'd like a Java-style "finally" clause too:
int id = session_id++; try { session_cache[id] = SessionObj(); do_stuff(); } onerror (Error err) if (err->is_my_app_error) { handle_my_app_error (err); continue; // Avoid rethrow. } finally { // This is always executed no matter what happens above. m_delete (session_cache, id); // If the try block was interrupted by an error other than the // my_app type, it's rethrown here. }
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 22:33: Subject: Re: throw or return
| catch { | ...->accept(); | } | handle (Exception e) | { | if (e->system_error && e->errno==EAGAIN) | continue; | }
;-)
I think this structure is the best, if you want to switch you could always do that.
/ Mirar
I think I would like continue to redo the try. I'm not totally clear what "avoid rethrow" would mean...
I really like try <statement> [ onerror [(variable decl)] <statement> ] [ finally <statement> ]
but note that I'd like all three to be statement, not { ... }, so you can write
try foo() onerror werror("got error!!1!¡\n");
if you like.
/ Mirar
Previous text:
2003-10-01 23:53: Subject: Re: throw or return
It is indeed a very flexible structure. Combined with that only explicit continue statements would avoid rethrowing, I think it would work well.
As for keywords, I think "try" and "onerror" fit best. Some examples:
Catch only I/O errors and report them on stderr:
try { do_stuff(); } onerror (Error err) if (err->is_io_error) { werror ("I/O error on %O: %s\n", err->file, err->description); continue; // Avoid rethrow. }
Catch and handle application specific errors, and log but rethrow I/O errors:
try { do_stuff(); } onerror (Error err) if (err->is_my_app_error) { handle_my_app_error (err); continue; // Avoid rethrow. } else { my_app_log ("Interrupted by error: %s\n", err->description); }
Clean up a cache no matter what happens:
int id = session_id++; try { session_cache[id] = SessionObj(); do_stuff(); } onerror () { m_delete (session_cache, id); // All errors are rethrown here. } m_delete (session_cache, id);
The last case, to always do some cleanup, is common and it shows code duplication. To avoid that I'd like a Java-style "finally" clause too:
int id = session_id++; try { session_cache[id] = SessionObj(); do_stuff(); } onerror (Error err) if (err->is_my_app_error) { handle_my_app_error (err); continue; // Avoid rethrow. } finally { // This is always executed no matter what happens above. m_delete (session_cache, id); // If the try block was interrupted by an error other than the // my_app type, it's rethrown here. }
/ Martin Stjernholm, Roxen IS
If you want to loop back to the try block again then I think you should put some loop statement around it all. I don't consider it entirely orthogonal to have that functionality directly in an error handling construct. Besides, a much better keyword for it would be "retry".
"Avoid rethrow" means to continue after the statement. The default is to throw the error again after executing the onerror clause (and the finally clause, if there is any).
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:00: Subject: Re: throw or return
I think I would like continue to redo the try. I'm not totally clear what "avoid rethrow" would mean...
I really like try <statement> [ onerror [(variable decl)] <statement> ] [ finally <statement> ]
but note that I'd like all three to be statement, not { ... }, so you can write
try foo() onerror werror("got error!!1!¡\n");
if you like.
/ Mirar
To me it seemed clearer that "break" would be "avoid rethrow" rather then "continue"...
/ Mirar
Previous text:
2003-10-02 00:10: Subject: Re: throw or return
If you want to loop back to the try block again then I think you should put some loop statement around it all. I don't consider it entirely orthogonal to have that functionality directly in an error handling construct. Besides, a much better keyword for it would be "retry".
"Avoid rethrow" means to continue after the statement. The default is to throw the error again after executing the onerror clause (and the finally clause, if there is any).
/ Martin Stjernholm, Roxen IS
Hmm, yes it fits better in the sense that "break" everywhere else means "continue after the end of some surrounding block".
In this case I thought "continue" was more natural since the alternative to the default rethrow is better described as to "continue" with the normal program flow rather than "break"ing something. It also weaves better with a switch block since no labels are necessary then to tell which construct the breaks apply to.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:11: Subject: Re: throw or return
To me it seemed clearer that "break" would be "avoid rethrow" rather then "continue"...
/ Mirar
Hmm, yes it fits better in the sense that "break" everywhere else means "continue after the end of some surrounding block".
I'm not sure that's relevant. Look at
foo: for(;;) { try {...}
onerror (Exception e) { if (e->error1) continue; else if (e->error2) break; else if (e->error3) continue foo; else break foo; } }
Here, both break foo and continue foo should go on executing without rethrowing the exception, right? The question is what a break and continue for the onerror block should do.
My gut reaction was that continue should rethrow the exception, and break ends the error handling. I guess that's because I think of the error handling code as part of larger context which includes other onerror blocks elsewhere in the call chain.
/ Niels Möller (igelkottsräddare)
Previous text:
2003-10-02 00:26: Subject: Re: throw or return
Hmm, yes it fits better in the sense that "break" everywhere else means "continue after the end of some surrounding block".
In this case I thought "continue" was more natural since the alternative to the default rethrow is better described as to "continue" with the normal program flow rather than "break"ing something. It also weaves better with a switch block since no labels are necessary then to tell which construct the breaks apply to.
/ Martin Stjernholm, Roxen IS
On Thu, Oct 02, 2003 at 12:15:01AM +0200, Martin Stjernholm, Roxen IS @ Pike developers forum wrote:
"Avoid rethrow" means to continue after the statement. The default is to throw the error again after executing the onerror clause (and the finally clause, if there is any).
What is the point to implicitly "rethrow" an exception which is handled?
Or, make it another way - what is the point to handle an exception to rethrow it?
Regards, /Al
With the onerror construct,
try ... onerror (Err x) { }
*all* errors will be handled. You need to differ between the errors you take care of and those you don't care about, so you can do
... onerror (Err x) { if (x is my special error) { handle_it(x); break; // don't rethrow } // rethrow }
for instance. I think rethrowing an unhandled error this way is a good idea.
/ Mirar
Previous text:
2003-10-02 00:23: Subject: Re: throw or return
On Thu, Oct 02, 2003 at 12:15:01AM +0200, Martin Stjernholm, Roxen IS @ Pike developers forum wrote:
"Avoid rethrow" means to continue after the statement. The default is to throw the error again after executing the onerror clause (and the finally clause, if there is any).
What is the point to implicitly "rethrow" an exception which is handled?
Or, make it another way - what is the point to handle an exception to rethrow it?
Regards, /Al
/ Brevbäraren
I still like the switch-like structure best, mainly because it's very easy to detect what's unhandled.
/ Per Hedbor ()
Previous text:
2003-10-02 00:25: Subject: Re: throw or return
With the onerror construct,
try ... onerror (Err x) { }
*all* errors will be handled. You need to differ between the errors you take care of and those you don't care about, so you can do
... onerror (Err x) { if (x is my special error) { handle_it(x); break; // don't rethrow } // rethrow }
for instance. I think rethrowing an unhandled error this way is a good idea.
/ Mirar
Me too, actually. And I think it's what you really want rather then to build a lot of if sequences... I don't mind at all if it's represented by "if" sequences internally, though.
/ Mirar
Previous text:
2003-10-02 00:27: Subject: Re: throw or return
I still like the switch-like structure best, mainly because it's very easy to detect what's unhandled.
/ Per Hedbor ()
That's a good point. Looking back at some of the examples, they aren't really as clean as I'd like them to be.
If we go for a switch-like thing, it's necessary to use "continue" to avoid rethrow, since some statement must be provided to jump out of it with a rethrow, and "break" would fit that much better.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:27: Subject: Re: throw or return
I still like the switch-like structure best, mainly because it's very easy to detect what's unhandled.
/ Per Hedbor ()
I think continue would fit rethrowing much better, since it means "go to the end of the block" (=rethrow) rather then breaks "go past the end of the block" (=get out of the block without rethrow)...
But that's me. :)
/ Mirar
Previous text:
2003-10-02 00:45: Subject: Re: throw or return
That's a good point. Looking back at some of the examples, they aren't really as clean as I'd like them to be.
If we go for a switch-like thing, it's necessary to use "continue" to avoid rethrow, since some statement must be provided to jump out of it with a rethrow, and "break" would fit that much better.
/ Martin Stjernholm, Roxen IS
You certainly got a point there.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:49: Subject: Re: throw or return
I think continue would fit rethrowing much better, since it means "go to the end of the block" (=rethrow) rather then breaks "go past the end of the block" (=get out of the block without rethrow)...
But that's me. :)
/ Mirar
How about 'rethrow'?
/ Per Hedbor ()
Previous text:
2003-10-02 00:45: Subject: Re: throw or return
That's a good point. Looking back at some of the examples, they aren't really as clean as I'd like them to be.
If we go for a switch-like thing, it's necessary to use "continue" to avoid rethrow, since some statement must be provided to jump out of it with a rethrow, and "break" would fit that much better.
/ Martin Stjernholm, Roxen IS
On Thu, Oct 02, 2003 at 01:20:03AM +0200, Per Hedbor () @ Pike (-) developers forum wrote:
Or, for simplicitys case 'throw(err)', where err is the original variable.
It would be better, IMHO. This is explicit and clearly states that error is not completely handled and passed on.
Regards, /Al
Then the point with a special syntax is largely lost. I think what Per commented on was my concern over providing a break-and-rethrow syntax to be used in the middle of the onerror clause, in addition to the break-and-don't-rethrow statement. He's right that throw(err) serves well for that, so there's no need for a special break-and-rethrow. Still, the default for all errors that aren't explicitly flagged as handled should be to rethrow.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 17:10: Subject: Re: throw or return
I am bound to agree. It doesn't add much effort to do:
{ default: throw(e); }
at the end.
/ David Hedbor
Yes, that makes sense. Break + rethrow would just use throw().
/ David Hedbor
Previous text:
2003-10-02 17:28: Subject: Re: throw or return
Then the point with a special syntax is largely lost. I think what Per commented on was my concern over providing a break-and-rethrow syntax to be used in the middle of the onerror clause, in addition to the break-and-don't-rethrow statement. He's right that throw(err) serves well for that, so there's no need for a special break-and-rethrow. Still, the default for all errors that aren't explicitly flagged as handled should be to rethrow.
/ Martin Stjernholm, Roxen IS
To avoid people hiding errors. Primarily from lazyness. It makes it much harder to track down bugs when someone encapsulated something in a a catch deep down in the project and didn't bother to rethrow.
/ Peter Bortas
Previous text:
2003-10-02 00:34: Subject: Re: throw or return
On Thu, Oct 02, 2003 at 12:30:01AM +0200, Mirar @ Pike developers forum wrote:
I think rethrowing an unhandled error this way is a good idea.
Why not explicitly? To avoid miscoding or something like this?
/Al
/ Brevbäraren
If they should accept any statement (which I also think is good) then the parenthesis after onerror probably have to be mandatory. It's possible to allow it to be left empty, though.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:00: Subject: Re: throw or return
I think I would like continue to redo the try. I'm not totally clear what "avoid rethrow" would mean...
I really like try <statement> [ onerror [(variable decl)] <statement> ] [ finally <statement> ]
but note that I'd like all three to be statement, not { ... }, so you can write
try foo() onerror werror("got error!!1!¡\n");
if you like.
/ Mirar
Hm, which statements can start with '(', except (useless) expressions?
What happens if you return in the try, onerror or finally part?
/ Mirar
Previous text:
2003-10-02 00:13: Subject: Re: throw or return
If they should accept any statement (which I also think is good) then the parenthesis after onerror probably have to be mandatory. It's possible to allow it to be left empty, though.
/ Martin Stjernholm, Roxen IS
On Thu, Oct 02, 2003 at 12:20:02AM +0200, Mirar @ Pike developers forum wrote:
What happens if you return in the try, onerror or finally part?
In the "try" part - return is handled as usual (obviously - if it reached then everything is OK).
In the "onerror" and "finally" parts - stack unwinding and return as usual (unless this is impossible at all, but there are no reasons why it should not be possible - for normal, i.e. not internal compiler/interpreter errors).
However, it would be nice to still have current "catch" behavior, i.e. catch() and catch{} - those are useful sometimes (it may return an exception object, but avoids extra code and looks more clean).
Regards, /Al
However, it would be nice to still have current "catch" behavior, i.e. catch() and catch{} - those are useful sometimes (it may return an exception object, but avoids extra code and looks more clean).
I don't agree that it looks more clean when taking into account all the surrounding code that is necessary to use it correctly. Still, it should of course continue to exist, for compatibility's sake if nothing else. And if people continue to prefer it in some situations then it'd be silly to remove it.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:32: Subject: Re: throw or return
On Thu, Oct 02, 2003 at 12:20:02AM +0200, Mirar @ Pike developers forum wrote:
What happens if you return in the try, onerror or finally part?
In the "try" part - return is handled as usual (obviously - if it reached then everything is OK).
In the "onerror" and "finally" parts - stack unwinding and return as usual (unless this is impossible at all, but there are no reasons why it should not be possible - for normal, i.e. not internal compiler/interpreter errors).
However, it would be nice to still have current "catch" behavior, i.e. catch() and catch{} - those are useful sometimes (it may return an exception object, but avoids extra code and looks more clean).
Regards, /Al
/ Brevbäraren
Consider this case:
#define FOO(X) (foo(X) ? bar() : gnu())
try do_stuff() onerror FOO(x) ...
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:17: Subject: Re: throw or return
Hm, which statements can start with '(', except (useless) expressions?
What happens if you return in the try, onerror or finally part?
/ Mirar
What happens if you return in the try, onerror or finally part?
At least, I think the finally clause always should be executed regardless of how execution is transferred from the try and onerror clauses (that also includes labelled breaks and continues).
For all those messy details we better just copy Java. See http://java.sun.com/docs/books/jls/second_edition/html/statements.doc.html#7....
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:17: Subject: Re: throw or return
Hm, which statements can start with '(', except (useless) expressions?
What happens if you return in the try, onerror or finally part?
/ Mirar
How about:
try(Exception e) { catch { format(); }
if(e->foobar) { write_error_message(); break; } if(e->gazonk) { fatal_error(); } }
The point of this syntax would be that the exception is automatically re-thrown at the end of the try statement, unless a break is encountered, only then is the error discarded.
/ Fredrik (Naranek) Hubinette (Real Build Master)
Previous text:
2003-10-01 20:42: Subject: Re: throw or return
I don't like this syntax very much. The one suggested in the message you commented is nice except that I would write it like this rather:
try { Stdio.format_filesystem("/dev/hda2", "ext5"); } catch (Exception e) { case e->invalid_file_system_type: // invalid file system type break; case e->no_permission; case e->not_mounted: // no permission or filesystem mounted break; }
/ David Hedbor
That's quite nice actually. I still want a discussion on the exception object(s) and throwing / creating them, to know how handling of them would work. The only problem with the syntax is that it's not entirely "logical" that the exception area would be called when no exception is thrown. Also it's possibly also the "if/else" mightmare that I mentioned in my other post, which is more of an issue with the way exception types are identified.
/ David Hedbor
Previous text:
2003-10-01 20:51: Subject: Re: throw or return
How about:
try(Exception e) { catch { format(); }
if(e->foobar) { write_error_message(); break; } if(e->gazonk) { fatal_error(); } }
The point of this syntax would be that the exception is automatically re-thrown at the end of the try statement, unless a break is encountered, only then is the error discarded.
/ Fredrik (Naranek) Hubinette (Real Build Master)
On Wed, Oct 01, 2003 at 09:30:02PM +0200, David Hedbor @ Pike developers forum wrote:
That's quite nice actually. I still want a discussion on the exception object(s) and throwing / creating them, to know how handling of them would work.
I would prefer exception classes (inheritable) and try/catch/finally (as in C++) construct. That's my vote :)
Regards, /Al
What's the reason for nesting the catch block inside the try block? Afaics that only opens up for odd issues like: What happens if there's other code before the catch block? What happens if there are several catch blocks? What is the visibility of the exception variable?
The idea that only explicit break statements would avoid rethrowing is neat, though I think "continue" is more apt. That idea can be used in switch-like blocks too, of course.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 20:51: Subject: Re: throw or return
How about:
try(Exception e) { catch { format(); }
if(e->foobar) { write_error_message(); break; } if(e->gazonk) { fatal_error(); } }
The point of this syntax would be that the exception is automatically re-thrown at the end of the try statement, unless a break is encountered, only then is the error discarded.
/ Fredrik (Naranek) Hubinette (Real Build Master)
Please don't use this syntax There is no gain at all when compared to the current system.
/ Per Hedbor ()
Previous text:
2003-10-01 20:23: Subject: Re: throw or return
If we make exceptions as expressful as Al suggests, then we would probably want normal if-expressions somehow.
keyword(Exception e) { Stdio.format_filesystem("/dev/hda2", "ext5"); } if(e->something==17 && sizeof(seamingly_unrelated)==3) { //handle this } else if(e->really_bad==1) { //handle that } else { //don't throw unknown exceptions }
I don't like this particular example though, since the if-statements are outside of the traditional range of the e variable.
/ Martin Nilsson (saturator)
I didn't say I wanted that syntax. It just looks very clumsy to look at the presence of constants in an object. E.g. it could be nice to categorize errors into system errors, c-level errors and pike errors, and then be able to catch only pike-level errors. One could have native-pike-module, application-specific-module and application as further clustering of the pike errors as well. To be able to use expressions like (e->level < APPLICATION_MODULE_LEVEL) would simplify things.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 20:47: Subject: Re: throw or return
Please don't use this syntax There is no gain at all when compared to the current system.
/ Per Hedbor ()
Who said it should be limited to looking at constants in the error objects (or using inheritance, which has the same expressive power)? I made a point that the catch conditions should be more powerful than that. As for categorizations, constants or a class hierarchy are both well suited to solve that.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-01 21:00: Subject: Re: throw or return
I didn't say I wanted that syntax. It just looks very clumsy to look at the presence of constants in an object. E.g. it could be nice to categorize errors into system errors, c-level errors and pike errors, and then be able to catch only pike-level errors. One could have native-pike-module, application-specific-module and application as further clustering of the pike errors as well. To be able to use expressions like (e->level < APPLICATION_MODULE_LEVEL) would simplify things.
/ Martin Nilsson (saturator)
I just assumed that, since you used "case", which currently only handles constants. I would like to keep such constrains if possible to keep some sort of internal consistency. If one should be able to use expressions, as we appears to agree on, we should either use a known keyword that handles expressions or use a new one.
/ Martin Nilsson (saturator)
Previous text:
2003-10-01 21:37: Subject: Re: throw or return
Who said it should be limited to looking at constants in the error objects (or using inheritance, which has the same expressive power)? I made a point that the catch conditions should be more powerful than that. As for categorizations, constants or a class hierarchy are both well suited to solve that.
/ Martin Stjernholm, Roxen IS
Ineritance does not have the same expressive power. constants can be redefined, inheritance can not. When this came up originally (a long long time ago, in a galaxy far far away) constants were deemed better because exceptions are not nessesarily easily organized in trees.
/ Fredrik (Naranek) Hubinette (Real Build Master)
Previous text:
2003-10-01 21:37: Subject: Re: throw or return
Who said it should be limited to looking at constants in the error objects (or using inheritance, which has the same expressive power)? I made a point that the catch conditions should be more powerful than that. As for categorizations, constants or a class hierarchy are both well suited to solve that.
/ Martin Stjernholm, Roxen IS
Since multiple inheritance exist it's not necessary to organize the errors in a tree. There can be several class hierarchies for different aspects that build a grid-like structure when inherited together. That would however require a more careful design and a lot more classes.
/ Martin Stjernholm, Roxen IS
Previous text:
2003-10-02 00:50: Subject: Re: throw or return
Ineritance does not have the same expressive power. constants can be redefined, inheritance can not. When this came up originally (a long long time ago, in a galaxy far far away) constants were deemed better because exceptions are not nessesarily easily organized in trees.
/ Fredrik (Naranek) Hubinette (Real Build Master)
pike-devel@lists.lysator.liu.se