Exception handling syntax

From Infogalactic: the planetary knowledge core
Jump to: navigation, search

Exception handling syntax varies between programming languages, partly to cover semantic differences but largely to fit into each language's overall syntactic structure. Some languages do not call the relevant concept 'exception handling'; others may not have direct facilities for it, but can still provide means for implementing it.

Most commonly, error handling uses a try...[catch...][finally...] block, and errors are created via a throw statement, but there is significant variation in naming and syntax.

Catalogue of exception handling syntaxes

Ada

Exception declarations
Some_Error : exception;
Raising exceptions
raise Some_Error;

raise Some_Error with "Out of memory"; -- specific diagnostic message
Exception handling and propagation
with Ada.Exceptions, Ada.Text_IO;

procedure Foo is
  Some_Error : exception;
begin
  Do_Something_Interesting;
exception -- Start of exception handlers
  when Constraint_Error =>
    ... -- Handle constraint error
  when Storage_Error =>
    -- Propagate Storage_Error as a different exception with a useful message
    raise Some_Error with "Out of memory";
  when Error : others => 
    -- Handle all others
    Ada.Text_IO.Put("Exception: ");
    Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Name(Error));
    Ada.Text_IO.Put_Line(Ada.Exceptions.Exception_Message(Error));
end Foo;

Assembly language

Most assembly languages will have a macro instruction or an interrupt address available for the particular system to intercept events such as illegal op codes, program check, data errors, overflow, divide by zero, and other such. IBM and Univac mainframes had the STXIT macro. Digital Equipment Corporation RT11 systems had trap vectors for program errors, i/o interrupts, and such. MS-DOS has certain interrupt addresses. Microsoft Windows has specific module calls to trap program errors.

Bash

#!/usr/bin/env bash
#set -e provides another error mechanism
print_error(){
	echo "there was an error"
}
trap print_error exit #list signals to trap
tempfile=`mktemp`
trap "rm $tempfile" exit
./other.sh || echo warning: other failed
echo oops)
echo never printed

One can set a trap for multiple errors, responding to any signal with syntax like:

trap 'echo Error at line ${LINENO}' ERR

BASIC

An On Error goto/gosub structure is used in BASIC and is quite different from modern exception handling; in BASIC there is only one global handler whereas in modern exception handling, exception handlers are stacked.

ON ERROR GOTO handler
OPEN "Somefile.txt" FOR INPUT AS #1
CLOSE #1
PRINT "File opened successfully"
END

handler:
PRINT "File does not exist"
END  ' RESUME may be used instead which returns control to original position.

C

The most common way to implement exception handling in standard C is to use setjmp/longjmp functions:

#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>

enum { SOME_EXCEPTION = 1 } exception;
jmp_buf state;

int main(void)
{
  if(!setjmp(state))                      // try
  {
    if(/* something happened */)
    {
      exception = SOME_EXCEPTION;
      longjmp(state, 0);                  // throw SOME_EXCEPTION
    }
  } 
  else switch(exception)
  {             
    case SOME_EXCEPTION:                  // catch SOME_EXCEPTION
      puts("SOME_EXCEPTION caught");
      break;
    default:                              // catch ...
      puts("Some strange exception");
  }
  return EXIT_SUCCESS;
}

Microsoft-specific

Microsoft-specific exception handling mechanisms:

  • Structured Exception Handling (SEH)
  • Vectored Exception Handling (VEH, introduced in Windows XP)

Example of SEH in C programming language:

int filterExpression (EXCEPTION_POINTERS* ep) {
   ++ep->ContextRecord->Eip;
   return EXCEPTION_CONTINUE_EXECUTION;
}
int main(void) {
   static int zero;
   __try {
       zero = 1/zero;
       printf ("Past the exception.\n");
   } __except (filterExpression (GetExceptionInformation())) {
       printf ("Handler called.\n");
   }
   return 0;
}

C#

public static void Main()
{
   try
   {
      // Code that could throw an exception
   }
   catch(System.Net.WebException ex)
   {
      // Process a WebException
   }
   catch(System.Exception)
   {
      // Process a System level CLR exception, that is not a System.Net.WebException,
      // since the exception has not been given an identifier it cannot be referenced
   }
   catch
   {
      // Process a non-CLR exception
   }
   finally
   {
      // (optional) code that will *always* execute
   }
}

C++

#include <exception>
int main() {
   try {
       // do something (might throw an exception)
   }
   catch (const std::exception& e) {
        // handle exception e
   }
   catch (...) {
        // catches all exceptions, not already caught by a catch block before
        // can be used to catch exception of unknown or irrelevant type
   }
}

In C++, a resource acquisition is initialization technique can be used to clean up resources in exceptional situations. C++ intentionally does not support finally.[1] Note that the outer braces for the method are optional.

CFML

Script Syntax

<cfscript>
try {
	//throw CF9+
	throw(type="TypeOfException", message="Oops", detail="xyz");
	// alternate throw syntax:
	throw "Oops"; // this equivalent to the "message" value in the above example
} catch (any e) {
	writeOutput("Error: " & e.message);
	rethrow; //CF9+
} finally { //CF9+
	writeOutput("I run even if no error");
}
</cfscript>

Adobe ColdFusion Documentation [2]

Tag Syntax

<cftry> 
    code that may cause an exception 
    <cfcatch ...> 
        <cftry> 
            First level of exception handling code 
            <cfcatch ...> 
                Second level of exception handling code 
            </cfcatch>
            <cffinally> 
                    final code    
             </cffinally> 
        </cftry> 
    </cfcatch> 
</cftry>

Adobe ColdFusion Documentation [3]

Railo / Lucee specific Syntax

In addition to the CFML syntax above, Railo's and Lucee's dialect of CFML allows for a retry statement.[4]

This statement returns processing to the beginning of the preceding try block.

CFScript example:

try {
	// code which could result in an exception 

} catch (any e){
	retry;
}

Tag-syntax example:

<cftry>

	<!--- code which could result in an exception --->

	<cfcatch>
		<cfretry>
	</cfcatch>
</cftry>

D

import std.stdio; // for writefln()
int main() {
  try {
      // do something that might throw an exception
  }
  catch (FooException e) {
       // handle exceptions of type FooException
  }
  catch (Object o) {
       // handle any other exceptions
       writefln("Unhandled exception: ", o);
       return 1;
  }
  return 0;
}

In D, a finally clause or the resource acquisition is initialization technique can be used to clean up resources in exceptional situations.

Delphi

Exception declarations
type ECustom = class(Exception) // Exceptions are children of the class Exception.
  private
    FCustomData: SomeType;      // Exceptions may have custom extensions.
  public
    constructor CreateCustom(Data: SomeType); // Needs an implementation
    property CustomData: SomeType read FCustomData;
  end;
Raising exceptions
raise Exception.Create('Message');

raise Exception.CreateFmt('Message with values: %d, %d',[value1, value2]); // See SysUtils.Format() for parameters. 

raise ECustom.CreateCustom(X);
Exception handling and propagation[5]
try // For finally.
  try // For except.
    ... // Code that may raise an exception.
  except
    on C:ECustom do
      begin
        ... // Handle ECustom.
        ... if Predicate(C.CustomData) then ...
      end;
    on S:ESomeOtherException do
      begin
        // Propagate as an other exception.
        raise EYetAnotherException.Create(S.Message); 
      end;
    on E:Exception do
      begin
        ... // Handle other exceptions.
        raise; // Propagate.
      end;
  end; 
finally
  // Code that will be executed whether or not an exception is raised (e.g. clean-up code).
end;

Erlang

try
  % some dangerous code
catch
  throw:{someError, X} -> ok;    % handle an exception
  error:X -> ok;                 % handle another exception
  _:_ -> ok                      % handle all exceptions
after
  % clean up
end

Haskell

Haskell does not have special syntax for exceptions. Instead, a try/catch/finally/etc. interface is provided by functions.

import Prelude hiding(catch)
import Control.Exception
instance Exception Int
instance Exception Double
main = do
  catch
    (catch
      (throw (42::Int))
      (\e-> print (0,e::Double)))
    (\e-> print (1,e::Int))

prints

(1,42)

in analogy with this C++

#include <iostream>
using namespace std;
int main()
{
  try
    {throw (int)42;}
  catch(double e)
    {cout << "(0," << e << ")" << endl;}
  catch(int e)
    {cout << "(1," << e << ")" << endl;}
}

Another example is

do {
  -- Statements in which errors might be thrown
} `catch` \ex -> do {
  -- Statements that execute in the event of an exception, with 'ex' bound to the exception
}

In purely functional code, if only one error condition exists, the Maybe type may be sufficient, and is an instance of Haskell's Monad class by default. More complex error propagation can be achieved using the Error or ErrorT monads, for which similar functionality (using `catch`) is supported.

Java

try {
   // Normal execution path
   throw new EmptyStackException();
} catch (ExampleException ee) {
   //  deal with the ExampleException
} finally {
   // This optional section is executed upon termination of any of the try or catch blocks above, 
   //  except when System.exit() is called in "try" or "catch" blocks;
}

JavaScript

try {
  // Statements in which exceptions might be thrown
  throw 'error';
} catch(error) {
  // Statements that execute in the event of an exception
} finally {
  // Statements that execute afterward either way
}

Lisp

Common Lisp

(ignore-errors (/ 1 0))

(handler-case
    (progn
      (print "enter an expression")
      (eval (read)))
  (error (e) (print e)))

(unwind-protect
    (progn
       (print "enter an expression")
       (eval (read)))
  (print "This print will always be executed, similar to finally."))

Lua

Lua uses the pcall and xpcall functions, with xpcall taking a function to act as a catch block.

Predefined function
function foo(x)
    if x then return "returned "..x end
    error"message"
end
function attempt(arg)
    status,value=pcall(foo,arg)
    if not status then print"error:"end
    print(value)
end
attempt"hello"
--returned hello
attempt(nil)
--error:
--stdin:3: message
attempt{}
--error:
--stdin:2: attempt to concatenate local 'x' (a table value)
if foo(42)then print"success"end
--success
Anonymous function
if pcall(function()
        --do something that might throw an error
    end)then
    print"no errors"--executed if the protected call was successful
else
    print"error encountered"--executed if the protected call failed
end
print"done"--will always be executed

Objective-C

Exception declarations
NSException *exception = [NSException exceptionWithName:@"myException"
                           reason:@"whatever"  userInfo:nil];
Raising exceptions
@throw exception;
Exception handling and propagation
@try {
    ...
}
@catch (SomeException *se) {
    // Handle a specific exception type.
    ...
}
@catch (NSException *ne) {
    // Handle general exceptions.
    ...

    // Propagate the exception so that it's handled at a higher level.
    @throw;
}
@catch (id ue) {
    // Catch all thrown objects.
    ...
}
@finally {
    // Perform cleanup, whether an exception occurred or not.
    ...
}

OCaml

exception MyException of string * int (* exceptions can carry a value *)
let _ =
  try
    raise (MyException ("not enough food", 2));
    print_endline "Not reached"
  with
  | MyException (s, i) -> 
      Printf.printf "MyException: %s, %d\n" s i
  | e ->  (* catch all exceptions *)
     Printf.eprintf "Unexpected exception : %s" (Printexc.to_string e);
     (*If using Ocaml >= 3.11, it is possible to also print a backtrace: *)
     Printexc.print_backtrace stderr;
       (* Needs to beforehand enable backtrace recording with
           Printexc.record_backtrace true
         or by setting the environment variable OCAMLRUNPARAM="b1"*)

Perl

The Perl mechanism for exception handling uses die to throw an exception when wrapped inside an eval { ... }; block. After the eval, the special variable $@ contains the value passed from die. However, scoping issues can make doing this correctly quite ugly:

my ( $error, $failed );
{
   local $@;
   $failed = not eval {
       # Code that could throw an exception (using 'die')
       open(FILE, $file) || die "Could not open file: $!";
       while (<FILE>) {
           process_line($_);
       }
       close(FILE) || die "Could not close $file: $!";
       return 1;
   };
   $error = $@;
}

if ( $failed ) {
   warn "got error: $error";
}

Perl 5.005 added the ability to throw objects as well as strings. This allows for better introspection and handling of types of exceptions.

eval {
  open(FILE, $file) || die MyException::File->new($!);
  while (<FILE>) {
    process_line($_);
  }
  close(FILE) || die MyException::File->new($!);
};
if ($@) {
  # The exception object is in $@
  if ($@->isa('MyException::File')) {
    # Handle file exception
  } else {
    # Generic exception handling
    # or re-throw with 'die $@'
  }
}

The __DIE__ pseudo-signal can be trapped to handle calls to die. This is not suitable for exception handling since it is global. However it can be used to convert string-based exceptions from third-party packages into objects.

local $SIG{__DIE__} = sub {
  my $err = shift;
  if ($err->isa('MyException')) {
    die $err; # re-throw
  } else {
    # Otherwise construct a MyException with $err as a string
    die MyException::Default->new($err);
  }
};

The forms shown above can sometimes fail if the global variable $@ is changed between when the exception is thrown and when it is checked in the if ($@) statement. This can happen in multi-threaded environments, or even in single-threaded environments when other code (typically called in the destruction of some object) resets the global variable before the checking code. The following example shows a way to avoid this problem (see [1]). But at the cost of not being able to use return values:

eval {
  # Code that could throw an exception (using 'die') but does NOT use the return statement;
  1;
} or do {
  # Handle exception here. The exception string is in $@
};

A number of modules in CPAN expand on the basic mechanism:

  • Error provides a set of exception classes and allows use of the try/throw/catch/finally syntax.
  • TryCatch and Try::Tiny both allow use of try/catch/finally syntax instead of boilerplate to handle exceptions correctly.
  • Exception::Class is a base class and class-maker for derived exception classes. It provides a full structured stack trace in $@->trace and $@->trace->as_string.
  • Fatal overloads previously defined functions that return true/false e.g. open, close, read, write, etc. This allows built-in functions and others to be used as if they threw exceptions.

PHP

// Exception handling is only available in PHP versions 5 and greater.
try
{
  // Code that might throw an exception
  throw new Exception('Invalid URL.');
}
catch (FirstExceptionClass $exception) 
{
  // Code that handles this exception
} 
catch (SecondExceptionClass $exception) 
{
  // Code that handles a different exception
}
finally
{
  // Perform cleanup, whether an exception occurred or not.
}

PowerBuilder

Exception handling is available in PowerBuilder versions 8.0 and above.

TRY
   // Normal execution path
CATCH (ExampleException ee)
   //  deal with the ExampleException
FINALLY
   // This optional section is executed upon termination of any of the try or catch blocks above
END TRY

Python

f = None
try:
   f = file("aFileName")
   f.write(could_make_error())
except IOError:
   print "Unable to open file"
except:   # catch all exceptions
   print "Unexpected error"
else:     # executed if no exceptions are raised
   print "File write completed successfully"
finally:  # clean-up actions, always executed
   if f:
      f.close()

R

tryCatch({
   stop("Here an error is signaled")   # default S3-class is simpleError a subclass of error
   cat("This and the following lines are not executed because the error is trapped before\n")
   stop( structure(simpleError("mySpecialError message"),class=c("specialError","error","condition")) )
}
,specialError=function(e){
    cat("catches errors of class specialError\n")
}
,error=function(e){
    cat("catches the default error\n")
}
,finally={ cat("do some cleanup (e.g. setwd)\n") }
)

REBOL

REBOL [
    Title: "Exception and error handling examples"
]

; TRY a block; capturing an error! and converting to object!
if error? exception: try [1 / 0][probe disarm exception]

; ATTEMPT results in the value of the block or the value none on error
print attempt [divide 1 0]

; User generated exceptions can be any datatype!
example: func ["A function to throw an exception"
][
    throw "I'm a string! exception"
]
catch [example]

; User generated exceptions can also be named,
;   and functions can include additional run time attributes 
sophisticated: func ["A function to throw a named error exception"
    [catch]
][
    throw/name make error! "I'm an error! exception" 'moniker
]
catch/name [sophisticated] 'moniker

REXX

 signal on halt;
 do a = 1
	 say a
	 do 100000 /* a delay */
	 end
 end
 halt:
 say "The program was stopped by the user"
 exit

Ruby

begin
  # Do something nifty
  raise SomeError, "This is the error message!"  # Uh-oh!
rescue SomeError
  # This is executed when a SomeError exception
  # is raised
rescue AnotherError => error
  # Here, the exception object is referenced from the
  # `error' variable
rescue
  # This catches all exceptions derived from StandardError
  retry # This executes the begin section again
else
  # This is executed only if no exceptions were raised
ensure
  # This is always executed, exception or not
end

S-Lang

 try 
 {
    % code that might throw an exception
 }
 catch SomeError: 
 { 
    % code that handles this exception
 }
 catch SomeOtherError:
 {  
    % code that handles this exception
 }
 finally   % optional block
 {
    % This code will always get executed
 }

New exceptions may be created using the new_exception function, e.g.,

 new_exception ("MyIOError", IOError, "My I/O Error");

will create an exception called MyIOError as a subclass of IOError. Exceptions may be generated using the throw statement, which can throw arbitrary S-Lang objects.

Smalltalk

  [ "code that might throw an exception" ]
     on: ExceptionClass 
     do: [:ex | "code that handles exception" ].

The general mechanism is provided by the message on:do:.[6] Exceptions are just normal objects that subclass Error, you throw one by creating an instance and sending it a #signal message, e.g. MyException new signal. The handling mechanism (#on:do:) is again just a normal message implemented by BlockClosure. The thrown exception is passed as a parameter to the handling block closure, and you can query it as well as potentially sending #resume to it, to allow execution flow to continue.

Swift

Exception handling is supported since Swift 2.

enum MyException : ErrorType {
  case Foo(String, Int)
}
func someFunc() throws {
  throw MyException.Foo("not enough food", 2)
}
do {
  try someFunc()
  print("Not reached")
} catch MyException.Foo(let s, let i) {
  print("MyException: \(s), \(i)")
} catch {
  print("Unexpected exception : \(error)")
}

Tcl

if { [ catch {
   foo
} err ] } {
   puts "Error: $err"
}

Since Tcl 8.6, there is also a try command:

try {
    someCommandWithExceptions
} on ok {res opt} {
    # handle normal case.
} trap ListPattern1 {err opt} {
    # handle exceptions with an errorcode matching ListPattern1
} trap ListPattern2 {err opt} {
    # ...
} on error {err opt} {
    # handle everything else.
} finally {
    # run whatever commands must run after the try-block.
}

VBScript

https://sites.google.com/site/truetryforvisualbasic/

With New Try: On Error Resume Next
    'Do Something (Only one statement recommended)
.Catch :On Error GoTo 0: Select Case .Number
    Case 0 'This line is required in VBScript when using 'Case Else' clause.
        'No exception
    Case ERRORNUMBER
        'Handle exception
    Case Else
        'Unknown exception
End Select: End With

' *** Try Class ***
Class Try
    Private mstrDescription
    Private mlngHelpContext
    Private mstrHelpFile
    Private mlngNumber
    Private mstrSource

    Public Sub Catch()
        mstrDescription = Err.Description
        mlngHelpContext = Err.HelpContext
        mstrHelpFile = Err.HelpFile
        mlngNumber = Err.Number
        mstrSource = Err.Source
    End Sub

    Public Property Get Source()
        Source = mstrSource
    End Property
    
    Public Property Get Number()
        Number = mlngNumber
    End Property

    Public Property Get HelpFile()
        HelpFile = mstrHelpFile
    End Property
    
    Public Property Get HelpContext()
        HelpContext = mlngHelpContext
    End Property
    
    Public Property Get Description()
        Description = mstrDescription
    End Property
End Class

Visual Basic

https://sites.google.com/site/truetryforvisualbasic/

With New Try: On Error Resume Next
    'Do Something (Only one statement recommended)
.Catch :On Error GoTo 0: Select Case .Number
    Case ERRORNUMBER
        'Handle exception
    Case Is <> 0
        'Unknown exception
End Select: End With

' *** Try Class ***
Private mstrDescription  As String
Private mlngHelpContext  As Long
Private mstrHelpFile     As String
Private mlngLastDllError As Long
Private mlngNumber       As Long
Private mstrSource       As String

Public Sub Catch()
    mstrDescription = Err.Description
    mlngHelpContext = Err.HelpContext
    mstrHelpFile = Err.HelpFile
    mlngLastDllError = Err.LastDllError
    mlngNumber = Err.Number
    mstrSource = Err.Source
End Sub

Public Property Get Source() As String
    Source = mstrSource
End Property

Public Property Get Number() As Long
    Number = mlngNumber
End Property

Public Property Get LastDllError() As Long
    LastDllError = mlngLastDllError
End Property

Public Property Get HelpFile() As String
    HelpFile = mstrHelpFile
End Property

Public Property Get HelpContext() As Long
    HelpContext = mlngHelpContext
End Property

Public Property Get Description() As String
    Description = mstrDescription
End Property

Visual Basic .NET

Try
   ' write the condition here
Catch ex As Exception When condition
   ' Handle Exception when a specific condition is true
Catch ex As Exception
   ' Handle Exception
Finally
   ' Cleanup, close connections etc
   ' NB this code is always executed regardless of if an Exception was raised or not!
End Try

Visual Prolog

http://wiki.visual-prolog.com/index.php?title=Language_Reference/Terms#Try-catch-finally

try
    % Block to protect
catch TraceId do
    % Code to execute in the event of an exception; TraceId gives access to the exception information
finally
    % Code will be executed regardles however the other parts behave
end try

Windows PowerShell

PowerShell V1.0

trap [Exception]
{
  # Statements that execute in the event of an exception
}
# Statements in which exceptions might be thrown

PowerShell V2.0

Try {
    Import-Module ActiveDirectory
    }
Catch [Exception1] {
  # Statements that execute in the event of an exception, matching the exception
    }
Catch [Exception2],[Exception3etc] {
  # Statements that execute in the event of an exception, matching any of the exceptions
    }
Catch {
  # Statements that execute in the event of an exception, not handled more specifically
    }

X++

public static void Main(Args _args)
{
   try
   {
      // Code that could throw an exception
   }
   catch (Exception::Error) // Or any other exception type
   {
      // Process the error
   }
   catch
   {
      // Process any other exception type not handled previously
   }

   // Code here will execute as long as any exception is caught
}

References

  1. Bjarne Stroustrup's FAQ
  2. Handling exceptions
  3. Exception handling tags
  4. https://issues.jboss.org/browse/RAILO-2176 # JBoss Community issue tracker ticket for adding retry
  5. Borland, Delphi Version 7.0, Online help
  6. Pharo by Example

See also