From ce1570a6fb618f72dc42e46cdb1a7b2a12b9ad08 Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Mon, 16 Nov 2020 23:40:17 -0800 Subject: [PATCH] defer: improve manual, clarify difference wrt try/finally (#16010) (cherry picked from commit 50d035b7896b85184fc6e97e22f32a189d76b81b) --- doc/manual.rst | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/doc/manual.rst b/doc/manual.rst index 4bebcb4f75..5dc8f9d4da 100644 --- a/doc/manual.rst +++ b/doc/manual.rst @@ -4372,7 +4372,9 @@ Custom exceptions can be raised like any others, e.g.: Defer statement --------------- -Instead of a ``try finally`` statement a ``defer`` statement can be used. +Instead of a ``try finally`` statement a ``defer`` statement can be used, which +avoids lexical nesting and offers more flexibility in terms of scoping as shown +below. Any statements following the ``defer`` in the current block will be considered to be in an implicit try block: @@ -4381,7 +4383,7 @@ to be in an implicit try block: :test: "nim c $1" proc main = - var f = open("numbers.txt") + var f = open("numbers.txt", fmWrite) defer: close(f) f.write "abc" f.write "def" @@ -4399,6 +4401,33 @@ Is rewritten to: finally: close(f) +When `defer` is at the outermost scope of a template/macro, its scope extends +to the block where the template is called from: + +.. code-block:: nim + :test: "nim c $1" + + template safeOpenDefer(f, path) = + var f = open(path, fmWrite) + defer: close(f) + + template safeOpenFinally(f, path, body) = + var f = open(path, fmWrite) + try: body # without `defer`, `body` must be specified as parameter + finally: close(f) + + block: + safeOpenDefer(f, "/tmp/z01.txt") + f.write "abc" + block: + safeOpenFinally(f, "/tmp/z01.txt"): + f.write "abc" # adds a lexical scope + block: + var f = open("/tmp/z01.txt", fmWrite) + try: + f.write "abc" # adds a lexical scope + finally: close(f) + Top-level ``defer`` statements are not supported since it's unclear what such a statement should refer to.