# How to capture an index in closure without allocating (or workaround)?

**URL:** <https://discourse.julialang.org/t/how-to-capture-an-index-in-closure-without-allocating-or-workaround/76334>\
**Category:** Performance\
**Tags:** closure\
**Created:** [February 13, 2022, 9:19am UTC](https://discourse.julialang.org/t/how-to-capture-an-index-in-closure-without-allocating-or-workaround/76334 "2022-02-13T09:19:19Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![taotree](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taotree/32/31982_2.png) [@taotree](https://discourse.julialang.org/u/taotree)\
**Post date:** [February 13, 2022, 9:19am UTC](https://discourse.julialang.org/t/how-to-capture-an-index-in-closure-without-allocating-or-workaround/76334/1 "2022-02-13T09:19:19Z")

</div>

Sorry the code is a bit long but the middle `testIt!` function is where the question is. If I run `run()` as-is, there are ~160k allocations. However, if I comment out the code with `i`, then there are no allocations. I’m assuming this is because it has to box `i` to capture it in the closure. I ran @code\_warntype on both cases and they’re both fine except there is an `i::Core.Box` when the `i` var is there. Is there way to structure this simply that will avoid allocations?

```julia
function itrCombis(f, v, ::Val{4})
    len = length(v)
    for i in 1:len
        for j in i:len
            for k in j:len
                for l in k:len
                    f((v[i], v[j], v[k], v[l]))
                end
            end
        end
    end
end

function testIt!(res, v1, v2)
    i = 0 # Ref{Int}(0)
    function inner(c1, c2)
        allCombi = Iterators.flatten(Iterators.product(c1, c2))
        for combi in allCombi
            i += 1 # i[] += 1
            res[i] = combi[1] > 5.0 ? nothing : 2.0
        end
        return
    end

    function outer(c1)
        itrCombis(c2 -> inner(c1, c2), v2, Val(4))
        return
    end

    itrCombis(outer, v1, Val(4))
    return
end

function run()
    res = Vector{Union{Nothing,Float64}}(undef, 100000000)
    num = 5
    v1 = collect(1:num)
    v2 = collect(1:num)
    testIt!(res, v1, v2)
    @time testIt!(res, v1, v2)
end

```

I tried using `i = Ref{Int}(0)` and that helped a lot. But it still allocates `(1 allocation: 16 bytes)`, which is much better. I could probably thread the index through the functions, but I wanted to ask if there is maybe some way to do this type of closures without allocations.

I was using the Combinatorics package originally, but discovered that its combinations function allocates, so that’s why I put in the `itrCombis` function in the example here.

---

<div class="post-metadata">

**Author:** ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)\
**Post date:** [February 13, 2022, 10:19am UTC](https://discourse.julialang.org/t/how-to-capture-an-index-in-closure-without-allocating-or-workaround/76334/2 "2022-02-13T10:19:33Z")

</div>

Can’t test this but is the allocation maybe just from benchmarking with `@time` instead of `@btime`?

---

<div class="post-metadata">

**Author:** ![taotree](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/taotree/32/31982_2.png) [@taotree](https://discourse.julialang.org/u/taotree)\
**Post date:** [February 13, 2022, 4:19pm UTC](https://discourse.julialang.org/t/how-to-capture-an-index-in-closure-without-allocating-or-workaround/76334/3 "2022-02-13T16:19:18Z")

</div>

No. You’ll see it does run testIt before the @time, so it’s timing the second run. Also, I have run @btime directly against testit() from the REPL for all three cases and it shows the same results.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [February 13, 2022, 6:29pm UTC](https://discourse.julialang.org/t/how-to-capture-an-index-in-closure-without-allocating-or-workaround/76334/4 "2022-02-13T18:29:11Z")

</div>

Maybe this is what you need: [https://github.com/c42f/FastClosures.jl](https://github.com/c42f/FastClosures.jl)

But that `i` update inside the closure seems a bug minefield to me. Can’t you pass it as a parameter so you can be sure what are you updating?

---

<div class="post-metadata">

**Author:** ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)\
**Post date:** [February 14, 2022, 9:20pm UTC](https://discourse.julialang.org/t/how-to-capture-an-index-in-closure-without-allocating-or-workaround/76334/5 "2022-02-14T21:20:36Z")

</div>

Remembering that “Closures are poor man’s objects and objects are poor man’s closures” you can explicitly represent and pass in your closure:

```julia
mutable struct MyInner{T1, T2}
    i::T1
    res::T2
end

function (in::MyInner)(c1, c2)
    allCombi = Iterators.flatten(Iterators.product(c1, c2))
    for combi in allCombi
        in.i += 1
        in.res[in.i] = combi[1] > 5.0 ? nothing : 2.0
    end
    return
end

function testIt!(inner, v1, v2)
    function outer(c1)
        itrCombis(c2 -> inner(c1, c2), v2, Val(4))
        return
    end
    
    itrCombis(outer, v1, Val(4))
    return
end

function run()
    res = Vector{Union{Nothing,Float64}}(undef, 100000000)
    num = 5
    v1 = collect(1:num)
    v2 = collect(1:num)
    in = MyInner(0, res)
    testIt!(in, v1, v2)
    @time testIt!(in, v1, v2)
end

```

Don’t think its worth the effort, just to prevent 16 bytes of allocation.
