# Constructing SVector with a loop

**URL:** <https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372>\
**Category:** General Usage\
**Tags:** question\
**Created:** [September 23, 2018, 11:00am UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372 "2018-09-23T11:00:16Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 23, 2018, 11:00am UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/1 "2018-09-23T11:00:16Z")

</div>

Suppose I want to construct an `SVector` with known length `S` and type `T`, but a loop (with a known number of iterations) would be the most comfortable way of doing it. What is the standard idiom for this in 1.0?

My problem is a bit complex, but for an example, consider

```julia
using StaticArrays

function SFib1(::Val{S}) where S
    values = Vector{Int}(undef, S)
    @inbounds for i in 1:S
        values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
    end
    SVector{S}(values)
end

```

Is it possible to allocate the SVector, then manipulate it with `reinterpret` or similar before returning it?

---

<div class="post-metadata">

**Author:** ![Gnimuc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gnimuc/32/2194_2.png) [@Gnimuc](https://discourse.julialang.org/u/Gnimuc)\
**Post date:** [September 23, 2018, 11:30am UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/2 "2018-09-23T11:30:52Z")

</div>

It looks like you’re looking for `MVector`?

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 23, 2018, 11:39am UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/3 "2018-09-23T11:39:32Z")

</div>

I am not sure. Should I construct an `MVector`, then convert to an `SVector`? It appears to be slower than using a `Vector`, eg

```julia
function SFibM(::Val{S}) where S
    values = MVector{S, Int}(undef)
    @inbounds for i in 1:S
        values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
    end
    SVector{S}(values)
end

julia> @btime SFib1(Val(10));
  40.800 ns (1 allocation: 160 bytes)

julia> @btime SFibM(Val(10));
  65.488 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![Gnimuc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gnimuc/32/2194_2.png) [@Gnimuc](https://discourse.julialang.org/u/Gnimuc)\
**Post date:** [September 23, 2018, 12:01pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/4 "2018-09-23T12:01:49Z")

</div>

It seems the crossover point is 7.

```julia
julia> @btime SFibM(Val(7))
  31.316 ns (0 allocations: 0 bytes)

julia> @btime SFib1(Val(7))
  48.441 ns (1 allocation: 144 bytes)

```

without the additional conversion, I get:

```julia
julia> @btime SFibM2(Val(7)) 
  10.438 ns (1 allocation: 64 bytes)

```

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [September 23, 2018, 3:01pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/5 "2018-09-23T15:01:16Z")

</div>

Probably not a valid solution, but fun anyway:

```julia
function SFibNtuple(::Val{S}) where S
    val_i_minus_2 = Ref(1)
    val_i_minus_1 = Ref(1)
    tup = ntuple(S) do i
        if i == 1 || i == 2
            1
        else
            val = val_i_minus_2[] + val_i_minus_1[]
            val_i_minus_2[] = val_i_minus_1[]
            val_i_minus_1[] = val
        end
    end
    SVector(tup)
end

```

This infers up to `Val(10)`.

```julia
using BenchmarkTools
@btime SFibNtuple(Val(10));

```

prints `1.702 ns (0 allocations: 0 bytes)`.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [September 23, 2018, 3:06pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/6 "2018-09-23T15:06:48Z")

</div>

You could use a generated function to unroll the loop.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [September 23, 2018, 3:32pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/7 "2018-09-23T15:32:13Z")

</div>

[`Setfield.@set`](https://jw3126.github.io/Setfield.jl/stable/#Setfield.@set-Tuple%7BAny%7D) is a great tool for manipulating `StaticArrays` efficiently

```julia
using Setfield
using StaticArrays

function SFib1(::Val{S}) where S
    values = zeros(SVector{S, Int})
    @inbounds for i in 1:S
        values = @set values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
    end
    values
end

```

```llvm
julia> @code_llvm SFib1(Val(4))

; Function SFib1
; Location: REPL[132]:2
define void @julia_SFib1_38655({ [4 x i64] }* noalias nocapture sret) {
L45.3:
; Location: REPL[132]:4
; Function macro expansion; {
; Location: /home/takafumi/.julia/packages/Setfield/X9IQb/src/sugar.jl:77
  %1 = bitcast { [4 x i64] }* %0 to <4 x i64>*
  store <4 x i64> <i64 1, i64 1, i64 2, i64 3>, <4 x i64>* %1, align 8
  ret void
;}
}

```

---

<div class="post-metadata">

**Author:** ![mschauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mschauer/32/13946_2.png) [@mschauer](https://discourse.julialang.org/u/mschauer)\
**Post date:** [September 23, 2018, 4:36pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/8 "2018-09-23T16:36:05Z")

</div>

Neither a loop nor necessarily a good idea, but here is this:

```julia
function raise_(N) 
    if N == 0 
        :(args...)
    elseif N == 1   
        :(f(args...)) 
    else
        expr = raise_(N-1)
        return :(f($expr))
    end
end

@generated function raise(f, ::Val{N}, args...) where N
    raise_(N)
end

using StaticArrays, BenchmarkTools
fib(_) = (1, 1)
fib(t::NTuple) = (t..., t[end] + t[end-1])
fibs(::Val{N}) where N = SVector(raise(fib, Val(N-1), nothing))

```

```julia
; Function fibs
; Location: /Users/schauermr/.julia/v0.6/Bridge/project/ntuple.jl:20
define void @julia_fibs_38351({ [4 x i64] }* noalias nocapture sret) {
top:
  %1 = bitcast { [4 x i64] }* %0 to <4 x i64>*
  store <4 x i64> <i64 1, i64 1, i64 2, i64 3>, <4 x i64>* %1, align 8
  ret void
}

```

---

<div class="post-metadata">

**Author:** ![user664303](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/user664303/32/37843_2.png) [@user664303](https://discourse.julialang.org/u/user664303)\
**Post date:** [May 19, 2025, 4:20pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/9 "2025-05-19T16:20:08Z")

</div>

Is there a better solution to this, now?

It seems that SVectors (and SMatrices and SArrays), while being fast, stack-based, fixed-size containers (and indeed my go-to container for short, fixed sized arrays), are complicated to construct if the computation is non trivial. Unless I’m missing something.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 19, 2025, 4:34pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/10 "2025-05-19T16:34:02Z")

</div>

I would use Accessors.jl for it:

```julia
julia> using StaticArrays, Accessors

julia> function SFib2(::Val{S}) where S
           values = SVector(ntuple(_ -> 0, Val(S)))
           @inbounds for i in 1:S
               @reset values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
           end
           values
       end

```

Accessors.jl is the successor to Setfield.jl (the already accepted answer).

Otherwise, I would use an MVector and convert to SVector at the end.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 19, 2025, 4:41pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/11 "2025-05-19T16:41:30Z")

</div>

For Julia 1.11+, you could try a `Memory`:

```julia
julia> function memfib(::Val{S}) where S
    values = Memory{Int}(undef, S)
    @inbounds for i in 1:S
        values[i] = ((i == 1) | (i == 2)) ? 1 : values[i-1] + values[i-2]
    end
    values
end

julia> @btime memfib(Val(7))
  4.010 ns (1 allocation: 80 bytes)
7-element Memory{Int64}:
  1
  1
  2
  3
  5
  8
 13

```

This stays pretty fast too.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [May 19, 2025, 4:42pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/12 "2025-05-19T16:42:25Z")

</div>

In v1.13 (but not v1.11, v1.12 I haven’t checked) I have found that if I construct or convert to a `MArray` initially but convert to a `SArray` by the end of the function (and don’t allow the `MArray` to escape) then it will run without heap allocations and quite quickly. This has let me apply functions like `LinearAlgebra.lowrankupdate!` (which requires mutability) to a `SMatrix` heap-free and without needing to write a non-mutating version of the function.

So the `MVector` approach may not be fantastic now but might be soon™.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 19, 2025, 4:45pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/13 "2025-05-19T16:45:24Z")

</div>

> [@Sukera](#):
>
> For Julia 1.11+, you could try a `Memory`:
> 
> ```julia
> 4.010 ns (1 allocation: 80 bytes)
> 
> ```
> 
> This stays pretty fast too.

The Accessors.jl solution doesn’t even have a runtime though, it’s all at compile time here which is nice. Unfortunately `Memory` is still too opaque to the compiler to be eliminated here.

---

<div class="post-metadata">

**Author:** ![matthias314](https://avatars.discourse-cdn.com/v4/letter/m/a88e4f/32.png) [@matthias314](https://discourse.julialang.org/u/matthias314)\
**Post date:** [May 19, 2025, 7:08pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/14 "2025-05-19T19:08:41Z")

</div>

> [@Mason](#):
>
> it’s all at compile time

If that’s the goal, couldn’t it simply be done with `@assume_effects`?

```julia
Base.@assume_effects :total function SFibA(::Val{S}) where S
    values = MVector{S, Int}(undef)
    @inbounds for i in 1:S
        values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
    end
    SVector{S}(values)
end

```

```julia
; @ In[13]:32 within `SFibA`
; ┌ @ /usr/local/julia-depot/packages/StaticArrays/LSPcF/src/convert.jl:180 within `StaticArray`
; │┌ @ /usr/local/julia-depot/packages/StaticArraysCore/7xxEJ/src/StaticArraysCore.jl:115 within `SArray`
    store <4 x i64> <i64 1, i64 1, i64 2, i64 3>, ptr %sret_return, align 8
    ret void
; └└

```

(One can probably reduce `:total` to something more modest.)

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [May 19, 2025, 7:14pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/15 "2025-05-19T19:14:27Z")

</div>

On 1.12, no effects are needed:

```julia
julia> function SFibA(::Val{S}) where S
           values = MVector{S, Int}(undef)
           @inbounds for i in 1:S
               values[i] = (i == 1 || i == 2) ? 1 : values[i-1] + values[i-2]
           end
           SVector{S}(values)
       end
SFibA (generic function with 1 method)

julia> @code_llvm debuginfo=:none SFibA(Val(4))
; Function Signature: SFibA(Base.Val{4})
define void @julia_SFibA_5700(ptr noalias nocapture noundef nonnull sret([1 x [4 x i64]]) align 8 dereferenceable(32) %sret_return) #0 {
L61.3:
  store <4 x i64> <i64 1, i64 1, i64 2, i64 3>, ptr %sret_return, align 8
  ret void
}

```

Looks like it works up to size 12:

```julia
julia> @code_llvm debuginfo=:none SFibA(Val(12))
; Function Signature: SFibA(Base.Val{12})
define void @julia_SFibA_5928(ptr noalias nocapture noundef nonnull sret([1 x [12 x i64]]) align 8 dereferenceable(96) %sret_return) #0 {
L61.11:
  store <4 x i64> <i64 1, i64 1, i64 2, i64 3>, ptr %sret_return, align 8
  %"new::SArray.sroa.0.sroa.5.0.sret_return.sroa_idx" = getelementptr inbounds i8, ptr %sret_return, i64 32
  store <4 x i64> <i64 5, i64 8, i64 13, i64 21>, ptr %"new::SArray.sroa.0.sroa.5.0.sret_return.sroa_idx", align 8
  %"new::SArray.sroa.0.sroa.9.0.sret_return.sroa_idx" = getelementptr inbounds i8, ptr %sret_return, i64 64
  store <4 x i64> <i64 34, i64 55, i64 89, i64 144>, ptr %"new::SArray.sroa.0.sroa.9.0.sret_return.sroa_idx", align 8
  ret void
}

```

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [May 19, 2025, 7:51pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/16 "2025-05-19T19:51:00Z")

</div>

> [@Mason](#):
>
> Unfortunately `Memory` is still too opaque to the compiler to be eliminated here.

Well, the `Memory` here will never be eliminated - it is returned after all, just like the `Vector` or `SVector` before it 🙂

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [May 19, 2025, 10:22pm UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/17 "2025-05-19T22:22:15Z")

</div>

Oh my bad, I didn’t read the code very carefully I guess, and just assumed you were still converting to an `SVector` since otherwise it wouldn’t really fit with the original question..

---

<div class="post-metadata">

**Author:** ![danielwe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielwe/32/35657_2.png) [@danielwe](https://discourse.julialang.org/u/danielwe)\
**Post date:** [May 20, 2025, 1:21am UTC](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/18 "2025-05-20T01:21:23Z")

</div>

Another compile-time version using only `ntuple`, no packages:

```julia-repl
julia> function fibntuple(::Val{S}) where S
           fib_curr::Int = 0
           fib_next::Int = 1
           return ntuple(Val(S)) do i
               @inline
               fib_curr, fib_next = fib_next, fib_curr + fib_next
               return fib_curr
           end
       end
fibntuple (generic function with 1 method)

julia> Sfib(::Val{S}) where {S} = SVector(fibntuple(Val(S)))
Sfib (generic function with 1 method)

julia> @btime Sfib(Val(32));
  0.584 ns (0 allocations: 0 bytes)

julia> @code_llvm debuginfo=:none Sfib(Val(32));
define void @julia_Sfib_1137([1 x [32 x i64]]* noalias nocapture noundef nonnull sret([1 x [32 x i64]]) align 8 dereferenceable(256) %0) #0 {
top:
  %1 = bitcast [1 x [32 x i64]]* %0 to i8*
  call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 8 dereferenceable(256) %1, i8* noundef nonnull align 8 dereferenceable(256) bitcast ([1 x [32 x i64]]* @_j_const1 to i8*), i64 256, i1 false)
  ret void
}

```

Note that, in contrast to [Constructing SVector with a loop - #15 by Oscar\_Smith](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/15), this doesn’t even have the SIMD instructions to populate the vector with hardcoded scalars. It’s just directly returning a stored constant. (In other words, there’s two levels of “moving the computation to compile time” here; one is computing all the values at compile time but assembling them into a vector at runtime, which I’ll call SIMD-style; another is doing nothing at all at runtime.) This works up to `S = 32`, beyond which `fibntuple` falls back SIMD-style and is no longer inlined into `Sfib`.

This behavior is quite particular, though. If you try to combine `fibntuple` and `Sfib` into a single function, and/or use `Ref`s instead of the typed (but boxed) locals, such as in [Constructing SVector with a loop - #5 by tkoolen](https://discourse.julialang.org/t/constructing-svector-with-a-loop/15372/5), you get SIMD-style LLVM again.
