# Retrieve a value within a do block

**URL:** <https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121>\
**Category:** General Usage\
**Tags:** question, jump\
**Created:** [July 28, 2025, 1:54am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121 "2025-07-28T01:54:27Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [July 28, 2025, 1:54am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/1 "2025-07-28T01:54:27Z")

</div>

```julia
julia> function a_correct_way_to_build_with_multithreading()
           model = Model()
           @variable(model, x[1:10])
           my_lock = Threads.ReentrantLock()
           Threads.@threads for i in 1:10
               con = @build_constraint(x[i] <= i)
               Threads.lock(my_lock) do
                   add_constraint(model, con)
               end
           end
           return model
       end

```

The code above from JuMP’s [doc](https://jump.dev/JuMP.jl/stable/tutorials/algorithms/parallelism/#Example:-building-data-structures-in-parallel) can be improved, if I want to have access to a reference of the `con` added.  
Here is a feasible method

```julia
con = JuMP.@build_constraint(x[1] <= 1)
cut = false # initialize a concrete object of JuMP.ConstraintRef (I don't know how to, thus use `false` instead)
Threads.lock(my_lock) do
    cut = JuMP.add_constraint(model, con) # retrieve the reference
end
# [important] Now I can do something with `cut` here

```

Are there any alternatives?

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [July 28, 2025, 5:30am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/2 "2025-07-28T05:30:59Z")

</div>

Is my “feasible” method above correct? I’m a bit unclear now, since `do` is a hard local block.

```julia
julia> function f(af)
           a = 3
           println("inside function: a = $a")
       end
f (generic function with 1 method)

julia> a = 0;

julia> for i = 1:1
           a = 2
           f() do
               a = 7
           end
           println("inside for: a = $a")
       end
inside function: a = 3
inside for: a = 2

julia> a
2

```

Given this fact, how can my following analogous code be made correct?

```julia
julia> Threads.nthreads()
4

julia> using JuMP

julia> my_lock = Threads.ReentrantLock();

julia> model = Model();

julia> JuMP.@variable(model, x[1:3]);

julia> for k = 1:1
           Threads.@threads for i = 1:3
               # The following line is indispensable. If it's absent, ERROR is seen
               cut = "the initial cut inside for i = $i"
               con = @build_constraint(x[i] <= i)
               Threads.lock(my_lock) do
                   cut = JuMP.add_constraint(model, con)
               end
               println("at the end of i = $i, cut = $cut")
           end
       end
at the end of i = 1, cut = x[1] <= 1
at the end of i = 3, cut = x[3] <= 3
at the end of i = 2, cut = x[2] <= 2

julia> print(model)
Feasibility
Subject to
 x[3] <= 3
 x[1] <= 1
 x[2] <= 2

```

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [July 28, 2025, 9:33am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/3 "2025-07-28T09:33:04Z")

</div>

Discussed in more detail in [A different do block scope rule exist for `Threads.lock(my_lock)`?](https://discourse.julialang.org/t/a-different-do-block-scope-rule-exist-for-threads-lock-my-lock/131124)

This is unrelated to JuMP.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [July 28, 2025, 11:18am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/4 "2025-07-28T11:18:07Z")

</div>

The question is written in the title.  
The code within `do-end` is essentially the body of an anonymous function. Although it appears that my method works, I don’t think it is decent. Can you think of a better alternative?

The following code explains why I think my crude method is fragile

```julia
# open a new julia REPL
julia> for _ = 1:1
           cut = false
           map([1, 3]) do x
               cut = rand()
               x^2
           end
           println("cut = $cut")
       end
cut = 0.8839225864031239

julia> cut = false;

julia> for _ = 1:1
           cut = false
           map([1, 3]) do x
               cut = rand()
               x^2
           end
           println("cut = $cut")
       end
cut = false

```

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [July 28, 2025, 1:30pm UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/5 "2025-07-28T13:30:09Z")

</div>

> [@WalterMadelim](#):
>
> Can you think of a better alternative?

I can provide a solution—use `try` instead of the complex `do` syntax—as follows

```julia
import JuMP, Gurobi; GRB_ENV = Gurobi.Env();
my_lock = Threads.ReentrantLock();
std_val = sum(1:1000000);
model = JuMP.Model(() -> Gurobi.Optimizer(GRB_ENV));
JuMP.@variable(model, x[1:1000000]);
for _ = 1:1 # This loop imitates the main training loop for some algorithm (e.g. Benders)
    Threads.@threads for j = 1:1000000 # blocks are executed in parallel
        local con = JuMP.@build_constraint(x[j] ≤ j)
        local cut = false
        lock(my_lock)
        try
            cut = JuMP.add_constraint(model, con) # ::JuMP.ConstraintRef
        finally
            unlock(my_lock)
        end
        # ★ Important ★ You can do something with `cut` HERE, e.g.
        JuMP.owner_model(cut) == model || error()
    end
end
JuMP.@objective(model, Max, sum(x));
JuMP.optimize!(model); JuMP.assert_is_solved_and_feasible(model; allow_local = false)
Δ = std_val - JuMP.objective_value(model)
abs(Δ) < 1e-11 && @info "test success"

```

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [July 28, 2025, 9:00pm UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/6 "2025-07-28T21:00:55Z")

</div>

There are many different ways you can achieve your goal, none of which rely on scoping rules for making the `cut` binding available in an outer scope.

A `do` block is just syntactic sugar for defining a function. You can return values from a function:

```Julia
julia> run_do_block(f) = f()
run_do_block (generic function with 1 method)

julia> cut = 0
0

julia> run_do_block() do
           cut = 1
       end
1

julia> cut
0

julia> cut = run_do_block() do
           cut = 1
           return cut
       end
1

julia> cut
1

```

Or you could use a mutable data structure (like a Ref or a Vector) for storing the value:

```julia
julia> ret = Ref{Any}()
Base.RefValue{Any}(#undef)

julia> run_do_block() do
           cut = 1
           ret[] = cut
           return nothing
       end

julia> cut = ret[]
1

```

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [July 29, 2025, 12:03am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/7 "2025-07-29T00:03:32Z")

</div>

> [@odow](#):
>
> ```julia-auto
> julia> cut
> 0
> 
> julia> cut = run_do_block() do
> cut = 1
> return cut
> end
> 1
> 
> julia> cut
> 1
> 
> ```

I’m afraid this method is unusable, and it is somewhat misleading for a new user. The reason is that in my context, the counterpart of `run_do_block` is `Thread.lock`. You have no idea what the concrete implementation of `Thread.lock` is—for example, it can `return nothing`—e.g.

```julia
julia> function run_do_block(f) # the concrete code implementation is entailed for proper inference
           f()
           return nothing
       end;

julia> cut = run_do_block() do # Here cut = the UPPER "return", not THIS "return"
           cut = 1
           return cut
       end;

julia> isnothing(cut) # it depends on the concrete code implementation of `run_do_block`
true

```

A related [post](https://discourse.julialang.org/t/will-my-variable-be-modified-in-a-do-block-very-subtle-to-anticipate/131124/12).

---

<div class="post-metadata">

**Author:** ![odow](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/odow/32/28685_2.png) [@odow](https://discourse.julialang.org/u/odow)\
**Post date:** [July 29, 2025, 12:20am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/8 "2025-07-29T00:20:39Z")

</div>

It works for `Threads.lock`:

```julia
julia> lock = ReentrantLock();

julia> ret = Threads.lock(lock) do
           return "The value of ret"
       end
"The value of ret"

julia> ret
"The value of ret"

```

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [July 29, 2025, 12:32am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/9 "2025-07-29T00:32:25Z")

</div>

> [@odow](#):
>
> It works for `Threads.lock`:

meaning that the `lock` function happens to return what the anonymous function returns. The correctness depends on the concrete implementation of `lock`, which is invisible from user’s side.

By comparison, your `Ref` method is more agreeable.

```julia
import JuMP, Gurobi; GRB_ENV = Gurobi.Env();
my_lock = Threads.ReentrantLock();
std_val = sum(1:1000000);
model = JuMP.Model(() -> Gurobi.Optimizer(GRB_ENV));
JuMP.@variable(model, x[1:1000000]);
for _ = 1:1 # This loop imitates the main training loop for some algorithm (e.g. Benders)
    Threads.@threads for j = 1:1000000 # blocks are executed in parallel
        local con = JuMP.@build_constraint(x[j] ≤ j)
        local ref = Ref{JuMP.ConstraintRef}()
        Threads.lock(my_lock) do
            ref[] = JuMP.add_constraint(model, con)
            nothing # you can do some other tasks here
        end
        # ★ Important ★ You can do something with `ref[]` HERE, e.g.
        JuMP.owner_model(ref[]) == model || error()
    end
end
JuMP.@objective(model, Max, sum(x));
JuMP.optimize!(model); JuMP.assert_is_solved_and_feasible(model; allow_local = false)
Δ = std_val - JuMP.objective_value(model)
abs(Δ) < 1e-11 && @info "test success"

```

---

<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:** [July 30, 2025, 9:18am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/10 "2025-07-30T09:18:01Z")

</div>

> [@WalterMadelim](#):
>
> meaning that the `lock` function happens to return what the anonymous function returns. The correctness depends on the concrete implementation of `lock`, which is invisible from user’s side.

The doc for `lock(f::Function, lock)` does not explicitly state that it returns the value of `f`. I think it should have. I doubt it will ever change, there is no reason to change it, and too many rely on this functionality. Anyway, if you think this is a problem, you can instead use

```julia-auto
ret = @lock lock begin
    stuff
    more stuff
    v # return value
end

```

The doc states what it expands to,

> [@](#):
>
> ```julia-auto
> @lock l expr
> 
> ```
> 
> Macro version of `lock(f, l::AbstractLock)` but with `expr` instead of `f` function. Expands to:
> 
> ```julia-auto
> lock(l)
> try
> expr
> finally
> unlock(l)
> end
> 
> ```

That is, it’s documented that it returns the value of `expr`.

---

<div class="post-metadata">

**Author:** ![WalterMadelim](https://avatars.discourse-cdn.com/v4/letter/w/3e96dc/32.png) [@WalterMadelim](https://discourse.julialang.org/u/WalterMadelim)\
**Post date:** [July 30, 2025, 10:06am UTC](https://discourse.julialang.org/t/retrieve-a-value-within-a-do-block/131121/11 "2025-07-30T10:06:15Z")

</div>

I like it. Now we have all three methods, with the macro version being

```julia
# ... omit the same code ...
Threads.@threads for j = 1:1000000 # blocks are executed in parallel
        local con = JuMP.@build_constraint(x[j] ≤ j)
        local cut = @lock my_lock JuMP.add_constraint(model, con)
        JuMP.owner_model(cut) == model || error()
end
# ... omit the same code ...

```
