mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-30 01:44:37 +00:00
159 lines
4.0 KiB
Plaintext
159 lines
4.0 KiB
Plaintext
Exception handling
|
|
==================
|
|
|
|
Try statement
|
|
-------------
|
|
|
|
Example:
|
|
|
|
.. code-block:: nim
|
|
# read the first two lines of a text file that should contain numbers
|
|
# and tries to add them
|
|
var
|
|
f: File
|
|
if open(f, "numbers.txt"):
|
|
try:
|
|
var a = readLine(f)
|
|
var b = readLine(f)
|
|
echo "sum: " & $(parseInt(a) + parseInt(b))
|
|
except OverflowError:
|
|
echo "overflow!"
|
|
except ValueError:
|
|
echo "could not convert string to integer"
|
|
except IOError:
|
|
echo "IO error!"
|
|
except:
|
|
echo "Unknown exception!"
|
|
finally:
|
|
close(f)
|
|
|
|
|
|
The statements after the ``try`` are executed in sequential order unless
|
|
an exception ``e`` is raised. If the exception type of ``e`` matches any
|
|
listed in an ``except`` clause the corresponding statements are executed.
|
|
The statements following the ``except`` clauses are called
|
|
`exception handlers`:idx:.
|
|
|
|
The empty `except`:idx: clause is executed if there is an exception that is
|
|
not listed otherwise. It is similar to an ``else`` clause in ``if`` statements.
|
|
|
|
If there is a `finally`:idx: clause, it is always executed after the
|
|
exception handlers.
|
|
|
|
The exception is *consumed* in an exception handler. However, an
|
|
exception handler may raise another exception. If the exception is not
|
|
handled, it is propagated through the call stack. This means that often
|
|
the rest of the procedure - that is not within a ``finally`` clause -
|
|
is not executed (if an exception occurs).
|
|
|
|
|
|
Try expression
|
|
--------------
|
|
|
|
Try can also be used as an expression; the type of the ``try`` branch then
|
|
needs to fit the types of ``except`` branches, but the type of the ``finally``
|
|
branch always has to be ``void``:
|
|
|
|
.. code-block:: nim
|
|
let x = try: parseInt("133a")
|
|
except: -1
|
|
finally: echo "hi"
|
|
|
|
|
|
To prevent confusing code there is a parsing limitation; if the ``try``
|
|
follows a ``(`` it has to be written as a one liner:
|
|
|
|
.. code-block:: nim
|
|
let x = (try: parseInt("133a") except: -1)
|
|
|
|
|
|
Except clauses
|
|
--------------
|
|
|
|
Within an ``except`` clause, it is possible to use
|
|
``getCurrentException`` to retrieve the exception that has been
|
|
raised:
|
|
|
|
.. code-block:: nim
|
|
try:
|
|
# ...
|
|
except IOError:
|
|
let e = getCurrentException()
|
|
# Now use "e"
|
|
|
|
Note that ``getCurrentException`` always returns a ``ref Exception``
|
|
type. If a variable of the proper type is needed (in the example
|
|
above, ``IOError``), one must convert it explicitly:
|
|
|
|
.. code-block:: nim
|
|
try:
|
|
# ...
|
|
except IOError:
|
|
let e = (ref IOError)(getCurrentException())
|
|
# "e" is now of the proper type
|
|
|
|
However, this is seldom needed. The most common case is to extract an
|
|
error message from ``e``, and for such situations it is enough to use
|
|
``getCurrentExceptionMsg``:
|
|
|
|
.. code-block:: nim
|
|
try:
|
|
# ...
|
|
except IOError:
|
|
echo "I/O error: " & getCurrentExceptionMsg()
|
|
|
|
|
|
Defer statement
|
|
---------------
|
|
|
|
Instead of a ``try finally`` statement a ``defer`` statement can be used.
|
|
|
|
Any statements following the ``defer`` in the current block will be considered
|
|
to be in an implicit try block:
|
|
|
|
.. code-block:: nim
|
|
var f = open("numbers.txt")
|
|
defer: close(f)
|
|
f.write "abc"
|
|
f.write "def"
|
|
|
|
Is rewritten to:
|
|
|
|
.. code-block:: nim
|
|
var f = open("numbers.txt")
|
|
try:
|
|
f.write "abc"
|
|
f.write "def"
|
|
finally:
|
|
close(f)
|
|
|
|
Top level ``defer`` statements are not supported
|
|
since it's unclear what such a statement should refer to.
|
|
|
|
|
|
Raise statement
|
|
---------------
|
|
|
|
Example:
|
|
|
|
.. code-block:: nim
|
|
raise newEOS("operating system failed")
|
|
|
|
Apart from built-in operations like array indexing, memory allocation, etc.
|
|
the ``raise`` statement is the only way to raise an exception.
|
|
|
|
.. XXX document this better!
|
|
|
|
If no exception name is given, the current exception is `re-raised`:idx:. The
|
|
`ReraiseError`:idx: exception is raised if there is no exception to
|
|
re-raise. It follows that the ``raise`` statement *always* raises an
|
|
exception.
|
|
|
|
|
|
Exception hierarchy
|
|
-------------------
|
|
|
|
The exception tree is defined in the `system <system.html>`_ module:
|
|
|
|
.. include:: ../exception_hierarchy_fragment.txt
|