# Are non-scoping \`begin ... end\` blocks useful?

**URL:** https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338
**Category:** General Usage
**Created:** [August 4, 2025, 2:40pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338 "2025-08-04T14:40:34Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)
#### Post date: [August 4, 2025, 2:40pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/1 "2025-08-04T14:40:34Z")

</div>

I’ve started writing a Julia tutorial for my colleagues and have come to an unexpected realization that I can’t construct a justified example when a non-scoping `begin ... end` block would be really useful. Am I missing something or is it really a historical feature that once was or has been thought to be useful but in practice can be replaced by `let` blocks or non-grouped expressions in all cases?

**PS** For a Pluto cell, using `let` blocks would introduce mild inconveniences when variables need to be visible in the whole notebook, but just marking names as `global` seems to be sufficient, so the non-scoping behavior is still not a strict requirement.

---

<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: [August 4, 2025, 2:56pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/2 "2025-08-04T14:56:36Z")

</div>

You’re right — it’s not common that you need to group expressions in a manner that wouldn’t be better expressed by another language construct. The big exception is macros and metaprogramming. For example, you might want to add timing to some chunk of code without changing its semantics. `@time begin ... end` is a simple answer.

Other macros explicitly expect a `begin`/`end` construct. It’s **the way** to create a “block-like” syntax with macros.

---

<div class="post-metadata">

### Author: ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)
#### Post date: [August 4, 2025, 3:24pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/3 "2025-08-04T15:24:17Z")

</div>

Thanks!  
I was thinking of just normal programming and was unsuccessfully trying to come up with a case where semantically we may need multiple expressions but only one is allowed syntactically. In case of macros, that is indeed quite common and cannot be replaced by other constructs.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [August 4, 2025, 3:44pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/4 "2025-08-04T15:44:23Z")

</div>

Another place where I find it useful, if rarely, is the condition check expressions of `elseif` statements. I can’t move code preparing the conditional checks before the overall `if` statement because I don’t want to unconditionally execute it all, and I don’t want to nest `if` statements in `else` clauses just to execute code after a `false` condition and before checking the following one. `elseif` visually suggests a simple sequence of conditions, so I prefer to reserve nested `if` statements for more branching.

```julia-auto
julia> expensiverandn() = (Libc.systemsleep(0.5); randn())
expensiverandn (generic function with 1 method)

julia> x = expensiverandn() # this part is unconditional
-0.9491878041085057

julia> if x > 0
            println("1st try $x > 0")
       elseif begin # if 1st try was successful, skips all this
          x = expensiverandn() # could be in else clause before if x > Inf
          x > Inf
              end
            println("Won't happen.")
       elseif x > 0 # can reuse x from 2nd call
            println("2nd try $x > 0.")
       elseif (x = expensiverandn()) > 0 # if 2nd try was successful, skips this
            println("3rd try $x > 0.")
       end
2nd try 1.2469240776848027 > 0.

```

That last branch uses `()` as an equivalent to a one-liner `begin end`.

---

<div class="post-metadata">

### Author: ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)
#### Post date: [August 4, 2025, 6:02pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/5 "2025-08-04T18:02:09Z")

</div>

That’s not quite what I asked because it does not matter in the example whether `begin / end` block creates a nested scope or not.  
I did think of a use case of evaluating something inside a condition or a loop condition but could not think of example where evaluating in the parent scope is necessary.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [August 4, 2025, 6:48pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/6 "2025-08-04T18:48:03Z")

</div>

> [@Vasily\_Pisarev](#):
>
> it does not matter in the example whether `begin / end` block creates a nested scope or not.

Not really sure what you mean here. As you’ve noted, `begin` blocks don’t introduce scope, and neither do `if` blocks. My example is only correct and equivalent to nested `if`-`else` blocks with no `begin` blocks if its `begin` block doesn’t introduce a local scope. Replacing the `begin` block with a `let` block would make a new local `x`, a significant change.

---

<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: [August 4, 2025, 7:34pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/7 "2025-08-04T19:34:26Z")

</div>

I think this more is a question of whether an _explicit_ `begin ... end` block is useful. A non-scoping block is implicitly inserted in all the julia constructs which end with `end`, before the code is lowered further. Even inside scoped constructions like `for` and `try` (which at the syntax tree level takes only a single expression as its content).

Any construction which takes just a single expression, like passing an argument to a function, can also take a `begin ... end` block, which is a simpler construction than a `let` (which implicitly contains a `begin ... end` block, and has additional semantics).

So, one might as well ask if julia should have such more or less redundant features.

---

<div class="post-metadata">

### Author: ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)
#### Post date: [August 4, 2025, 7:52pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/8 "2025-08-04T19:52:49Z")

</div>

> [@Benny](#):
>
> Replacing the `begin` block with a `let` block would make a new local `x`, a significant change.

Ah, you’re right, in a global scope it’s a different behavior. But that’s basically the same situation I wrote about in the PS and it would be still possible to do with a `let` block by marking the inner `x` as `global`.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [August 4, 2025, 8:10pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/9 "2025-08-04T20:10:57Z")

</div>

> [@Vasily\_Pisarev](#):
>
> it would be still possible to do with a `let` block by marking the inner `x` as `global`.

A `let` block in the global scope where we have to explicitly mark all variables as `global` is effectively manually stripping it down to the implicit `begin` block inside. This won’t work generally; if we have a `let` block in a outer local scope, we have no manual `outer` option and are fully reliant on the outer local scope assigning the variable somewhere:

```julia-auto
julia> for x = -1.0
       if x > 0
            println("1st try $x > 0")
       elseif let
            y = expensiverandn() # let-scope local y
            y > Inf
          end
            println("Won't happen.")
       elseif y > 0 # no assigned y in for-scope
            println("2nd try $y > 0.")
       elseif (z = expensiverandn()) > 0
            println("3rd try $z > 0.")
       end
       end
ERROR: UndefVarError: `y` not defined in `Main`

```

So why not let people write `begin` if they really mean to not introduce scope? Would `if true ... end` really be worth saving a keyword?

---

<div class="post-metadata">

### Author: ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)
#### Post date: [August 4, 2025, 8:30pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/10 "2025-08-04T20:30:14Z")

</div>

> [@sgaure](#):
>
> I think this more is a question of whether an _explicit_ `begin ... end` block is useful.

Yes, in some sense.

I know that Julia is inspired by Lisp and there `begin` is required because a lot of constructs only take a single expression as an argument. So, it’s logical to assume that it was introduced in Julia because the devs initially thought that it’ll be just as necessary here. And later, it could happen that nobody bothered to review its necessity before 1.0 so it stuck as a legacy feature.

Based on @mbauman’s reply I think it _is_ mostly unnecessary outside metaprogramming (I mean, I do write `x -> begin; something something; end` for lambdas but here it’s wrapped into a function scope so that one wouldn’t notice if `begin` created a scope by itself). But for macros, it seems to be a necessary marker of whether the macro has to be expanded in the current scope or create a nested 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: [August 4, 2025, 8:32pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/11 "2025-08-04T20:32:04Z")

</div>

> [@Vasily\_Pisarev](#):
>
> (I mean, I do write `x -> begin; something something; end` for lambdas but here it’s wrapped into a function scope so that one wouldn’t notice if `begin` created a scope by itself)

There’s also a long-form anonymous function syntax that creates the block for you — that’s more in-line with what I meant by “another language construct.”

```julia-auto
function(x)
  something something
end

```

Macros themselves could choose to require `let` blocks and then completely disregard `let`’s normal semantics. Or anything else. They could really use any block syntax they so chose. But `begin/end` is the simplest and most straightforward thing to use. Note that creating a group of expressions with `(expression; expression; expression)` is creates the identical syntax tree to a begin/end — except the latter will insert line number nodes.

---

<div class="post-metadata">

### Author: ![MDSW](https://avatars.discourse-cdn.com/v4/letter/m/94ad74/32.png) [@MDSW](https://discourse.julialang.org/u/MDSW)
#### Post date: [August 4, 2025, 11:28pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/12 "2025-08-04T23:28:10Z")

</div>

I recently found an interesting use… when you communicate with Julia over `stdio`, if you don’t want every single line writing back `ans` (supression doesn’t work over `stdio`, apparently…), a `begin...end` block keeps things neat _without_ changing the scope of the code within. Useful workaround for a [notebook-style client](https://github.com/mdsw/obsidian-execute-code) where you usually only want the last result back.

---

<div class="post-metadata">

### Author: ![Kirby\_Zhang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kirby_zhang/32/36204_2.png) [@Kirby\_Zhang](https://discourse.julialang.org/u/Kirby_Zhang)
#### Post date: [August 6, 2025, 8:22pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/13 "2025-08-06T20:22:11Z")

</div>

I use it a lot in test code I send to the REPL with Shift-Enter. It functions almost like a cell in an interactive notebook, but without complex dependencies and setup. It took a while to understand this, but non-scoping begin…end blocks are actually a good fit for the interactive style of Julia.

---

<div class="post-metadata">

### Author: ![rafael.guerra](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rafael.guerra/32/216610_2.png) [@rafael.guerra](https://discourse.julialang.org/u/rafael.guerra)
#### Post date: [August 6, 2025, 9:05pm UTC](https://discourse.julialang.org/t/are-non-scoping-begin-end-blocks-useful/131338/14 "2025-08-06T21:05:04Z")

</div>

I use it in one-liners like the following:

```julia
x = (3, "TEMP") # in real code `x` comes from an user terminal input function, which can return nothing

!isnothing(x) && (begin n, dir = x; end)

```

I just remembered one interesting example from [this other post](https://discourse.julialang.org/t/use-condition-result-inside-conditional/52893/6), by the way, which I rewrite here for reference:

```julia-auto
foo() = 3
!isnothing(begin x = foo() end) && println(x)

```
