# Cumbersome scoping rules for try - catch - finally

**URL:** <https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582>\
**Category:** General Usage\
**Created:** [July 1, 2017, 8:50am UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582 "2017-07-01T08:50:23Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [July 1, 2017, 8:50am UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/1 "2017-07-01T08:50:23Z")

</div>

I just had to implement the following logic:

1 - connect to DB (with potential error)  
2 - run query (with potential error)  
3 - return query result  
4 - make sure the connection is closed

The most concise way to write this would be:

```julia
try # catch all errors here
  conn = db_connect(...)
  result = db_query(conn, ...)
finally # make sure you disconnect
  disconnect(conn)
end

do_stuff_with_query_result(result)

```

But due to the scoping rules, you end up with something like:

```julia
conn = db_connect(...) # this will require another try - catch if you want to handle the exception
result = try 
           db_query(conn, ...)
         finally
           disconnect(conn)
         end

do_stuff_with_query_result(result)

```

It seems unnecessarily complicated. Is there any other way to handle this?

Also, why isn’t a variable defined inside `try` available inside `finally` ? I expected that the whole `try ... end` is just one scope block.

```julia
julia> try
         a = 2+2
       finally
         @show a
       end
------ UndefVarError ------------------- Stacktrace (most recent call last)

 [1] — anonymous at <missing>:?

 [2] — macro expansion; at REPL[1]:4 [inlined]

 [3] — macro expansion; at show.jl:218 [inlined]

UndefVarError: a not defined

```

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [July 1, 2017, 10:23am UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/4 "2017-07-01T10:23:14Z")

</div>

If variables that are created inside the `try` block are available inside the `finally` block, then that implicitly assumes that part of the code inside the `try` block will run successfully. But the point of `try` is that code inside it might fail…

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [July 1, 2017, 12:02pm UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/5 "2017-07-01T12:02:10Z")

</div>

It’s similar to `result` in my first example. It is initialised but if the `try` fails, it will reference something else (whatever the `catch` will return).

And that needs to be checked after the `try` block. So it just moves the check somewhere else.

---

<div class="post-metadata">

**Author:** ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)\
**Post date:** [July 1, 2017, 12:37pm UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/6 "2017-07-01T12:37:31Z")

</div>

You can declare the variable as `local` to make it visible inside the `finally`.

```julia
function foo()
    local yy
    try 
      yy = 2
    finally 
      @show yy
    end
end
foo()

```

I agree with @Per: if `db_connect` fails, `conn` will be undefined and your `finally` will fail.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [July 1, 2017, 1:07pm UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/7 "2017-07-01T13:07:59Z")

</div>

You could create a new method for `db_connect` that handles the try-catch-disconnect.

Something like:

```julia
db_connect(f::Function, args...) = begin
  conn = db_connect(args...)
  try
    f(conn)
  finally
    disconnect(conn)
  end
end

```

(Something like that. I didn’t test this.)

With this method you can then use a do-block:

```julia
db_connect(...) do conn
  result = db_query(conn, ....)
end

```

and this will be guaranteed to close the connection even if the `db_query` throws an exception.

You can then wrap that last piece of code in another `try` block if you want.

Edit: There was a better example in the documentation. Fixed my code.  
[https://docs.julialang.org/en/stable/manual/functions/#Do-Block-Syntax-for-Function-Arguments-1](https://docs.julialang.org/en/stable/manual/functions/#Do-Block-Syntax-for-Function-Arguments-1)

Edit2: I guess there might still be issues with the scope of the `result` variable.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [July 1, 2017, 5:43pm UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/8 "2017-07-01T17:43:23Z")

</div>

Yes, that’s a nice design pattern, it’s a good approach for sure.

Heh, indeed, `result` would have to be defined before `db_connect` in order to be accessible after it, which would move the problem 🙂

Thus better:

```julia
result = db_connect(...) do conn
  db_query(conn, ....)
end

```

This could be combined with another design pattern where the `try ... catch` block would return a `Nullable` type which `isnull` on error.

---

<div class="post-metadata">

**Author:** ![jpfairbanks](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jpfairbanks/32/4500_2.png) [@jpfairbanks](https://discourse.julialang.org/u/jpfairbanks)\
**Post date:** [July 1, 2017, 6:39pm UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/9 "2017-07-01T18:39:58Z")

</div>

I often handle this problem by making an zero or empty value for `result` before doing the try catch finally dance.

```julia
   result = QueryResult()
   conn = DBConnection()
   try
      conn = connect(params)
      res = query(conn, "select fields from tables")
   finally
     close(conn)
   end
   return res

```

Then when you call it you check that `res != QueryResult()` to make sure that the query ran successfully.  
This only works for types that have a valid “uninitialized” state. If there is no such “invalid” value, then you can use something like [https://github.com/iamed2/ResultTypes.jl](https://github.com/iamed2/ResultTypes.jl). Where you return the value that contains the data and another value of a Error type to indicate failure.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [July 1, 2017, 10:46pm UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/10 "2017-07-01T22:46:29Z")

</div>

As a final option, you can use `local conn, result` to introduce the variables into the outer scope (even without a definition). They’re then inherited into the try/catch/finally scopes. This has the downside of an undefined variable error if `db_connect` fails before it returns a value for `conn`.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [July 1, 2017, 11:19pm UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/11 "2017-07-01T23:19:12Z")

</div>

Which you can catch with a try-catch block 😹. It’s try-catch blocks all the way down… 🐢 🐢 🐢

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [July 3, 2017, 11:16am UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/12 "2017-07-03T11:16:58Z")

</div>

You probably meant

```julia
res = QueryResult() # instead of result = ... 

```

That’s going to be harder to check though (does `QueryResult` have an `isempty()` method or how do you know it worked). It’s maybe more Julian to say

```julia
res = Nullable{QueryResult}() 

```

and use `isnull(res)` to check.

---

<div class="post-metadata">

**Author:** ![essenciary](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/essenciary/32/210469_2.png) [@essenciary](https://discourse.julialang.org/u/essenciary)\
**Post date:** [July 3, 2017, 11:20am UTC](https://discourse.julialang.org/t/cumbersome-scoping-rules-for-try-catch-finally/4582/13 "2017-07-03T11:20:36Z")

</div>

Yeah, once you start going down the rabbit hole it gets crazy fast. 😄

Luckily, with the notable exception of GUI apps, DB connection errors are usually allowed to bubble all the way up and crash the app since you can’t do anything without the DB handle.
