# Passing \`Symbol\` variable allocates when literal does not?

**URL:** https://discourse.julialang.org/t/passing-symbol-variable-allocates-when-literal-does-not/110518
**Category:** General Usage
**Tags:** memory-allocation, function-parameters, keyword-arguments
**Created:** [February 21, 2024, 2:20pm UTC](https://discourse.julialang.org/t/passing-symbol-variable-allocates-when-literal-does-not/110518 "2024-02-21T14:20:24Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![bremez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bremez/32/38777_2.png) [@bremez](https://discourse.julialang.org/u/bremez)
#### Post date: [February 21, 2024, 2:20pm UTC](https://discourse.julialang.org/t/passing-symbol-variable-allocates-when-literal-does-not/110518/1 "2024-02-21T14:20:24Z")

</div>

I have the following snippet:

```julia
function preparearrays!(arrays, N, L; mode = :all)
    for n in 0:(length(arrays)-1)
        if mode === :all
            for m in 0:(L-1) # run till length L to zero all bits
                arrays[n+1][m+1] = (n & (1 << m)) >> m
            end
        elseif mode === :basis
            arrays[n+1] .= 0;
            arrays[n+1][n+1] = 1;
        end
    end
    return arrays
end

preparearrays(N, L; mode = :all) = preparearrays!(collect(zeros(Int64, L) for i in 1:ifelse(mode==:basis, N, 2^N)), N, L; mode = mode)

```

My issue is that I want to set a variable at the start of my calculation, `mode = :all` or `mode = :basis`. (The above pattern appears in other places in my code.) However, calling the above function with a variable seems to allocate (and dramatically regress performance):

```julia
arr = preparearrays(8, 16; mode = :basis);
@btime preparearrays!(arr, 8, 16; mode = :basis);
# 62.245 ns (0 allocations: 0 bytes)
var = :basis;
@btime preparearrays!(arr, 8, 16; mode = var);
# 183.043 ns (2 allocations: 32 bytes)

```

Any idea where the allocation comes from, and how to avoid it?

---

<div class="post-metadata">

### Author: ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)
#### Post date: [February 21, 2024, 2:35pm UTC](https://discourse.julialang.org/t/passing-symbol-variable-allocates-when-literal-does-not/110518/2 "2024-02-21T14:35:47Z")

</div>

This looks like a benchmarking artifact. Check the documentation of BencharkTools.jl: you should interpolate the global variables that you pass to the benchmarked code:

```julia
julia> @btime preparearrays!(arr, 8, 16; mode = var);
  171.130 ns (2 allocations: 32 bytes)

julia> @btime preparearrays!(arr, 8, 16; mode = $var);
  50.771 ns (1 allocation: 16 bytes)

```

---

<div class="post-metadata">

### Author: ![bremez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bremez/32/38777_2.png) [@bremez](https://discourse.julialang.org/u/bremez)
#### Post date: [February 21, 2024, 2:48pm UTC](https://discourse.julialang.org/t/passing-symbol-variable-allocates-when-literal-does-not/110518/3 "2024-02-21T14:48:06Z")

</div>

You are right. I had only tried interpolated `$arr`…

---

<div class="post-metadata">

### Author: ![bremez](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bremez/32/38777_2.png) [@bremez](https://discourse.julialang.org/u/bremez)
#### Post date: [February 21, 2024, 2:53pm UTC](https://discourse.julialang.org/t/passing-symbol-variable-allocates-when-literal-does-not/110518/4 "2024-02-21T14:53:48Z")

</div>

@sijo though in my defense, `@time` and `@allocated` (which I don’t believe support interpolation?) do report these allocation.

---

<div class="post-metadata">

### Author: ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)
#### Post date: [February 21, 2024, 4:04pm UTC](https://discourse.julialang.org/t/passing-symbol-variable-allocates-when-literal-does-not/110518/5 "2024-02-21T16:04:44Z")

</div>

For these macros I think to avoid these extra allocations you need to use typed globals (or constants but then the benchmark might be affected by constant propagation?)

```julia
using BenchmarkTools

function preparearrays!(arrays, N, L; mode = :all)
    for n in 0:(length(arrays)-1)
        if mode === :all
            for m in 0:(L-1) # run till length L to zero all bits
                arrays[n+1][m+1] = (n & (1 << m)) >> m
            end
        elseif mode === :basis
            arrays[n+1] .= 0;
            arrays[n+1][n+1] = 1;
        end
    end
    return arrays
end

preparearrays(N, L; mode = :all) = preparearrays!(collect(zeros(Int64, L) for i in 1:ifelse(mode==:basis, N, 2^N)), N, L; mode = mode)

arr::Vector{Vector{Int64}} = preparearrays(8, 16; mode = :basis);
var::Symbol = :basis

```

With this I get

```julia
julia> @allocated preparearrays!(arr, 8, 16; mode=var)
0

```

You can also make a wrapper function:

```julia
using BenchmarkTools

function preparearrays!(arrays, N, L; mode = :all)
    for n in 0:(length(arrays)-1)
        if mode === :all
            for m in 0:(L-1) # run till length L to zero all bits
                arrays[n+1][m+1] = (n & (1 << m)) >> m
            end
        elseif mode === :basis
            arrays[n+1] .= 0;
            arrays[n+1][n+1] = 1;
        end
    end
    return arrays
end

preparearrays(N, L; mode = :all) = preparearrays!(collect(zeros(Int64, L) for i in 1:ifelse(mode==:basis, N, 2^N)), N, L; mode = mode)

function get_allocated(arr, var)
    @allocated preparearrays!(arr, 8, 16; mode=var)
end

arr = preparearrays(8, 16; mode = :basis);
var = :basis;

get_allocated(arr, var) # returns 0

```
