Exceptions/Catch an exception thrown in a nested call: Difference between revisions
(→{{header|Lasso}}: Output?) |
(→{{header|Lasso}}: Added stdout to code and output to example.) |
||
Line 1,267:
=={{header|Lasso}}==
Lasso currently does not currently have a try mechanic — but we can easily add one like so.
Line 1,277 ⟶ 1,276:
handle => {
// Only relay error if it's not the specified exception
if(#error
if(#error->get(2) == #exception) => {
stdoutnl('Handled exception: '+#error->get(2))
else
stdoutnl('Throwing exception: '+#error->get(2))
fail(:#error)
}
}
}
protect => {
Line 1,288 ⟶ 1,294:
define foo => {
stdoutnl('foo')
try('U0') => { bar }
try('U0') => { bar }
Line 1,293 ⟶ 1,300:
define bar => {
stdoutnl('- bar')
baz()
}
define baz => {
stdoutnl(' - baz')
var(bazzed) ? fail('U1') | $bazzed = true
fail('U0')
}</lang>
Output:
<lang Lasso>foo
- bar
- baz
Handled exception: U0
- bar
- baz
Throwing exception: U1</lang>
Error Stack:
13:2 error.lasso
38:19 Debugger
33:5 Debugger
28:20 Debugger
21:9 Debugger
18:9 Debugger
6:5 Debugger</lang>
=={{header|Lua}}==
|
Revision as of 11:10, 3 November 2013
You are encouraged to solve this task according to the task description, using any language you may know.
Show how to create a user-defined exception and show how to catch an exception raised from several nested calls away.
- Create two user-defined exceptions, U0 and U1.
- Have function foo call function bar twice.
- Have function bar call function baz.
- Arrange for function baz to raise, or throw exception U0 on its first call, then exception U1 on its second.
- Function foo should catch only exception U0, not U1.
Show/describe what happens when the program is run.
Ada
<lang ada>with Ada.Text_Io; use Ada.Text_Io;
procedure Exceptions_From_Nested_Calls is
U0 : exception; U1 : exception; Baz_Count : Natural := 0; procedure Baz is begin Baz_Count := Baz_Count + 1; if Baz_Count = 1 then raise U0; else raise U1; end if; end Baz; procedure Bar is begin Baz; end Bar; procedure Foo is begin Bar; exception when U0 => Put_Line("Procedure Foo caught exception U0"); end Foo;
begin
for I in 1..2 loop Foo; end loop;
end Exceptions_From_Nested_Calls;</lang> Sample output:
Procedure Foo caught exception U0 raised EXCEPTIONS_FROM_NESTED_CALLS.U1 : exceptions_from_nested_calls.adb:13
An unhandled exception leads to termination of the corresponding task. When the task is the main task of the program as in the example, the whole program is terminated. In the example the exception back tracing message is compiler-specific (in this case it is GNAT and further depends on the compiler options.
Aime
<lang aime>void baz(integer i, text &exception) {
exception = cat("U", itoa(i)); error(exception);
}
void bar(integer i, text &exception) {
baz(i, exception);
}
void foo(void) {
integer i;
i = 0; while (i < 2) {
text e;
if (trap(bar, i, e)) { o_text("Exception `"); o_text(e); o_text("' thrown\n"); if (!compare(e, "U1")) { o_text("will not catch exception\n"); error(e); } } i += 1;
}
o_text("Never reached.\n");
}
integer main(void) {
foo();
return 0;
}</lang>
- Output:
aime: tmp/nce: 5: U0 Exception `U0' thrown aime: tmp/nce: 5: U1 Exception `U1' thrown will not catch exception aime: tmp/nce: 29: U1
Exception U0 is caught, exception U1 is caught and re-thrown. Program execution is terminated as the U1 exception is not caught when thrown the second time.
ALGOL 68
The following example follows the method used by ALGOL 68 for handling events in the language's transput prelude. Note that in the transput, then exception is effectively bound to the file handle, hence different file events can be caught by event handler associated to that particular file. Similarly the following example has bound two unique exceptions - u0 & u1 - to each unique instance of object.
c.f. ALGOL 68 Exceptions for more details. <lang algol68>MODE OBJ = STRUCT(
INT value, STRUCT( STRING message, FLEX[0]STRING args, PROC(REF OBJ)BOOL u0, u1 ) exception
);
PROC on u0 = (REF OBJ self, PROC (REF OBJ) BOOL mended)VOID:
u0 OF exception OF self := mended;
PROC on u1 = (REF OBJ self, PROC (REF OBJ) BOOL mended)VOID:
u1 OF exception OF self := mended;
PRIO INIT = 1, RAISE = 1;
OP INIT = (REF OBJ self, INT value)REF OBJ: (
value OF self := value; u0 OF exception OF self := u1 OF exception OF self := (REF OBJ skip)BOOL: FALSE; args OF exception OF self := message OF exception OF self := "OBJ Exception"; self
);
OP RAISE = (REF OBJ self, PROC (REF OBJ) BOOL mended)VOID:
IF NOT mended(self) THEN put(stand error, (message OF exception OF self+" not caught - stop", new line)); stop FI;
PROC (REF OBJ)VOID bar, baz; # early declaration is required by the ALGOL 68RS subset language #
PROC foo := VOID:(
FOR value FROM 0 TO 1 DO REF OBJ i = LOC OBJ INIT value; on u0(i, (REF OBJ skip)BOOL: (GO TO except u0; SKIP )); bar(i); GO TO end on u0; except u0: print(("Function foo caught exception u0", new line)); end on u0: SKIP OD
);
- PROC # bar := (REF OBJ i)VOID:(
baz(i) # Nest those calls #
);
- PROC # baz := (REF OBJ i)VOID:
IF value OF i = 0 THEN i RAISE u0 OF exception OF i ELSE i RAISE u1 OF exception OF i FI;
foo</lang> Output:
Function foo caught exception u0 OBJ Exception not caught - stop
Note: when an event occurs there are three possible responses.
- return false - in which case the default action takes place.
- mend the object and return true - date is mended and the program can continue from the point the event was raised.
- jump to an appropriately named label - effectively abandoning the offending section of code.
In the case of parallel processing, if the label is outside of the par clause, then all parallel the threads are terminated and the program continues in the parent thread.
AutoHotkey
True exceptions
In AutoHotkey_L, Try, Catch, and Throw are available to handle exceptions.
When this program is run, the first exception (U0) is raised, and caught by the try-catch section. This causes a Message Box containing the text "An exception was raised: First Exception" to be displayed by the script. The second exception is not caught, generating a runtime error.
<lang AHK>global U0 := Exception("First Exception")
global U1 := Exception("Second Exception")
foo()
foo(){ try bar() catch e MsgBox % "An exception was raised: " e.Message bar() }
bar(){ baz() }
baz(){ static calls := 0 if ( ++calls = 1 ) throw U0 else if ( calls = 2 ) throw U1 }</lang> The runtime error:
Error: Second Exception Line# 019: calls := 0 001: U0 := Exception("First Exception") ---> 002: U1 := Exception("Second Exception") 004: foo() 006: { 007: Try 008: bar() 009: Catch,e 010: MsgBox,"An exception was raised: " e.Message 011: bar() The thread has exited.
ErrorLevel-based exceptions
AutoHotkey_Basic has very simple support for error tracking. The global ErrorLevel keeps track of the last error. Here is one way to keep track of nested errors: <lang AutoHotkey>foo() Return
foo() {
bar(0) If InStr(ErrorLevel, "U0") MsgBox caught error: U0 bar(1) If InStr(ErrorLevel, "U0") MsgBox caught error: U0
}
bar(i) {
StringReplace, ErrorLevel, ErrorLevel, baz_error, , All ; clear baz_error(s) If !baz(i) ErrorLevel .= "baz_error" ; add baz_error to errorstack
}
baz(i) {
StringReplace, ErrorLevel, ErrorLevel, U1, , All ; clear U1 errors StringReplace, ErrorLevel, ErrorLevel, U0, , All ; clear U0 errors If i ErrorLevel .= "U1" ; add U1 errors to errorstack Else ErrorLevel .= "U0" Return 1
}</lang>
BBC BASIC
<lang bbcbasic> REM Allocate error numbers:
U0& = 123 U1& = 124 PROCfoo END DEF PROCfoo ON ERROR LOCAL IF ERR = U0& THEN PRINT "Exception U0 caught in foo" ELSE \ \ RESTORE ERROR : ERROR ERR, REPORT$ PROCbar PROCbar ENDPROC DEF PROCbar PROCbaz ENDPROC DEF PROCbaz PRIVATE called% called% += 1 CASE called% OF WHEN 1: ERROR U0&, "Exception U0 thrown" WHEN 2: ERROR U1&, "Exception U1 thrown" ENDCASE ENDPROC
</lang> Output (the second message is output by the default error handler):
Exception U0 caught in foo Exception U1 thrown
C
C doesn't have exception handling. But that won't stop crazy people. <lang C>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- include <ucontext.h>
- define try push_handler(); if (!exc_string)
- define catch(e) pop_handler(e); for (; exc_string; exc_string = 0)
ucontext_t *exc; int exc_depth = 0; int exc_alloc = 0; const char * exc_string;
void throw(const char *str) {
exc_string = str; setcontext(exc + exc_depth - 1);
}
void push_handler() {
exc_string = 0; if (exc_alloc <= exc_depth) { exc_alloc += 16; exc = realloc(exc, sizeof(ucontext_t) * exc_alloc); } getcontext(exc + exc_depth++);
}
void pop_handler(const char *e) {
exc_depth --; if (exc_string && strcmp(e, exc_string)) { if (exc_depth > 0) throw(exc_string); fprintf(stderr, "Fatal: unhandled exception %s\n", exc_string); exit(1); }
}
/* try out the exception system */
void baz() {
static int count = 0; switch (count++) { case 0: throw("U0"); case 1: throw("U1"); case 2: throw("U2"); }
}
void foo() {
printf(" foo: calling baz\n"); try { baz(); } catch("U0") { printf(" foo: got exception U0; handled and dandy\n"); }
printf(" foo: finished\n");
}
int main() {
int i; for (i = 0; i < 3; i++) { printf("main: calling foo: %d\n", i); try { foo(); } catch("U1") { printf("main: Someone threw U1; handled and dandy\n"); } } return 0;
}</lang>Output:<lang>main: calling foo: 0
foo: calling baz foo: got exception U0; handled and dandy foo: finished
main: calling foo: 1
foo: calling baz
main: Someone threw U1; handled and dandy main: calling foo: 2
foo: calling baz
Unhandled exception U2</lang> Disclaimer: this is pure hackery, and any kind of bad thing could happen with it. You are not seriously going to use it.
C++
First exception will be caught and message will be displayed, second will be caught by the default exception handler, which as required by the C++ Standard, will call terminate(), aborting the task, typically with an error message.
<lang cpp>#include <iostream> class U0 {}; class U1 {};
void baz(int i) {
if (!i) throw U0(); else throw U1();
} void bar(int i) { baz(i); }
void foo() {
for (int i = 0; i < 2; i++) { try { bar(i); } catch(U0 e) {
std::cout<< "Exception U0 caught\n";
} }
}
int main() {
foo(); std::cout<< "Should never get here!\n"; return 0;
}</lang>
Result:
Exception U0 caught This application has requested the Runtime to terminate it in an unusual way.
The exact behavior for an uncaught exception is implementation-defined.
C#
This example will first catch U0 and print "U0 Caught" to the console when it does. The uncaught U1 exception will then cause the program to terminate and print the type of the exception, location of the error, and the stack.
<lang csharp>using System; //Used for Exception and Console classes class Exceptions {
class U0 : Exception { } class U1 : Exception { } static int i; static void foo() { for (i = 0; i < 2; i++) try { bar(); } catch (U0) { Console.WriteLine("U0 Caught"); } } static void bar() { baz(); } static void baz(){ if (i == 0) throw new U0(); throw new U1(); }
public static void Main() { foo(); }
}</lang>
Output:
U0 Caught Unhandled Exception: Exceptions+U1: Exception of type 'Exceptions+U1' was thrown. at Exceptions.baz() in Program.cs:line 27 at Exceptions.bar() in Program.cs:line 22 at Exceptions.foo() in Program.cs:line 14 at Exceptions.Main() in Program.cs:line 32
Common Lisp
<lang lisp>(define-condition user-condition-1 (error) ()) (define-condition user-condition-2 (error) ())
(defun foo ()
(dolist (type '(user-condition-1 user-condition-2)) (handler-case (bar type) (user-condition-1 (c) (format t "~&foo: Caught: ~A~%" c)))))
(defun bar (type)
(baz type))
(defun baz (type)
(error type)) ; shortcut for (error (make-condition type))
(trace foo bar baz) (foo)</lang>
Sample output (the numbered lines are output from trace
):
<lang lisp> 0: (FOO)
1: (BAR USER-CONDITION-1) 2: (BAZ USER-CONDITION-1)
foo: Caught: Condition USER-CONDITION-1 was signalled.
1: (BAR USER-CONDITION-2) 2: (BAZ USER-CONDITION-2)</lang>
At this point, the debugger (if any) is invoked with the unhandled condition of type USER-CONDITION-2.
D
First exception will be caught and message will be displayed, second will be caught by default exception handler. <lang d>class U0 : Exception {
this() @safe pure nothrow { super("U0 error message"); }
}
class U1 : Exception {
this() @safe pure nothrow { super("U1 error message"); }
}
void foo() {
import std.stdio;
foreach (immutable i; 0 .. 2) { try { i.bar; } catch (U0) { "Function foo caught exception U0".writeln; } }
}
void bar(in int i) @safe pure {
i.baz;
}
void baz(in int i) @safe pure {
throw i ? new U1 : new U0;
}
void main() {
foo;
}</lang>
- Output:
test.U1(at)test.d(8): U1 error message ---------------- \test.d(20): pure void test.bar(int) \test.d(25): void test.baz() \test.d(33): _Dmain ---------------- Exception U0 caught
Delphi
<lang delphi>program ExceptionsInNestedCall;
{$APPTYPE CONSOLE}
uses SysUtils;
type
U0 = class(Exception) end; U1 = class(Exception) end;
procedure Baz(i: Integer); begin
if i = 0 then raise U0.Create('U0 Error message') else raise U1.Create('U1 Error message');
end;
procedure Bar(i: Integer); begin
Baz(i);
end;
procedure Foo; var
i: Integer;
begin
for i := 0 to 1 do begin try Bar(i); except on E: U0 do Writeln('Exception ' + E.ClassName + ' caught'); end; end;
end;
begin
Foo;
end.</lang>
Output:
Exception U0 caught
The uncaught exception shows a Windows Error Report dialog.
DWScript
First exception will be caught and message will be displayed, second will be caught by default exception handler. <lang delphi>type Exception1 = class (Exception) end; type Exception2 = class (Exception) end;
procedure Baz(i : Integer); begin
if i=0 then raise new Exception1('Error message 1') else raise new Exception2('Error message 2');
end;
procedure Bar(i : Integer); begin
Baz(i);
end;
procedure Foo; var
i : Integer;
begin
for i:=0 to 2 do begin try Bar(i); except on E : Exception1 do PrintLn(E.ClassName+' caught'); end; end;
end;
Foo;</lang> Result:
Exception1 caught User defined exception: Error message 2
Eiffel
version 2.4
A file called main.e: <lang eiffel>class MAIN
inherit EXCEPTIONS
creation foo
feature {ANY}
baz_calls: INTEGER
feature foo is do Current.bar rescue if is_developer_exception_of_name("U0") then baz_calls := 1 print("Caught U0 exception.%N") retry end if is_developer_exception then print("Won't catch ") print(developer_exception_name) print(" exception...%N") end end
feature bar is do Current.baz end
feature baz is do if baz_calls = 0 then raise("U0") else raise("U1") end end
end</lang>
Sample output:
Caught U0 exception. Won't catch U1 exception... Exception number 3 not handled. Developer exception: 3 frames in current stack. ===== Bottom of run-time stack ===== <system root> Current = MAIN#0x8068038 [ baz_calls = 1 ] line 9 column 13 file ./main.e ====================================== foo MAIN Current = MAIN#0x8068038 [ baz_calls = 1 ] line 21 column 17 file ./main.e ==== Rescue stack ================= bar MAIN Current = MAIN#0x8068038 [ baz_calls = 1 ] line 27 column 21 file ./main.e ===== Top of run-time stack ===== Exception number 3 not handled. Developer exception:
EGL
<lang EGL>record U0 type Exception end
record U1 type Exception end
program Exceptions
function main() foo(); end
function foo() try bar(); onException(ex U0) SysLib.writeStdout("Caught a U0 with message: '" :: ex.message :: "'"); end bar(); end
function bar() baz(); end
firstBazCall boolean = true; function baz() if(firstBazCall) firstBazCall = false; throw new U0{message = "This is the U0 exception"}; else throw new U1{message = "This is the U1 exception"}; end end
end</lang>
Output:
Caught a U0 with message: 'This is the U0 exception' This is the U1 exception
Erlang
<lang Erlang> -module( exceptions_catch ).
-export( [task/0] ).
task() -> [foo(X) || X<- lists:seq(1, 2)].
baz( 1 ) -> erlang:throw( u0 ); baz( 2 ) -> erlang:throw( u1 ).
foo( N ) -> try baz( N )
catch _:u0 -> io:fwrite( "Catched ~p~n", [u0] )
end. </lang>
- Output:
76> exceptions_catch:task(). Catched u0 ** exception throw: u1 in function exceptions_catch:baz/1 (src/exceptions_catch.erl, line 10) in call from exceptions_catch:foo/1 (src/exceptions_catch.erl, line 14) in call from exceptions_catch:'-task/0-lc$^0/1-0-'/1 (src/exceptions_catch.erl, line 5) in call from exceptions_catch:'-task/0-lc$^0/1-0-'/1 (src/exceptions_catch.erl, line 5)
Fantom
<lang fantom> const class U0 : Err {
new make () : super ("U0") {}
}
const class U1 : Err {
new make () : super ("U1") {}
}
class Main {
Int bazCalls := 0
Void baz () { bazCalls += 1 if (bazCalls == 1) throw U0() else throw U1() }
Void bar () { baz () }
Void foo () { 2.times { try { bar () } catch (U0 e) { echo ("Caught U0") } } }
public static Void main () { Main().foo }
} </lang>
Output:
Caught U0 nestedexceptions_0::U1: U1 nestedexceptions_0::U1.<init> (nested-exceptions.fan) nestedexceptions_0::U1.make (nested-exceptions.fan:9) nestedexceptions_0::Main.baz (nested-exceptions.fan:22) nestedexceptions_0::Main.bar (nested-exceptions.fan:27) nestedexceptions_0::Main.foo (nested-exceptions.fan:36) fan.sys.FanInt.times (FanInt.java:492) nestedexceptions_0::Main.foo (nested-exceptions.fan:33) nestedexceptions_0::Main.main (nested-exceptions.fan:47) java.lang.reflect.Method.invoke (Method.java:597) fan.sys.Method.invoke (Method.java:552) fan.sys.Method$MethodFunc.callList (Method.java:198) fan.sys.Method.callList (Method.java:138) fanx.tools.Fan.callMain (Fan.java:135) fanx.tools.Fan.executeFile (Fan.java:88) fanx.tools.Fan.execute (Fan.java:34) fanx.tools.Fan.run (Fan.java:250) fanx.tools.Fan.main (Fan.java:288)
The output shows the first exception is caught and handled. The second exception is not handled, and results in the program finishing and printing a stack trace.
Go
Not strictly conforming to task description as foo does not directly call bar.
The panic/recover mechanism of Go is missing (by design) some elements of exception handling needed for this task. Specifically, a function that recovers a panic cannot resume execution of the remainder of the function. If foo recovers a panic in the first call to bar, there is no way for it to make the second call to bar. The solution here is to define a wrapper, or proxy function, called try. Function foo calls bar indirectly through try. <lang go>// Outline for a try/catch-like exception mechanism in Go // // As all Go programmers should know, the Go authors are sharply critical of // the try/catch idiom and consider it bad practice in general. // See http://golang.org/doc/go_faq.html#exceptions
package main
import (
"fmt" "runtime" "strings"
)
// trace is for pretty output for the Rosetta Code task. // It would have no place in a practical program. func trace(s string) {
nc := runtime.Callers(2, cs) f := runtime.FuncForPC(cs[0]) fmt.Print(strings.Repeat(" ", nc-3), f.Name()[5:], ": ", s, "\n")
}
var cs = make([]uintptr, 10)
type exception struct {
name string handler func()
}
// try implents the try/catch-like exception mechanism. It takes a function // to be called, and a list of exceptions to catch during the function call. // Note that for this simple example, f has no parameters. In a practical // program it might, of course. In this case, the signature of try would // have to be modified to take these parameters and then supply them to f // when it calls f. func try(f func(), exs []exception) {
trace("start") defer func() { if pv := recover(); pv != nil { trace("Panic mode!") if px, ok := pv.(exception); ok { for _, ex := range exs { if ex.name == px.name { trace("handling exception") px.handler() trace("panic over") return } } } trace("can't recover this one!") panic(pv) } }() f() trace("complete")
}
func main() {
trace("start") foo() trace("complete")
}
// u0, u1 declared at package level so they can be accessed by any function. var u0, u1 exception
// foo. Note that function literals u0, u1 here in the lexical scope // of foo serve the purpose of catch blocks of other languages. // Passing u0 to try serves the purpose of the catch condition. // While try(bar... reads much like the try statement of other languages, // this try is an ordinary function. foo is passing bar into try, // not calling it directly. func foo() {
trace("start") u0 = exception{"U0", func() { trace("U0 handled") }} u1 = exception{"U1", func() { trace("U1 handled") }} try(bar, []exception{u0}) try(bar, []exception{u0}) trace("complete")
}
func bar() {
trace("start") baz() trace("complete")
}
var bazCall int
func baz() {
trace("start") bazCall++ switch bazCall { case 1: trace("panicking with execption U0") panic(u0) case 2: trace("panicking with execption U1") panic(u1) } trace("complete")
}</lang> Output:
main: start foo: start try: start bar: start baz: start baz: panicking with execption U0 _func_001: Panic mode! _func_001: handling exception _func_002: U0 handled _func_001: panic over try: start bar: start baz: start baz: panicking with execption U1 _func_001: Panic mode! _func_001: can't recover this one! panic: (main.exception) (0x468040,0xf8400273c0) [recovered] panic: (main.exception) (0x468040,0xf8400273c0) goroutine 1 [running]: main._func_001(0x2af727232f20, 0x2af727232100, 0x2af727232fb8, 0x2af727232e70) t.go:52 +0x1d9 ----- stack segment boundary ----- main.baz() t.go:100 +0xd1 main.bar() t.go:85 +0x31 main.try(0x40105b, 0x2af727232f68, 0x100000001, 0x478dec) t.go:55 +0x4f main.foo() t.go:79 +0x16c main.main() t.go:61 +0x31
Haskell
<lang haskell>import Control.Monad.Error import Control.Monad.Trans (lift)
-- Our "user-defined exception" tpe data MyError = U0 | U1 | Other deriving (Eq, Read, Show)
-- Required for any error type instance Error MyError where
noMsg = Other strMsg _ = Other
-- Throwing and catching exceptions implies that we are working in a monad. In -- this case, we use ErrorT to support our user-defined exceptions, wrapping -- IO to be able to report the happenings. ('lift' converts ErrorT e IO a -- actions into IO a actions.)
foo = do lift (putStrLn "foo")
mapM_ (\toThrow -> bar toThrow -- the protected call `catchError` \caught -> -- the catch operation -- ↓ what to do with it case caught of U0 -> lift (putStrLn "foo caught U0") _ -> throwError caught) [U0, U1] -- the two exceptions to throw
bar toThrow = do lift (putStrLn " bar")
baz toThrow
baz toThrow = do lift (putStrLn " baz")
throwError toThrow
-- We cannot use exceptions without at some outer level choosing what to do -- if an exception propagates all the way up. Here we just print the exception -- if there was one. main = do result <- runErrorT foo
case result of Left e -> putStrLn ("Caught error at top level: " ++ show e) Right v -> putStrLn ("Return value: " ++ show v)</lang>
The output of this program is:
foo bar baz foo caught U0 bar baz Caught error at top level: U1
Icon and Unicon
The following Unicon example makes use of support for exceptions found in the The Unicon Code Library. Since exception support is not built into Unicon, but rather implemented as Unicon code, there are limitations not found in languages that natively support exceptions.
<lang Unicon>import Exceptions
class U0 : Exception()
method getMessage() return "U0: " || (\message | "unknown") end
end
class U1 : Exception()
method getMessage() return "U1: " || (\message | "unknown") end
end
procedure main()
# (Because Exceptions are not built into Unicon, uncaught # exceptions are ignored. This clause will catch any # exceptions not caught farther down in the code.) case Try().call{ foo() } of { Try().catch(): { ex := Try().getException() write(ex.getMessage(), ":\n", ex.getLocation()) } }
end
procedure foo()
every 1|2 do { case Try().call{ bar() } of { Try().catch("U0"): { ex := Try().getException() write(ex.getMessage(), ":\n", ex.getLocation()) } } }
end
procedure bar()
return baz()
end
procedure baz()
initial U0().throw("First exception") U1().throw("Second exception")
end</lang>
When run, this example produces:
U0: First exception: procedure baz [Etest5.icn:43] procedure bar [Etest5.icn:39] procedure foo [Etest5.icn:29] U1: Second exception: procedure baz [Etest5.icn:44] procedure bar [Etest5.icn:39] procedure foo [Etest5.icn:29]
Note: it may be possible to implement exceptions in Icon; however, it would require a major rework and would likely be inelegant.
J
Solution:
J leaves most of the implementation of exceptions to the programmer, so:
<lang J>main=: monad define
smoutput 'main' try. foo catcht. smoutput 'main caught ',type_jthrow_ end.
)
foo=: monad define
smoutput ' foo' for_i. 0 1 do. try. bar i catcht. if. type_jthrow_-:'U0' do. smoutput ' foo caught ',type_jthrow_ else. throw. end. end. end.
)
bar=: baz [ smoutput bind ' bar'
baz=: monad define
smoutput ' baz' type_jthrow_=: 'U',":y throw.
)</lang>
Example use: <lang j> main main
foo bar baz foo caught U0 bar baz
main caught U1</lang>
Java
Methods that may throw an exception (or that call a method that may throw an exception that it does not catch) must explicitly declare that they can throw such an exception (or a superclass thereof), unless they are unchecked exceptions (subclasses of RuntimeException
or Error
):
<lang java>class U0 extends Exception { }
class U1 extends Exception { }
public class ExceptionsTest {
public static void foo() throws U1 { for (int i = 0; i <= 1; i++) { try { bar(i); } catch (U0 e) { System.out.println("Function foo caught exception U0"); } } }
public static void bar(int i) throws U0, U1 { baz(i); // Nest those calls }
public static void baz(int i) throws U0, U1 { if (i == 0) throw new U0(); else throw new U1(); }
public static void main(String[] args) throws U1 { foo(); }
}</lang> Sample output:
Function foo caught exception U0 Exception in thread "main" U1 at ExceptionsTest.baz(ExceptionsTest.java:23) at ExceptionsTest.bar(ExceptionsTest.java:16) at ExceptionsTest.foo(ExceptionsTest.java:8) at ExceptionsTest.main(ExceptionsTest.java:27)
The first line of the output is generated from catching the U0 exception in function foo.
Uncaught exceptions give information showing where the exception originated through the nested function calls together with the name of the uncaught exception, (U1) to stderr, then quit the running program.
JavaScript
except for the print() function
The callee.name
property, and the catch(e if ...)
statement are Mozilla JavaScript extensions.
<lang javascript>function U() {} U.prototype.toString = function(){return this.className;}
function U0() {
this.className = arguments.callee.name;
} U0.prototype = new U();
function U1() {
this.className = arguments.callee.name;
} U1.prototype = new U();
function foo() {
for (var i = 1; i <= 2; i++) { try { bar(); } catch(e if e instanceof U0) { print("caught exception " + e); } }
}
function bar() {
baz();
}
function baz() {
// during the first call, redefine the function for subsequent calls baz = function() {throw(new U1());} throw(new U0());
}
foo();</lang> Rhino output:
caught exception U0 js: "nested_calls.js", line 31: exception from uncaught JavaScript throw: U1
SpiderMonkey output:
caught exception U0 uncaught exception: U1
Lasso
Lasso currently does not currently have a try mechanic — but we can easily add one like so.
<lang Lasso>define try(exception) => {
local( gb = givenblock, error ) handle => { // Only relay error if it's not the specified exception if(#error) => { if(#error->get(2) == #exception) => { stdoutnl('Handled exception: '+#error->get(2)) else stdoutnl('Throwing exception: '+#error->get(2)) fail(:#error) } } } protect => { handle_error => { #error = (:error_code,error_msg,error_stack) } #gb() }
}
define foo => {
stdoutnl('foo') try('U0') => { bar } try('U0') => { bar }
}
define bar => {
stdoutnl('- bar') baz()
}
define baz => {
stdoutnl(' - baz') var(bazzed) ? fail('U1') | $bazzed = true fail('U0')
}</lang>
Output:
<lang Lasso>foo - bar - baz Handled exception: U0 - bar - baz Throwing exception: U1</lang>
Error Stack:
<lang Lasso>U1 13:2 error.lasso 38:19 Debugger 33:5 Debugger 28:20 Debugger 21:9 Debugger 18:9 Debugger 6:5 Debugger</lang>
Lua
<lang Lua>local baz_counter=1 function baz()
if baz_counter==1 then baz_counter=baz_counter+1 error("U0",3)--3 sends it down the call stack. elseif baz_counter==2 then error("U1",3)--3 sends it down the call stack. end
end
function bar()
baz()
end
function foo()
function callbar() local no_err,result = pcall(bar) --pcall is a protected call which catches errors. if not no_err then --If there are no errors, pcall returns true. if not result:match("U0") then --If the error is not a U0 error, rethrow it. error(result,2) --2 is the distance down the call stack to send --the error. We want it to go back to the callbar() call. end end end callbar() callbar()
end
foo() </lang> output:
lua: errorexample.lua:31: U1 stack traceback: [C]: in function 'error' errorexample.lua:24: in function 'callbar' errorexample.lua:31: in function 'foo' errorexample.lua:34: in main chunk [C]: ?
Mathematica
<lang mathematica>foo[] := Catch[ bar[1]; bar[2]; ]
bar[i_] := baz[i];
baz[i_] := Switch[i,
1, Throw["Exception U0 in baz"];, 2, Throw["Exception U1 in baz"];]</lang>
Output:
foo[] -> Exception U0 in baz
MATLAB / Octave
<lang MATLAB>function exceptionsCatchNestedCall()
function foo()
try bar(1); bar(2); catch disp(lasterror); rethrow(lasterror); end
end
function bar(i) baz(i); end
function baz(i) switch i case 1 error('BAZ:U0','HAHAHAH'); case 2 error('BAZ:U1','AWWWW'); otherwise disp 'I cant do that Dave.'; end end
foo();
end</lang> Output: <lang MATLAB>>> exceptionsCatchNestedCall()
message: [1x177 char] identifier: 'BAZ:U0' stack: [4x1 struct]
??? Error using ==> exceptionsCatchNestedCall>baz at 21 HAHAHAH
Error in ==> exceptionsCatchNestedCall at 29
foo();</lang>
Nemerle
<lang Nemerle>using System; using System.Console;
namespace NestedExceptions {
public class U0 : Exception { public this() {base()} }
public class U1 : Exception { public this() {base()} }
module NestedExceptions { Foo () : void { mutable call = 0; repeat(2) { try { Bar(call); } catch { |e is U0 => WriteLine("Exception U0 caught.") } finally { call++; } } } Bar (call : int) : void { Baz(call) } Baz (call : int) : void // throw U0() on first call, U1() on second { unless (call > 0) throw U0(); when (call > 0) throw U1(); } Main () : void { Foo() } }
}</lang> Output:
Exception U0 caught. Unhandled Exception: NestedExceptions.U1: Exception of type 'NestedExceptions.U1' was thrown. at NestedExceptions.NestedExceptions.Baz(Int32 call) at NestedExceptions.NestedExceptions.Foo() at NestedExceptions.NestedExceptions.Main()
Objective-C
<lang objc>@interface U0 : NSObject { } @end @interface U1 : NSObject { } @end @implementation U0 @end @implementation U1 @end
void foo(); void bar(int i); void baz(int i);
void foo() {
for (int i = 0; i <= 1; i++) { @try { bar(i); } @catch (U0 *e) { NSLog(@"Function foo caught exception U0"); } }
}
void bar(int i) {
baz(i); // Nest those calls
}
void baz(int i) {
if (i == 0) @throw [[U0 new] autorelease]; else @throw [[U1 new] autorelease];
}
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
foo();
[pool drain]; return 0;
}</lang> Sample output:
2011-06-03 23:11:53.871 Untitled[9968:903] Function foo caught exception U0 2011-06-03 23:11:53.878 Untitled[9968:903] *** Terminating app due to uncaught exception of class 'U1'
OCaml
<lang ocaml>exception U0 exception U1
let baz i =
raise (if i = 0 then U0 else U1)
let bar i = baz i (* Nest those calls *)
let foo () =
for i = 0 to 1 do try bar i with U0 -> print_endline "Function foo caught exception U0" done
let () = foo ()</lang> Sample output:
Function foo caught exception U0 Exception: U1.
Oz
Any value can be raised as an exception. In this example, we simply use atoms.
Exceptions are caught by pattern matching. <lang oz>declare
proc {Foo} for I in 1..2 do try {Bar I} catch u0 then {System.showInfo "Procedure Foo caught exception u0"} end end end
proc {Bar I} {Baz I} end
proc {Baz I} if I == 1 then raise u0 end else raise u1 end end end
in
{Foo}</lang>
Sample output:
Procedure Foo caught exception u0 %**************************************************************** %** %** Error: unhandled exception %** %** u1 %**--------------------------------------------------------------
Pascal
See Delphi
Perl
Note: Both exceptions are caught and one is re-raised rather than only one being caught. <lang perl>sub foo {
foreach (0..1) { eval { bar($_) }; if ($@ =~ /U0/) { print "Function foo caught exception U0\n"; } else { die; } # propagate the exception }
}
sub bar {
baz(@_); # Nest those calls
}
sub baz {
my $i = shift; die ($i ? "U1" : "U0");
}
foo();</lang> Sample output:
Function foo caught exception U0 U1 at exceptionsnested.pl line 15. ...propagated at exceptionsnested.pl line 5.
Perl 6
<lang perl6>sub foo() {
for 0..1 -> $i { bar $i; CATCH { when /U0/ { say "Function foo caught exception U0" } } }
}
sub bar($i) { baz $i }
sub baz($i) { die "U$i" }
foo;</lang>
- Output:
Function foo caught exception U0 U1 in sub baz at catch:12 in sub bar at catch:10 in sub foo at catch:4 in block at catch:14
PicoLisp
<lang PicoLisp>(de foo ()
(for Tag '(U0 U1) (catch 'U0 (bar Tag) ) ) )
(de bar (Tag)
(baz Tag) )
(de baz (Tag)
(throw Tag) )
(mapc trace '(foo bar baz)) (foo)</lang> Output:
foo : bar : U0 baz : U0 bar : U1 baz : U1 [x:13] !? (throw Tag) U1 -- Tag not found ? # Debug prompt
PL/I
<lang PL/I> /* Exceptions: Catch an exception thrown in a nested call */ test: proc options (main);
/* 8/1/2011 */ declare (m, n) fixed initial (2); declare (U0, U1) condition;
foo: procedure () returns (fixed);
on condition(U0) snap begin; put list ('Raised condition U0 in function <bar>.'); put skip; end; m = bar(); m = bar(); return (m);
end foo;
bar: procedure () returns (fixed);
n = n + 1; return (baz()); return (n);
end bar; baz: procedure () returns (fixed);
declare first bit(1) static initial ('1'b); n = n + 1; if first then do; first = '0'b; signal condition(U0); end; else signal condition(U1); return (n);
end baz;
m = foo();
end test; </lang>
DESCRIPTION OF EXECUTION:
Function FOO is invoked. FOO invokes BAR. BAR invoked BAZ. In BAZ, exception UO is raised, and is handled in FOO, which outputs a message and a traceback is produced. Upon return to BAZ, BAZ terminates, and control returns to FOO. In FOO, BAR is invoked a second time, which in turn invokes BAZ. This (second) time that BAZ is invoked, the exception U1 is raised. As this exception is defined in the outer procedure TEST, a diagnostic and traceback are produced, and execution resumes in BAZ, returns to BAR, and then to FOO. Finally, a return is made to TEST and the program terminates. OUTPUT: CONDITION condition was raised At offset +000000E0 in procedure with entry FOO From offset +0000007C in procedure with entry TEST Raised condition U0 in function <bar>. IBM0400I ONCODE=0500 The CONDITION condition was raised by a SIGNAL statement and the condition U1 was signaled. At offset +0000010D in procedure with entry FOO
Python
There is no extra syntax to add to functions and/or methods such as bar, to say what exceptions they may raise or pass through them: <lang python>class U0(Exception): pass class U1(Exception): pass
def foo():
for i in range(2): try: bar(i) except U0: print("Function foo caught exception U0")
def bar(i):
baz(i) # Nest those calls
def baz(i):
raise U1 if i else U0
foo()</lang> Sample output:
Function foo caught exception U0 Traceback (most recent call last): File "C:/Paddy3118/Exceptions_Through_Nested_Calls.py", line 17, in <module> foo() File "C:/Paddy3118/Exceptions_Through_Nested_Calls.py", line 7, in foo bar(i) File "C:/Paddy3118/Exceptions_Through_Nested_Calls.py", line 12, in bar baz(i) # Nest those calls File "C:/Paddy3118/Exceptions_Through_Nested_Calls.py", line 15, in baz raise U1 if i else U0 U1
The first line of the output is generated from catching the U0 exception in function foo.
Uncaught exceptions give information showing where the exception originated through the nested function calls together with the name of the uncaught exception, (U1) to stderr, then quit the running program.
R
The counter for the number of calls to baz is kept in the global environment for simplicity, but you could hide it in your own environment. See ?new.env and ?get. <lang r> number_of_calls_to_baz <- 0
foo <- function() {
for(i in 1:2) tryCatch(bar())
}
bar <- function() baz()
baz <- function() {
e <- simpleError(ifelse(number_of_calls_to_baz > 0, "U1", "U0")) assign("number_of_calls_to_baz", number_of_calls_to_baz + 1, envir=globalenv()) stop(e)
} </lang> Example Usage: <lang r> foo() # Error: U0 traceback() </lang>
6: stop(e) at file.r#11 5: baz() 4: bar() 3: tryCatchList(expr, classes, parentenv, handlers) 2: tryCatch(bar()) at file.r#4 1: foo()
Racket
<lang racket>
- lang racket
(define-struct (exn:U0 exn) ()) (define-struct (exn:U1 exn) ())
(define (foo)
(for ([i 2]) (with-handlers ([exn:U0? (λ(_) (displayln "Function foo caught exception U0"))]) (bar i))))
(define (bar i)
(baz i))
(define (baz i)
(if (= i 0) (raise (make-exn:U0 "failed 0" (current-continuation-marks))) (raise (make-exn:U1 "failed 1" (current-continuation-marks)))))
(foo) </lang> Output: <lang racket> Function foo caught exception U0 . . failed 1 </lang>
REXX
While the REXX language doesn't have a throw capability pe se, it does have the ability to catch exceptions (by label).
This type of exception handling (in REXX) has its limitation (the label is local to the program, not external subroutines).
<lang rexx>/*REXX program to create two exceptions & demonstrate how to handle them*/
call foo /*invoke the FOO function. */
say 'mainline program is done.' /*indicate that Elroy was here. */
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────FOO function────────────────────────*/ foo: call bar; call bar /*invoke BAR function twice. */
return 0 /*return a zero to invoker. */
U0: say 'exception U0 caught in FOO' /*handle the U0 exception. */ return -2 /*return to the invoker. */
/*──────────────────────────────────BAR function────────────────────────*/ bar: call baz /*have BAR invoke BAZ function. */
return 0 /*return a zero to invoker. */
/*──────────────────────────────────BAZ function────────────────────────*/ baz: if symbol('BAZ#')=='LIT' then baz#=0 /*initialize BAZ invocation#*/
baz# = baz#+1 /*bump the BAZ invocation # by 1.*/ if baz#==1 then signal U0 /*if first invocation, raise U0 */ if baz#==2 then signal U1 /* " second " " U1 */ return 0 /*return a zero to invoker. */
U0: return -1 /*handle exception if not caught.*/ U1: return -1 /* " " " " " */</lang> output
exception U0 caught in FOO mainline program is done.
Ruby
Uses a global variable to count the number of calls to baz <lang ruby>def foo
begin bar rescue U0 puts "captured exception U0" end
end
def bar
baz
end
def baz
raise $bazcount == 1 ? U0 : U1
end
class U0 < Exception end
class U1 < Exception end
for $bazcount in [1, 2]
foo
end</lang>
$ ruby nested_calls.rb captured exception U0 nested_calls.rb:14:in `baz': U1 (U1) from nested_calls.rb:10:in `bar' from nested_calls.rb:3:in `foo' from nested_calls.rb:24 from nested_calls.rb:23:in `each' from nested_calls.rb:23
Wait, why does in `each'
appear in the stack trace? There's no each in that code. Ruby translates this
<lang ruby>for $bazcount in [1, 2]
foo
end</lang> to this <lang ruby>[1, 2].each {|$bazcount| foo}</lang>
Smalltalk
functional code, not class based, using blocks as functions, and anonymous exceptions (signals): <lang Smalltalk>| u0 u1 foo bar baz|
u0 := Signal new. u1 := Signal new.
foo := [
2 timesRepeat:[ [ bar value ] on: u0 do:[ 'u0 cought' printCR ] ] ].
bar := [
baz value ].
baz := [
|alreadyCalled|
[ alreadyCalled isNil ifTrue:[ alreadyCalled := true. u0 raise ] ifFalse:[ u1 raise ] ] ] value.
foo value </lang>
"traditional" implementation, using class based exceptions, and method invocations:
<lang Smalltalk>Exception
subclass: #U0 instanceVariableNames: classVariableNames: poolDictionaries: category:'example'.
Exception
subclass: #U1 instanceVariableNames: classVariableNames: poolDictionaries: category:'example'.
Object
subclass: #CatchMeIfYouCan instanceVariableNames:'bazAlreadyCalled' classVariableNames: poolDictionaries: category:'example'.
" CatchMeIfYouCan methods "
foo
2 timesRepeat:[ [ self bar ] on: U0 do:[ 'U0 cought' printCR ] ]
bar
self baz
baz
bazAlreadyCalled isNil ifTrue:[ bazAlreadyCalled := true. U0 raise ] ifFalse:[ U1 raise ]
CatchMeIfYouCan new foo</lang>
Tcl
Note: Both exceptions are caught and one is re-raised rather than only one being caught.
<lang tcl>package require Tcl 8.5
proc foo {} {
set code [catch {bar} ex options] if {$code == 1} { switch -exact -- $ex { U0 {puts "caught exception U0"} default {return -options $options $ex ;# re-raise exception} } }
}
proc bar {} {baz}
- create an alias to pass the initial exception U0 to the baz proc
interp alias {} baz {} _baz U0
proc _baz {exception} {
# re-set the alias so subsequent invocations will use exception U1 interp alias {} baz {} _baz U1 # throw return -code error $exception
}
foo foo</lang> Running this program results in:
$ tclsh85 exceptions.tcl caught exception U0 U1 while executing "baz" (procedure "bar" line 1) invoked from within "bar" (procedure "foo" line 2) invoked from within "foo" (file "exceptions.tcl" line 26)
TXR
<lang txr>@(defex u0) @(defex u1) @(define baz (x)) @ (cases) @ (bind x "0") @ (throw u0 "text0") @ (or) @ (bind x "1") @ (throw u1 "text1") @ (end) @(end) @(define bar (x)) @ (baz x) @(end) @(define foo ()) @ (next `!echo "0\n1\n"`) @ (collect) @num @ (try) @ (bar num) @ (catch u0 (arg)) @ (output) caught u0: @arg @ (end) @ (end) @ (end) @(end) @(foo)</lang>
Run:
$ txr except.txr caught u0: text0 txr: unhandled exception of type u1: txr: ((t . "text1")) Aborted
Ursala
Foo calls bar, and bar calls baz. Normal termination of bar is bypassed if baz raises an exception. The exception is caught or not by foo. <lang Ursala>#import std
baz =
~&?(
~&h?( :/'baz succeeded with this input:', <'baz threw a user-defined empty string exception','U1'>!%), <'baz threw a user-defined empty file exception','U0'>!%)
bar = :/'bar received this result from normal termination of baz:'+ baz
- executable&
foo =
guard(
:/'foo received this result from normal termination of bar:'+ bar, 'U0'?=z/~& :/'foo caught an exception with this error message:')</lang>
Note that the definition of bar includes no conditional (?) or exception handling operators, and is written without regard for any exceptions. Here is an example bash session.
$ echo "valid input" | foo foo received this result from normal termination of bar: bar received this result from normal termination of baz: baz succeeded with this input: valid input $ foo < /dev/null baz threw a user-defined empty file exception U0 $ echo "" | foo foo caught an exception with this error message: baz threw a user-defined empty string exception U1
- Programming Tasks
- Solutions by Programming Task
- Ada
- Aime
- Aime examples needing attention
- Examples needing attention
- ALGOL 68
- AutoHotkey
- Autohotkey examples needing attention
- BBC BASIC
- C
- C examples needing attention
- C++
- C sharp
- Common Lisp
- D
- Delphi
- DWScript
- Eiffel
- EGL
- EGL examples needing attention
- Erlang
- Fantom
- Go
- Haskell
- Unicon
- J
- Java
- JavaScript
- Lasso
- Lua
- Mathematica
- MATLAB
- Octave
- Nemerle
- Objective-C
- OCaml
- Oz
- Pascal
- Perl
- Perl 6
- PicoLisp
- PL/I
- Python
- R
- Racket
- REXX
- Ruby
- Smalltalk
- Tcl
- TXR
- Ursala
- C/Omit
- GUISS/Omit
- M4/Omit
- Retro/Omit