# Initializing an array with literals without allocating a temporary

**URL:** https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590
**Category:** General Usage
**Created:** [August 8, 2020, 10:28pm UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590 "2020-08-08T22:28:29Z")
**Posts on this page:** 19
**Page:** 1

<div class="post-metadata">

### Author: ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)
#### Post date: [August 8, 2020, 10:28pm UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/1 "2020-08-08T22:28:29Z")

</div>

In this example:

```julia
buf = Int64[0, 0, 0, 0]

function foo(buf)
  buf[1] = 3
  buf[2] = 1
  buf[3] = 4
  buf[4] = 1
  nothing
end

function baz(buf)
  buf = [3, 1, 4, 1]
  nothing
end

```

`foo` doesn’t allocate, but is a bit tedious to type; `baz` is short, but allocates a temporary array:

```julia
julia> @btime foo($buf)
  1.841 ns (0 allocations: 0 bytes)

julia> @btime baz($buf)
  18.942 ns (1 allocation: 112 bytes)

```

Is there a best of both option?

**SOLUTION**

Macros offered by @Henrique_Becker and @rdeits are great solutions to this problem. Discourse allows selecting only one solution, so I decided to do it differently.

---

<div class="post-metadata">

### Author: ![tomerarnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomerarnon/32/3170_2.png) [@tomerarnon](https://discourse.julialang.org/u/tomerarnon)
#### Post date: [August 8, 2020, 10:32pm UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/2 "2020-08-08T22:32:05Z")

</div>

```julia
julia> function baz(buf)
         buf .= (3, 1, 4, 1)
         nothing
       end
baz (generic function with 1 method)

julia> @btime baz($buf)
  5.512 ns (0 allocations: 0 bytes)

julia> @btime foo($buf)
  2.640 ns (0 allocations: 0 bytes)

```

Close.

---

<div class="post-metadata">

### Author: ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)
#### Post date: [August 8, 2020, 11:36pm UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/3 "2020-08-08T23:36:45Z")

</div>

> [@pauljurczak](#):
>
> ```julia
> function baz(buf)
> buf = [3, 1, 4, 1]
> nothing
> end
> 
> ```

Note that this _doesn’t_ mutate `buf`, and would ideally be a no-op.

---

<div class="post-metadata">

### Author: ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)
#### Post date: [August 9, 2020, 12:11am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/4 "2020-08-09T00:11:10Z")

</div>

> [@DNF](#):
>
> this _doesn’t_ mutate `buf`

Good point! Old habits die so hard…

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [August 9, 2020, 12:18am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/5 "2020-08-09T00:18:04Z")

</div>

> [@tomerarnon](#):
>
> `buf .= (3, 1, 4, 1)`

ah, sneaky, if use `Array` here (which is not heap allocated), it takes x5 times.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [August 9, 2020, 1:07am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/6 "2020-08-09T01:07:34Z")

</div>

@jling I think you meant

> [@jling](#):
>
> if use `Array` here (which is ~~not~~ heap allocated), it takes x5 times.

@pauljurczak, the version @tomerarnon wrote is the right way to do it. It is slightly slower, so if you want blazing speed (I find this hardly necessary, but I do not know your use case) ~~you could write a macro that expands to the tedious code you write in `foo`~~ , nevermind, I wrote it, it is ugly as hell, my first non-trivial macro, and will probably break if you do anything unexpected, but it is the same as writing that tedious code by hand.

```julia
julia> macro assign(vector, values)
          code = :(begin end)
          for (i, v) in enumerate(values.args)
              code = :($code; $(esc(vector))[$i] = $v)
          end
          return code
       end

julia> function foobar(buf)
           @assign buf (3, 1, 4, 1)
           nothing
       end

julia> buf = [0, 0, 0, 0];

julia> function foo(buf) # the original
         buf[1] = 3
         buf[2] = 1
         buf[3] = 4
         buf[4] = 1
         nothing
       end

julia> @code_lowered foo(buf)
CodeInfo(
1 ─ Base.setindex!(buf, 3, 1)
│ Base.setindex!(buf, 1, 2)
│ Base.setindex!(buf, 4, 3)
│ Base.setindex!(buf, 1, 4)
└── return Main.nothing
)

julia> @code_lowered foobar(buf)
CodeInfo(
1 ─ Base.setindex!(buf, 3, 1)
│ Base.setindex!(buf, 1, 2)
│ Base.setindex!(buf, 4, 3)
│ Base.setindex!(buf, 1, 4)
└── return Main.nothing
)

julia> @btime foo($buf)
  2.551 ns (0 allocations: 0 bytes)

julia> @btime foobar($buf)
  2.247 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [August 9, 2020, 1:09am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/7 "2020-08-09T01:09:10Z")

</div>

I was just passing by but now I’m impressed by your effort

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [August 9, 2020, 1:15am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/8 "2020-08-09T01:15:33Z")

</div>

You can automate the boring way with a macro:

```julia
julia> using MacroTools

julia> macro fill(lhs, rhs)
         @capture rhs [elements__]
         quote
           begin
             @assert firstindex($(esc(lhs))) == 1 && length($(esc(lhs))) == $(length(elements))
             $([:($(esc(lhs))[$i] = $(esc(element))) for (i, element) in enumerate(elements)]...)
             $(esc(lhs))
           end
         end
       end
@fill (macro with 1 method)

```

Usage:

```julia
julia> x = zeros(5)
5-element Array{Float64,1}:
 0.0
 0.0
 0.0
 0.0
 0.0

julia> @fill x [1, 2, 3, 4, 5]
5-element Array{Float64,1}:
 1.0
 2.0
 3.0
 4.0
 5.0

julia> x
5-element Array{Float64,1}:
 1.0
 2.0
 3.0
 4.0
 5.0

```

Edit: Dang! @Henrique_Becker beat me to it 😉

Edit2: Fixed assertion, per @pauljurczak’s suggestion.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [August 9, 2020, 1:16am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/9 "2020-08-09T01:16:42Z")

</div>

XD, I have always shied away from writing macros because I already failed at it many times, but while I was writing the answer I was thinking “this really should be a macro, it really should not be that hard, I should be able to write something that, in fact it would be a good learning experience for me”, so I ended up writing it more because I decided it was the time for me to finally try to learn macros again than because I really think it is a must have.

It probably have a lot of problems in it, however. That `values.args` seems something that could break easily (it does not handle, for example, passing a name of a tuple variable in the local scope, it needs to be the tuple itself in the `@assign` line).

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [August 9, 2020, 1:19am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/10 "2020-08-09T01:19:37Z")

</div>

Your macro is probably more robust, XD. If you can criticize mine, I would be happy to learn the details of how truly horrifying is that macro code.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [August 9, 2020, 1:29am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/11 "2020-08-09T01:29:17Z")

</div>

Haha, no, you did fine 🙂

I think you’re missing an escape on the right-hand side of each assignment. You have `$v` which should be `$(esc(v))`. You can see why this matters if you test in a function:

```julia
julia> function test!(x)
         a = 1
         @assign x [a, 2, 3, 4, 5]
       end
test! (generic function with 1 method)

julia> test!(x)
ERROR: UndefVarError: a not defined

```

The missing `esc` means you end up trying to read a variable named `a` in _global_ scope, not the local one with that name.

Adding `esc` fixes it:

```julia
julia> macro assign(vector, values)
          code = :(begin end)
          for (i, v) in enumerate(values.args)
              code = :($code; $(esc(vector))[$i] = $(esc(v)))
          end
          return code
       end
@assign (macro with 1 method)

julia> function test!(x)
         a = 1
         @assign x [a, 2, 3, 4, 5]
       end
test! (generic function with 1 method)

julia> test!(x)
5

```

I agree that using `.args` directly is sketchy. I really like using `@capture` from MacroTools.jl` for this, since you can unpack exactly the syntax you expect (e.g. a list or a tuple) and get an error for any other syntax.

---

<div class="post-metadata">

### Author: ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)
#### Post date: [August 9, 2020, 1:33am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/12 "2020-08-09T01:33:47Z")

</div>

@Henrique_Becker@rdeits: I had a sneaky suspicion that a macro is the way to handle this case, but I didn’t want today to be the day I wrote the first one.

---

<div class="post-metadata">

### Author: ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)
#### Post date: [August 9, 2020, 1:44am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/13 "2020-08-09T01:44:12Z")

</div>

Your example works, but I’m getting:

```julia
julia> y = zeros(Int64, 4)
4-element Array{Int64,1}:
 0
 0
 0
 0

julia> @fill y [3, 1, 4, 1]
ERROR: AssertionError: firstindex($(Expr(:escape, [1.0, 2.0, 3.0, 4.0, 5.0]))) == 1 && length($(Expr(:escape, [1.0, 2.0, 3.0, 4.0, 5.0]))) == 4
Stacktrace:
 [1] top-level scope at /home/paul/st/julia/test.jl:728
 [2] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1088

```

There was a tiny error in your macro, here is corrected version:

```julia
macro fill(lhs, rhs)
  @capture rhs [elements__]
  quote
    begin
      @assert firstindex($(esc(lhs))) == 1 && length($(esc(lhs))) == $(length(elements))
      $([:($(esc(lhs))[$i] = $(esc(element))) for (i, element) in enumerate(elements)]...)
      $(esc(lhs))
    end
  end
end

```

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [August 9, 2020, 2:04am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/14 "2020-08-09T02:04:34Z")

</div>

Ahh, it escaped the `x` that did not exist inside the macro and just happened to work because it was the right variable name, not the `lhs`/`rhs` arguments themselves.

This kind of _works but then suddenly very strange bug appears_ that makes me avoid writing macros when possible. Seem like my distributed and parallel processing teacher said: the problem with distributed programming is that it has all problems/bugs of non-distributed programming, plus the problems/bugs that only happen with distributed programming. The same applies to macros, 😅.

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [August 9, 2020, 2:35am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/15 "2020-08-09T02:35:54Z")

</div>

Thanks! I’ve edited my post too to avoid confusing future copy-and-paste-ers.

---

<div class="post-metadata">

### Author: ![greg\_plowman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/greg_plowman/32/8100_2.png) [@greg\_plowman](https://discourse.julialang.org/u/greg_plowman)
#### Post date: [August 9, 2020, 6:06am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/16 "2020-08-09T06:06:41Z")

</div>

On my machine, initializing from a tuple using `@inbounds` loop seems quick:

```julia
function bar(buf)
    v = (3, 1, 4, 1)
    for i in eachindex(v)
        @inbounds buf[i] = v[i]
    end
    nothing
end

```

Here’s the timings:

```julia
julia> @btime foo($buf)
  6.699 ns (0 allocations: 0 bytes)

julia> @btime baz($buf)
  11.010 ns (0 allocations: 0 bytes)

julia> @btime bar($buf)
  6.499 ns (0 allocations: 0 bytes)

```

> **Full code**
>
> ```julia
> using BenchmarkTools
> 
> buf = [0, 0, 0, 0]
> 
> function foo(buf)
> buf[1] = 3
> buf[2] = 1
> buf[3] = 4
> buf[4] = 1
> nothing
> end
> 
> function baz(buf)
> buf .= (3, 1, 4, 1)
> nothing
> end
> 
> function bar(buf)
> v = (3, 1, 4, 1)
> for i in eachindex(v)
> @inbounds buf[i] = v[i]
> end
> nothing
> end
> 
> @btime foo($buf)
> @btime baz($buf)
> @btime bar($buf)
> 
> ```

---

<div class="post-metadata">

### Author: ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)
#### Post date: [August 9, 2020, 7:03am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/17 "2020-08-09T07:03:54Z")

</div>

Is `buf` this small in the actual use case, or is this just a simplified example?

If the actual `buf` is large, then storing the initialization data as code will flush the code cache of the CPU, making subsequent function calls slower.

In that case it might be better to go with something like

```julia
const ibuf = [3,1,4,1]
function bat(buf)
    buf .= ibuf
    nothing
end

```

---

<div class="post-metadata">

### Author: ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)
#### Post date: [August 9, 2020, 7:07am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/18 "2020-08-09T07:07:46Z")

</div>

`buf` is small and has to be initialized at the beginning of a loop starting  
an inner hot loop.

---

<div class="post-metadata">

### Author: ![pauljurczak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pauljurczak/32/921_2.png) [@pauljurczak](https://discourse.julialang.org/u/pauljurczak)
#### Post date: [August 9, 2020, 7:32am UTC](https://discourse.julialang.org/t/initializing-an-array-with-literals-without-allocating-a-temporary/44590/19 "2020-08-09T07:32:48Z")

</div>

> [@greg\_plowman](#):
>
> On my machine, initializing from a tuple using `@inbounds` loop seems quick

`bar` is distinctly the fastest on my 2 systems (execute file):

```julia
  2.184 ns (0 allocations: 0 bytes)
  5.166 ns (0 allocations: 0 bytes)
  1.642 ns (0 allocations: 0 bytes)

```

The timing is very unstable on my fastest PC when I measure functions one by one in REPL (fixed CPU frequency, turbo off), but the ranking is the same. I’m surprised `bar` is faster than `foo`. I even tried:

```julia
function foo(buf)
  @inbounds buf[1] = 3
  @inbounds buf[2] = 1
  @inbounds buf[3] = 4
  @inbounds buf[4] = 1
  nothing
end

```

and I was going to write it didn’t help, but after executing as a file with above `foo`, I’ve got:

```julia
  1.643 ns (0 allocations: 0 bytes)
  5.166 ns (0 allocations: 0 bytes)
  1.642 ns (0 allocations: 0 bytes)

```

so `@inbounds` macro helps in both cases.
