# Reassigning variable in do syntax is not optimized, \`\`Ref\`\` is, what is the difference?

**URL:** <https://discourse.julialang.org/t/reassigning-variable-in-do-syntax-is-not-optimized-ref-is-what-is-the-difference/17635>\
**Category:** Performance\
**Tags:** question\
**Created:** [November 17, 2018, 8:57am UTC](https://discourse.julialang.org/t/reassigning-variable-in-do-syntax-is-not-optimized-ref-is-what-is-the-difference/17635 "2018-11-17T08:57:19Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 17, 2018, 8:57am UTC](https://discourse.julialang.org/t/reassigning-variable-in-do-syntax-is-not-optimized-ref-is-what-is-the-difference/17635/1 "2018-11-17T08:57:19Z")

</div>

I frequently stumble about examples similar to the following, where I have a helper function which supports `do` style anonymous functions

```julia
helper(cont, range) = for i ∈ range
  cont(i)
end

```

and want to write something which uses it by for instance accumulating the results

```julia
function f()
  a = 0
  helper(1:4) do i
    a += i
  end
  a
end

```

the generated code looks super complicated

> **julia\> @code\_llvm f()**
>
> ```nohighlight
> julia> @code_llvm f()
> ; Function f
> ; Location: D:\ProjectsJulia\Traits\test\tmp.jl:76
> ; Function Attrs: uwtable
> define nonnull %jl_value_t addrspace(10)* @japi1_f_37345(%jl_value_t addrspace(10)*, %jl_value_t add
> rspace(10)**, i32) #0 {
> top:
> %gcframe = alloca %jl_value_t addrspace(10)*, i32 4
> %3 = bitcast %jl_value_t addrspace(10)** %gcframe to i8*
> call void @llvm.memset.p0i8.i32(i8* %3, i8 0, i32 32, i32 0, i1 false)
> %4 = alloca %jl_value_t addrspace(10)**, align 8
> store volatile %jl_value_t addrspace(10)**%1, %jl_value_t addrspace(10)*** %4, align 8
> %5 = call %jl_value_t***inttoptr (i64 18155948864 to %jl_value_t*** ()*)() #6
> ; Function Type; {
> ; Location: boot.jl:328
> %6 = getelementptr %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %gcframe, i32 0
> %7 = bitcast %jl_value_t addrspace(10)** %6 to i64*
> store i64 4, i64* %7
> %8 = getelementptr %jl_value_t **, %jl_value_t*** %5, i32 0
> %9 = getelementptr %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %gcframe, i32 1
> %10 = bitcast %jl_value_t addrspace(10) **%9 to %jl_value_t***
> %11 = load %jl_value_t **, %jl_value_t*** %8
> store %jl_value_t **%11, %jl_value_t*** %10
> %12 = bitcast %jl_value_t***%8 to %jl_value_t addrspace(10)***
> store %jl_value_t addrspace(10)**%gcframe, %jl_value_t addrspace(10)*** %12
> %13 = bitcast %jl_value_t*** %5 to i8*
> %14 = call noalias nonnull %jl_value_t addrspace(10)* @jl_gc_pool_alloc(i8* %13, i32 1488, i32 16)
> #1
> %15 = bitcast %jl_value_t addrspace(10)* %14 to %jl_value_t addrspace(10)* addrspace(10)*
> %16 = getelementptr %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)* addrspace(10)* %15, i64
> -1
> store %jl_value_t addrspace(10)* addrspacecast (%jl_value_t* inttoptr (i64 21670413472 to %jl_valu
> e_t*) to %jl_value_t addrspace(10)*), %jl_value_t addrspace(10)* addrspace(10)* %16
> %17 = addrspacecast %jl_value_t addrspace(10)* %14 to %jl_value_t addrspace(11)*
> %18 = bitcast %jl_value_t addrspace(11)* %17 to %jl_value_t addrspace(10)* addrspace(11)*
> ;}
> %19 = bitcast %jl_value_t addrspace(10)* %14 to %jl_value_t addrspace(10)* addrspace(10)*
> store %jl_value_t addrspace(10)* addrspacecast (%jl_value_t* inttoptr (i64 70946288 to %jl_value_t
> *) to %jl_value_t addrspace(10)*), %jl_value_t addrspace(10)* addrspace(10)* %19, align 8
> %20 = getelementptr %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %gcframe, i32 3
> store %jl_value_t addrspace(10)* %14, %jl_value_t addrspace(10)** %20
> ; Location: D:\ProjectsJulia\Traits\test\tmp.jl:77
> %21 = call noalias nonnull %jl_value_t addrspace(10)* @jl_gc_pool_alloc(i8* %13, i32 1488, i32 16)
> #1
> %22 = bitcast %jl_value_t addrspace(10)* %21 to %jl_value_t addrspace(10)* addrspace(10)*
> %23 = getelementptr %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)* addrspace(10)* %22, i64
> -1
> store %jl_value_t addrspace(10)* addrspacecast (%jl_value_t* inttoptr (i64 135523168 to %jl_value_
> t*) to %jl_value_t addrspace(10)*), %jl_value_t addrspace(10)* addrspace(10)* %23
> %24 = bitcast %jl_value_t addrspace(10)* %21 to %jl_value_t addrspace(10)* addrspace(10)*
> store %jl_value_t addrspace(10)* %14, %jl_value_t addrspace(10)* addrspace(10)* %24, align 8
> %25 = getelementptr %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %gcframe, i32 2
> store %jl_value_t addrspace(10)* %21, %jl_value_t addrspace(10)** %25
> ; Function helper; {
> ; Location: D:\ProjectsJulia\Traits\test\tmp.jl:62
> %26 = call nonnull %jl_value_t addrspace(10)* @"julia_#31_37346"(%jl_value_t addrspace(10)* nonnull %21, i64 1)
> %27 = call nonnull %jl_value_t addrspace(10)* @"julia_#31_37346"(%jl_value_t addrspace(10)* nonnull %21, i64 2)
> %28 = call nonnull %jl_value_t addrspace(10)* @"julia_#31_37346"(%jl_value_t addrspace(10)* nonnull %21, i64 3)
> %29 = call nonnull %jl_value_t addrspace(10)* @"julia_#31_37346"(%jl_value_t addrspace(10)* nonnull %21, i64 4)
> ;}
> ; Location: D:\ProjectsJulia\Traits\test\tmp.jl:80
> %30 = load %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)* addrspace(11)* %18, align 8
> %31 = icmp eq %jl_value_t addrspace(10)* %30, null
> br i1 %31, label %err, label %pass
> 
> pass: ; preds = %top
> %32 = getelementptr %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %gcframe, i32 1
> %33 = load %jl_value_t addrspace(10)*, %jl_value_t addrspace(10)** %32
> %34 = getelementptr %jl_value_t **, %jl_value_t*** %5, i32 0
> %35 = bitcast %jl_value_t***%34 to %jl_value_t addrspace(10)**
> store %jl_value_t addrspace(10)* %33, %jl_value_t addrspace(10)** %35
> ret %jl_value_t addrspace(10)* %30
> 
> err: ; preds = %top
> call void @jl_undefined_var_error(%jl_value_t addrspace(12)* addrspacecast (%jl_value_t* inttoptr (i64 70912160 to %jl_value_t*) to %jl_value_t addrspace(12)*))
> unreachable
> }
> 
> ```

with the little help of `Ref`, everything condenses nicely to a constant function

```julia
function g()
  a = Ref(0)
  helper(1:4) do i
    a.x += i
  end
  a.x
end

```

gives

```julia
julia> @code_llvm g()
; Function g
; Location: D:\ProjectsJulia\Traits\test\tmp.jl:67
; Function Attrs: uwtable
define i64 @julia_g_37350() #0 {
top:
; Location: D:\ProjectsJulia\Traits\test\tmp.jl:71
  ret i64 10
}

```

What is the decisive difference here?  
Can I adapt `f()` so that it gains the same powerup as `g()`?

> **extra: @code\_warntype look similar**
>
> here the `@code_warntype` - I cannot spot the decisive difference unfortunately, it looks astonishingly similar to me
> 
> ```julia
> julia> @code_warntype f()
> Body::Any
> 76 1 ── %1 = %new(Core.Box)::Core.Box │╻ Type
> │ (Core.setfield!)(%1, :contents, 0) │
> 77 │ %3 = %new(Main.:(##35#36), %1)::getfield(Main, Symbol("##35#36")) │
> │ (Base.ifelse)(true, 4, 0) ││╻╷ Type
> │ %5 = (Base.slt_int)(4, 1)::Bool ││╻╷╷╷ iterate
> └─── goto #3 if not %5 │││
> 2 ── goto #4 │││
> 3 ── goto #4 │││
> 4 ┄─ %9 = φ (#2 => true, #3 => false)::Bool ││
> │ %10 = φ (#3 => 1)::Int64 ││
> │ %11 = φ (#3 => 1)::Int64 ││
> │ %12 = (Base.not_int)(%9)::Bool ││
> └─── goto #10 if not %12 ││
> 5 ┄─ %14 = φ (#4 => %10, #9 => %22)::Int64 ││
> │ %15 = φ (#4 => %11, #9 => %23)::Int64 ││
> │ invoke %3(%14::Int64) ││
> │ %17 = (%15 === 4)::Bool │││╻ ==
> └─── goto #7 if not %17 │││
> 6 ── goto #8 │││
> 7 ── %20 = (Base.add_int)(%15, 1)::Int64 │││╻ +
> └─── goto #8 ││╻ iterate
> 8 ┄─ %22 = φ (#7 => %20)::Int64 ││
> │ %23 = φ (#7 => %20)::Int64 ││
> │ %24 = φ (#6 => true, #7 => false)::Bool ││
> │ %25 = (Base.not_int)(%24)::Bool ││
> └─── goto #10 if not %25 ││
> 9 ── goto #5 ││
> 10 ─ goto #11 ││
> 80 11 ─ %29 = (Core.isdefined)(%1, :contents)::Bool │
> └─── goto #13 if not %29 │
> 12 ─ goto #14 │
> 13 ─ $(Expr(:throw_undef_if_not, :a, false)) │
> 14 ┄ %33 = (Core.getfield)(%1, :contents)::Any │
> └─── return %33 │
> 
> julia> @code_warntype g()
> Body::Int64
> 67 1 ── %1 = %new(Base.RefValue{Int64}, 0)::Base.RefValue{Int64} │╻╷╷ Type
> 68 │ (Base.ifelse)(true, 4, 0) │╻╷╷ Colon
> │ %3 = (Base.slt_int)(4, 1)::Bool ││╻╷╷╷ iterate
> └─── goto #3 if not %3 │││
> 2 ── goto #4 │││
> 3 ── goto #4 │││
> 4 ┄─ %7 = φ (#2 => true, #3 => false)::Bool ││
> │ %8 = φ (#3 => 1)::Int64 ││
> │ %9 = φ (#3 => 1)::Int64 ││
> │ %10 = (Base.not_int)(%7)::Bool ││
> └─── goto #10 if not %10 ││
> 5 ┄─ %12 = φ (#4 => %8, #9 => %22)::Int64 ││
> │ %13 = φ (#4 => %9, #9 => %23)::Int64 ││
> │ %14 = (Base.getfield)(%1, :x)::Int64 ││╻╷ #29
> │ %15 = (Base.add_int)(%14, %12)::Int64 │││╻ +
> │ (Base.setfield!)(%1, :x, %15) │││╻ setproperty!
> │ %17 = (%13 === 4)::Bool │││╻ ==
> └─── goto #7 if not %17 │││
> 6 ── goto #8 │││
> 7 ── %20 = (Base.add_int)(%13, 1)::Int64 │││╻ +
> └─── goto #8 ││╻ iterate
> 8 ┄─ %22 = φ (#7 => %20)::Int64 ││
> │ %23 = φ (#7 => %20)::Int64 ││
> │ %24 = φ (#6 => true, #7 => false)::Bool ││
> │ %25 = (Base.not_int)(%24)::Bool ││
> └─── goto #10 if not %25 ││
> 9 ── goto #5 ││
> 10 ─ goto #11 ││
> 71 11 ─ %29 = (Base.getfield)(%1, :x)::Int64 │╻ getproperty
> └─── return %29            
> 
> ```

---

<div class="post-metadata">

**Author:** ![schlichtanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/schlichtanders/32/32145_2.png) [@schlichtanders](https://discourse.julialang.org/u/schlichtanders)\
**Post date:** [November 17, 2018, 9:00am UTC](https://discourse.julialang.org/t/reassigning-variable-in-do-syntax-is-not-optimized-ref-is-what-is-the-difference/17635/2 "2018-11-17T09:00:53Z")

</div>

using [Traceur.jl](https://github.com/MikeInnes/Traceur.jl) there is a indeed a huge difference, however I am too unexperienced about how to use the Traceur suggestions from `@trace f()` to improve it towards `g()`

```julia
julia> @trace f()
┌ Warning: dynamic dispatch to (Core.getfield)((Core.getfield)(#self#, a), contents) + i
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: getfield(Main, Symbol("##13#14"))(Core.Box(1)) returns Any
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: dynamic dispatch to (Core.getfield)((Core.getfield)(#self#, a), contents) + i
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: getfield(Main, Symbol("##13#14"))(Core.Box(3)) returns Any
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: dynamic dispatch to (Core.getfield)((Core.getfield)(#self#, a), contents) + i
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: getfield(Main, Symbol("##13#14"))(Core.Box(6)) returns Any
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: dynamic dispatch to (Core.getfield)((Core.getfield)(#self#, a), contents) + i
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: getfield(Main, Symbol("##13#14"))(Core.Box(10)) returns Any
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:69
┌ Warning: f returns Any
└ @ D:\ProjectsJulia\Traits\test\tmp.jl:76

julia> @trace g()
10

```
