# Using Let block

**URL:** <https://discourse.julialang.org/t/using-let-block/110490>\
**Category:** General Usage\
**Tags:** scope\
**Created:** [February 21, 2024, 12:31am UTC](https://discourse.julialang.org/t/using-let-block/110490 "2024-02-21T00:31:54Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)\
**Post date:** [February 21, 2024, 12:31am UTC](https://discourse.julialang.org/t/using-let-block/110490/1 "2024-02-21T00:31:54Z")

</div>

If I define a variable `b` in Main and then use the let block:

```julia
b = 5
let 
  b = b
  println(b)
end

```

I get the error saying: " UndefVarError: `b` not defined"

I can get this to work by doing:

```julia
b = 5
let 
  b = Main.b
  println(b)
end

```

Is there a way to do this which doesn’t use Main but instead whatever level this was called in? In other words if I did this within a function, then I wouldn’t want to use the word `Main`.

I tried using the escape function but wasn’t successful.

Thanks,

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [February 21, 2024, 12:37am UTC](https://discourse.julialang.org/t/using-let-block/110490/2 "2024-02-21T00:37:08Z")

</div>

> [@co1emi11er](#):
>
> ```julia
> let 
> b = Main.b
> println(b)
> end
> 
> ```

You can also do:

```julia
julia> b = 5
5

julia> let 
         global b
         println(b)
       end

```

---

<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:** [February 21, 2024, 12:39am UTC](https://discourse.julialang.org/t/using-let-block/110490/3 "2024-02-21T00:39:09Z")

</div>

> [@co1emi11er](#):
>
> ```julia
> let 
> b = Main.b
> println(b)
> end
> 
> ```

No that doesn’t do anything. If you want a new `b` inside the let block, put it on the first line of the `let` block

```julia
julia> let b = b
           println(b)
       end
5

```

---

<div class="post-metadata">

**Author:** ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)\
**Post date:** [February 21, 2024, 12:47am UTC](https://discourse.julialang.org/t/using-let-block/110490/4 "2024-02-21T00:47:01Z")

</div>

Wow. Very interesting. I needed to do multiple variables, but I just created a block in first line and it works. Thanks!

---

<div class="post-metadata">

**Author:** ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)\
**Post date:** [February 22, 2024, 7:36am UTC](https://discourse.julialang.org/t/using-let-block/110490/5 "2024-02-22T07:36:28Z")

</div>

When defining multiple variables in a let block, I tend to favor the following syntax (which I learned about [here](https://discourse.julialang.org/t/tips-on-how-to-use-let-blocks-to-shadow-local-variables-and-avoid-accidentally-modifying-the-original-variable/101467/5) on Discourse, too). In the line of the `let` keyword, I only list the variables to be given a local scope, without their assigned values. And then, in the first fiew lines of the body of the `let` block, I assign their values. E.g.,

```julia
global_value = let x, y
    x = <expression-to-compute-x>
    y = <expression-to-compute-y>
    <expression-using-x-and-y>
end

```

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [February 22, 2024, 12:51pm UTC](https://discourse.julialang.org/t/using-let-block/110490/6 "2024-02-22T12:51:55Z")

</div>

> [@HanD](#):
>
> In the line of the `let` keyword, I only list the variables to be given a local scope, without their assigned values. And then, in the first fiew lines of the body of the `let` block, I assign their values.

Yes, but only in the first line of the `let` block do you have the ability to create a new binding for an existing variable, while still referring to that variable for the assigned value. (And this was precisely the use case mentioned in the OP).

Consider the following example:

```julia
julia> x = 1
1

# in the lhs, x refers to a new binding
# in the rhs, x refers to the global variable
julia> let x = x + 1
           x *= 2
       end
4

julia> x
1

```

but

```julia
julia> x = 1
1

julia> let x # <- new binding introduced here, shadows the global variable everywhere in the let body
           x = x + 1 # x refers to the new variable in both lhs and rhs
           x *= 2 # => ERROR
       end
ERROR: UndefVarError: `x` not defined
Stacktrace:
 [1] top-level scope
   @ REPL[4]:2

```

---

<div class="post-metadata">

**Author:** ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)\
**Post date:** [February 22, 2024, 3:25pm UTC](https://discourse.julialang.org/t/using-let-block/110490/7 "2024-02-22T15:25:41Z")

</div>

> [@ffevotte](#):
>
> Yes, but only in the first line of the `let` block do you have the ability to create a new binding for an existing variable, while still referring to that variable for the assigned value.

Fair point. If you need to use the values of some shadowed variables, you have no other option than to use them in the first line of the let block. I don’t like rebinding variables, though, so this is usually not an issue for me.

---

<div class="post-metadata">

**Author:** ![greg\_plowman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/greg_plowman/32/8100_2.png) [@greg\_plowman](https://discourse.julialang.org/u/greg_plowman)\
**Post date:** [February 22, 2024, 9:01pm UTC](https://discourse.julialang.org/t/using-let-block/110490/8 "2024-02-22T21:01:09Z")

</div>

> [@HanD](#):
>
> I don’t like rebinding variables, though, so this is usually not an issue for me.

In this case, is it possible to omit the variables on the `let` line?

```julia
global_value = let
    x = <expression-to-compute-x>
    y = <expression-to-compute-y>
    <expression-using-x-and-y>
end

```

---

<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:** [February 22, 2024, 9:03pm UTC](https://discourse.julialang.org/t/using-let-block/110490/9 "2024-02-22T21:03:06Z")

</div>

That will reassign existing variables. If you want new variables they have to go in the first line of the `let`.

Edit: it’s different if the existing variables are globals. See below.

---

<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:** [February 23, 2024, 6:55am UTC](https://discourse.julialang.org/t/using-let-block/110490/10 "2024-02-23T06:55:15Z")

</div>

No I don’t think so:

```julia-repl
julia> x=5
5

julia> let
           x=10
       end
10

julia> x
5

```

Because let creates a local scope and assignments in local scopes create a new binding. If you only used `x` inside the let block then you’d get the global value. But in any case you cannot overwrite it globally without using `global x` somewhere.

---

<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:** [February 23, 2024, 7:21am UTC](https://discourse.julialang.org/t/using-let-block/110490/11 "2024-02-23T07:21:21Z")

</div>

I think your example does rely only on the global. Assignments in the body of a `let` otherwise reassign existing variables from enclosing scopes.

```julia
julia> function f()
           x = 5
           let
               x = 10
           end
           x
       end
f (generic function with 1 method)

julia> f()
10

```

---

<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:** [February 23, 2024, 8:10am UTC](https://discourse.julialang.org/t/using-let-block/110490/12 "2024-02-23T08:10:46Z")

</div>

Your are right of course. Here `x` is already a local binding - just not local to the `let`-block (which I honestly find a bit confusing). Arguably that is the default mode of operation for `let` and what I posted a special case for true `global` variables.

I think, I just interpreted the @greg_plowman’s code to be in global scope due to the variable named `global_value`.

Good that you cleared this up 🙂

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 2, 2024, 3:32pm UTC](https://discourse.julialang.org/t/using-let-block/110490/13 "2024-11-02T15:32:58Z")

</div>

Can I ask, what is the reason for wanting to do this?

You can write your code like this:

```julia
b = 5
another_b = b
println(b)

```

There is no `let` block there. That suggests to me I haven’t understood why you wanted to introduce a new scope?

---

<div class="post-metadata">

**Author:** ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)\
**Post date:** [November 2, 2024, 4:37pm UTC](https://discourse.julialang.org/t/using-let-block/110490/14 "2024-11-02T16:37:53Z")

</div>

My package Handcalcs.jl can find functions and “unpack” the lines in the function into the current scope. See [here](https://co1emi11er2.github.io/Handcalcs.jl/stable/tutorial/#Function-Examples). But I don’t actually want to introduce those variables into the current scope, so I wrap them in a let block.

lets say I have a function:

```julia
function my_add(a, b)
c = a + b
end

```

If I write something like:

```julia
a = 2
b = 3
@handcalcs c = my_add(a, b)

```

The handcalcs macro will turn this into something like:

```julia
c = let (a, b) = (a, b)
c = a + b
end

```

There is more going on in the macro but this was the intent of the question. When the parameter names happen to be variables names in the current scope, the let block will not see the variables in the current scope so it needs to be in the first line rather than the second part of the let block.

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [November 2, 2024, 6:27pm UTC](https://discourse.julialang.org/t/using-let-block/110490/15 "2024-11-02T18:27:28Z")

</div>

Right I see, so it was to protect users of your macro from clobbering their locals?

---

<div class="post-metadata">

**Author:** ![co1emi11er](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/co1emi11er/32/206849_2.png) [@co1emi11er](https://discourse.julialang.org/u/co1emi11er)\
**Post date:** [November 2, 2024, 6:33pm UTC](https://discourse.julialang.org/t/using-let-block/110490/16 "2024-11-02T18:33:41Z")

</div>

Yes. Exactly
