# Confusion about scope in try-catch blocks

**URL:** https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622
**Category:** General Usage
**Tags:** scope
**Created:** [June 11, 2024, 9:40pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622 "2024-06-11T21:40:06Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### Author: ![Tortar](https://avatars.discourse-cdn.com/v4/letter/t/6bbea6/32.png) [@Tortar](https://discourse.julialang.org/u/Tortar)
#### Post date: [June 11, 2024, 9:40pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/1 "2024-06-11T21:40:06Z")

</div>

Regarding scoping rules this used to trip me up a bit:

Python:

```julia
>>> try:
... x = 2
... except:
... pass
... 
>>> x
2

```

Julia:

```julia
julia> try
           x = 2
       catch
       end
2

julia> x
ERROR: UndefVarError: `x` not defined

```

---

<div class="post-metadata">

### Author: ![oOosys](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ooosys/32/209566_2.png) [@oOosys](https://discourse.julialang.org/u/oOosys)
#### Post date: [June 11, 2024, 9:51pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/2 "2024-06-11T21:51:32Z")

</div>

OK … so `try` `catch` are blocks of code with own scoping here, right? To make it work like in Python you probably need somehow declare the x as global to be available outside of the code block, right?

---

<div class="post-metadata">

### Author: ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)
#### Post date: [June 11, 2024, 9:57pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/3 "2024-06-11T21:57:08Z")

</div>

Right, you can do `local x` outside the `try`, but it’s often simpler to just put the `x` outside in the first place.

```julia
julia> x = try
               1
           catch
               2
           end
1

julia> x
1

```

Julia can do this because `try` is an expression, not (as in Python) a statement, so it has a value and you can assign it to a variable.

---

<div class="post-metadata">

### Author: ![mihalybaci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mihalybaci/32/13528_2.png) [@mihalybaci](https://discourse.julialang.org/u/mihalybaci)
#### Post date: [June 13, 2024, 11:52am UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/4 "2024-06-13T11:52:38Z")

</div>

Keeping in mind that REPL global scope is different, this does work in a function

```julia
function foo()
  try
    x=2
  catch
  end
end

foo() #properly returns 2

```

Every now and then I have to remember that there are some things that I can’t test easily in the REPL without a function (like the try/catch example).

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [June 13, 2024, 1:28pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/5 "2024-06-13T13:28:39Z")

</div>

> [@mihalybaci](#):
>
> ```julia
> function foo()
> try
> x=2
> catch
> end
> end
> 
> foo() #properly returns 2
> 
> ```

The equivalent to the REPL example would be as follows.

```julia-repl
julia> function foo()
         try
           x=2
         catch
         end
         return x
       end
foo (generic function with 1 method)

julia> foo()
ERROR: UndefVarError: `x` not defined

```

There are two fixes that come to mind.

```julia-repl
julia> function foo()
         x = 0
         try
           x=2
         catch
         end
         return x
       end
foo (generic function with 1 method)

julia> foo()
2

julia> function foo()
         x = try
           2
         catch
         end
         return x
       end
foo (generic function with 1 method)

julia> foo()
2

```

---

<div class="post-metadata">

### Author: ![mihalybaci](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mihalybaci/32/13528_2.png) [@mihalybaci](https://discourse.julialang.org/u/mihalybaci)
#### Post date: [June 13, 2024, 2:18pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/6 "2024-06-13T14:18:09Z")

</div>

I was playing around with it a bit too, and here’s one I don’t quite get.

```julia
function bar()
    try
        x=2
    catch
    end
    x += 1
    return x
ends

bar() # returns 3

```

Somehow the `+=` operator is able to grab the value of `x` when `return` can’t, then assign to `x` in a way that can be `return`ed.

---

<div class="post-metadata">

### Author: ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)
#### Post date: [June 13, 2024, 2:46pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/7 "2024-06-13T14:46:55Z")

</div>

Huh, that is weird. Could that be a bug? This fails (as I would expect it to):

```julia-repl
julia> function bar()
           try
               x = 2
           catch
           end
           y = x + 1
           y
       end
bar (generic function with 1 method)

julia> bar()
ERROR: UndefVarError: `x` not defined

```

Maybe your example is spooky-action-at-a-distance? Julia looks for a variable binding anywhere in the enclosing scope, even if it is after the try-catch scope?

---

<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: [June 13, 2024, 2:51pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/8 "2024-06-13T14:51:19Z")

</div>

`x += 1` is `x = x + 1`. By assigning to `x` in the outer scope (_anywhere_, either syntactically before or _after_ the try scope), you’re establishing `x` as a local name avaliable in `bar()` — and then the `x` in the `try` loop is the same `x`.

Honestly, I think Julia’s scoping behaviors are quite prone to establish these sorts of “bad” mental models (akin to what I was saying above) because they _mostly_ “do what you mean” so very often.

---

<div class="post-metadata">

### Author: ![oOosys](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ooosys/32/209566_2.png) [@oOosys](https://discourse.julialang.org/u/oOosys)
#### Post date: [June 13, 2024, 8:09pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/9 "2024-06-13T20:09:54Z")

</div>

> [@mbauman](#):
>
> (_anywhere_, either syntactically before or _after_ the try scope)

You need to make it bold - best the “anywhere” a font size larger … and or _also after_ a font larger … to make the point apparent at the first glance. The issue with the mental model is that it usually thinks in terms like from left to right, from top to bottom … so outer scope expression seen **AFTER** the inner scope is intuitively not considered to be the outer scope for the inner one … By the way: the core of the idea of **oOo** is to work with the inner mental model - your awareness of it is surprising because it seems that there are as good as no programmer around aware of this … maybe you are “The ONE” able to grasp the idea a join me in my efforts of making the oOo approach to programming reality? I am myself not that smart and progressing very slowly … having hard time to explain what I intend as final outcome and what it should be good for if I am asking a question.

---

<div class="post-metadata">

### Author: ![oOosys](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ooosys/32/209566_2.png) [@oOosys](https://discourse.julialang.org/u/oOosys)
#### Post date: [June 13, 2024, 8:21pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/10 "2024-06-13T20:21:54Z")

</div>

> [@mbauman](#):
>
> `x += 1` is `x = x + 1`. By assigning to `x` in the outer scope (_anywhere_, either syntactically before or _after_ the try scope), you’re establishing `x` as a local name avaliable in `bar()` — and then the `x` in the `try` loop is the same `x`.

This is really hard to grasp … I suggest to find a way to explain it in a way which is better understandable pointing out the actual issue with the mental model which is the intuitive assumption that code lines AFTER the lines before are not able to change the meaning of the lines before. This is with scopes apparently not the case. The assignment AFTER the try/catch/end block changes the scope of the `x` used in the block - do I understand it right?

---

<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: [June 13, 2024, 8:46pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/11 "2024-06-13T20:46:45Z")

</div>

The set of local names available isn’t imperatively defined/updated by a sequence of events that are executed, but rather it’s a static property of the given scope. Each scope has a concrete set of local names it can use. Those names are established by the assignments that occur in that scope (or explicit `local` declarations). And then inner scopes can inherit those names.

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [June 14, 2024, 6:12am UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/12 "2024-06-14T06:12:18Z")

</div>

Scoping rules are probably the thing about Julia I dislike most. In Python you can summarize the rules with “only functions introduce a scope”, which is a simple rule you could get tattooed.  
In Julia, the rule is more like “Most blocks introduce a scope, but not if a variable is used already local to a surrounding scope except if that is the top-level of the REPL. Also assigning to a variable makes it visible in the entire scope.” This is a much more complicated rule, which leads to strange situation like outlined above. In fact, we can make it look even more alienating:

```julia
function foo()
    try
        x = 2
    catch
    end
    return x
end
foo() # does not work

function bar()
    try
        x = 2
    catch
    end
    x = x
    return x
end
bar() # DOES work

```

For me this would be something I’d like to see changed in Julia 2.0. Either make it so that a variable needs to be declared _before_ the scope (via e.g. `local x` which already works btw) or make it like Python, but that while simple is annoying if one uses closures a lot which tends to happen more often in Julia than in Python. So reflecting on this: It’s probably the fact that the declaration/assignment may appear _below_ the inner scope that bothers me, because that means I need to read everything to understand an “embedded scope” and not just everything above that scope.

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [June 14, 2024, 9:02am UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/14 "2024-06-14T09:02:26Z")

</div>

> [@mihalybaci](#):
>
> ```julia
> function bar()
> try
> x=2
> catch
> end
> x += 1
> return x
> ends
> 
> bar() # returns 3
> 
> ```

This does seem weird. Stylistically, I think I would always write this as follows even if this is technically unnecessary.

```julia
function bar()
    x = 0
    try
        x = 2
    catch
    end
    x += 1
    return x
end

```

---

<div class="post-metadata">

### Author: ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)
#### Post date: [June 14, 2024, 9:08am UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/15 "2024-06-14T09:08:25Z")

</div>

> [@mkitti](#):
>
> ```julia
> function bar()
> x = 0
> try
> x = 2
> catch
> end
> x += 1
> return x
> end
> 
> ```

Or use local to “declare” the variable, which perhaps communicates the intent more clearly:

```julia
function bar()
    local x
    try
        x = 2
    catch
    end
    x += 1
    return x
end

```

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [June 14, 2024, 9:12am UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/16 "2024-06-14T09:12:19Z")

</div>

I would appreciate this as long the catch also initialized `x`.

```julia
function bar()
    local x
    try
        error("boo!")
        x = 2
    catch
        x = 0
    end
    x += 1
    return x
end

```

---

<div class="post-metadata">

### Author: ![Tarny\_GG\_Channie](https://avatars.discourse-cdn.com/v4/letter/t/3bc359/32.png) [@Tarny\_GG\_Channie](https://discourse.julialang.org/u/Tarny_GG_Channie)
#### Post date: [June 14, 2024, 1:22pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/17 "2024-06-14T13:22:32Z")

</div>

Maybe I’m the weird one here but I’m actually in favor of allowing code to draw on later information. It allows cool things like attribute inference where the attribute of an object with undeclared fields (like in Python) can be inferred by its later uses allowing the object to avoid using dictionary. It also allows type inference or type parameter inference to be more aggressive.

---

<div class="post-metadata">

### Author: ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)
#### Post date: [June 14, 2024, 2:53pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/18 "2024-06-14T14:53:11Z")

</div>

This particular scoping rule can be quite confusing. In particular when combined with anonymous functions. Say you have a vector of vectors, and a function which takes a vector. You want to sum things inside some function:

```julia
f::Function
v::Vector{Vector{Float64}}
s = sum(f, v)
... some computations
# set up for some other computation:
a = 4; b = 5; x = 2.3; y = 4.5
g(a, b, x, y, s)

```

Now, the `f` takes time, so you want a parallel variant running on chunks of the vector `v`. You just replace the `s = sum(f, v)` by:

```julia
s = sum(fetch, [@spawn (y = sum(f, vc); @show(y); y) for vc in chunks(v)])

```

This is admittedly sloppy variable naming, but the net effect is that the program is now incorrect. All the parallel tasks share the same `y` because it was assigned to later in the function. Sneak in a `local y =` in the task, and it is correct.

The problem with this is that what you do later in the function affects what happens at the beginning. It’s counter intuitive, but of course, perfectly understandable.

---

<div class="post-metadata">

### Author: ![ianshmean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ianshmean/32/216042_2.png) [@ianshmean](https://discourse.julialang.org/u/ianshmean)
#### Post date: [June 14, 2024, 3:27pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/19 "2024-06-14T15:27:11Z")

</div>

The idea of a `@noscope` macro for try blocks was explored before, but I lost momentum on it, if someone wants to follow the triage recommendation here [Add noscope macro to make try blocks evaluate in the local scope by IanButterworth · Pull Request #39217 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/39217)

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [June 14, 2024, 5:28pm UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/20 "2024-06-14T17:28:34Z")

</div>

5 posts were split to a new topic: [Programming languages with only global scope?](https://discourse.julialang.org/t/programming-languages-with-only-global-scope/115665)

---

<div class="post-metadata">

### Author: ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)
#### Post date: [June 15, 2024, 5:27am UTC](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622/21 "2024-06-15T05:27:00Z")

</div>

> [@jar1](#):
>
> Julia can do this because `try` is an expression, not (as in Python) a statement, so it has a value and you can assign it to a variable.

This is something I didn’t know. Thank you!

But that leads me to the following question: Why is it like that? I mean: in my opinion, the scoping behavior of try-catch blocks is more confusing than that of others because it looks like an if-else, so intuitively I would expect it to work like an if-else, but it doesn’t.

[Next page](https://discourse.julialang.org/t/confusion-about-scope-in-try-catch-blocks/115622.md?page=2)
