# \[ANN\] FixedSizeArrays.jl: What Array probably should have been

**URL:** <https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724>\
**Category:** Package Announcements\
**Tags:** announcement, arrays\
**Created:** [June 7, 2025, 4:45pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724 "2025-06-07T16:45:43Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [June 7, 2025, 4:45pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/1 "2025-06-07T16:45:43Z")

</div>

This has been one year in the making, but the first release of [`FixedSizeArrays.jl`](https://github.com/JuliaArrays/FixedSizeArrays.jl) is finally out and you can install it in your environment with

```julia
import Pkg
Pkg.add("FixedSizeArrays")

```

This package can be installed in Julia v1.10 and following releases, but the improvements mentioned in the sections below are generally available only in v1.11+ thanks to the use of the new `Memory` type.

@nsajko and @oscar_smith greatly contributed to FixedSizeArrays.jl.

### Motivation

The `Base.Array` type is very convenient and flexible, but in many applications it’s _too_ flexible: it’s a [dynamic array type](https://en.wikipedia.org/wiki/Dynamic_array), which allows you to add or remove elements from both ends. However there are many situations (most notably linear algebra applications) where this flexibily is unnecessary and actually comes with a performance cost: it prevents some compiler optimisations, since the size of the array _could_ change, even if it never does in practice. The package `FixedSizeArrays.jl` provides a mutable array implementation, [`FixedSizeArray`](https://juliaarrays.github.io/FixedSizeArrays.jl/stable/reference/#FixedSizeArrays.FixedSizeArray), with the same backend as `Base.Array` (this is an implementation detail!), but whose size is fixed after construction. This allows the compiler to better reason about optimisations, since the size of an array is known with certainty after construction.

As a taster of the performance of `FixedSizeArrays`, allocating and filling a `FixedSizeVector` is (slightly) faster and uses less memory (32 bytes) than an equally sized `Base.Vector`:

```julia-repl
julia> using BenchmarkTools, FixedSizeArrays

julia> for n in (0, 2^0, 2^5, 2^10, 2^15, 2^20, 2^25, 2^30)
           @info "n = $(n)"
           @btime fill!(Vector{Float32}(undef, $(n)), 0.0)
           @btime fill!(FixedSizeVectorDefault{Float32}(undef, $(n)), 0.0)
       end
[ Info: n = 0
  5.028 ns (1 allocation: 32 bytes)
  2.884 ns (0 allocations: 0 bytes)
[ Info: n = 1
  8.280 ns (2 allocations: 64 bytes)
  6.991 ns (1 allocation: 32 bytes)
[ Info: n = 32
  9.534 ns (2 allocations: 192 bytes)
  7.569 ns (1 allocation: 160 bytes)
[ Info: n = 1024
  91.336 ns (3 allocations: 4.07 KiB)
  88.852 ns (2 allocations: 4.04 KiB)
[ Info: n = 32768
  1.578 μs (3 allocations: 128.07 KiB)
  1.641 μs (2 allocations: 128.04 KiB)
[ Info: n = 1048576
  55.965 μs (3 allocations: 4.00 MiB)
  35.493 μs (2 allocations: 4.00 MiB)
[ Info: n = 33554432
  42.459 ms (3 allocations: 128.00 MiB)
  42.026 ms (2 allocations: 128.00 MiB)
[ Info: n = 1073741824
  1.352 s (3 allocations: 4.00 GiB)
  1.340 s (2 allocations: 4.00 GiB)

```

Furthermore, to facilitate escape analysis, when possible we throw a [custom error exception](https://juliaarrays.github.io/FixedSizeArrays.jl/dev/usage/#BoundsErrorLight-exception) when accessing out-of-bounds indices: this exception does not capture the entire array, thus enabling further optimisations, such as entirely removing memory allocations for small arrays because the error path could be elided (note: this happens only in Julia v1.12+):

```julia-repl
julia> using BenchmarkTools, FixedSizeArrays, Random

julia> function g(T)
           v = T(undef, 250)
           rand!(v)
           return foldl(+, v)
       end
g (generic function with 1 method)

julia> @btime g(Vector{Float64}) setup=(Random.seed!(1))
  223.163 ns (2 allocations: 2.02 KiB)
131.05489829603343

julia> @btime g(FixedSizeVectorDefault{Float64}) setup=(Random.seed!(1))
  221.137 ns (0 allocations: 0 bytes)
131.05489829603343

```

### Comparison with other packages

See the documentation for [comparison with other fixed-size arrays in the ecosystem](https://juliaarrays.github.io/FixedSizeArrays.jl/dev/#Comparison-with-other-array-types), but in a gist this does not replace `StaticArray` if what you want is an immutable stack-allocated array with the size in the type domain which you can dispatch on. `FixedSizeArray` really looks a lot more like `Base.Array`, but with fixed size.

### JuliaCon talk

If you’re going to attend JuliaCon 2025, either in-person or remotely, make sure to come to our talk [FixedSizeArrays.jl: What Array probably should have been](https://pretalx.com/juliacon-2025/talk/J3J7U8/).

---

<div class="post-metadata">

**Author:** ![drandran12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/drandran12/32/220647_2.png) [@drandran12](https://discourse.julialang.org/u/drandran12)\
**Post date:** [June 7, 2025, 4:50pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/2 "2025-06-07T16:50:49Z")

</div>

Congrats! 🎉 Will need to benchmark this with StaticArrays.MVector and Smallcollections.MutableSmallVector soon.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [June 7, 2025, 4:56pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/3 "2025-06-07T16:56:10Z")

</div>

I’m not familiar with `Smallcollections.MutableSmallVector`, but [a comparison with `StaticArrays.MArray` is mentioned in the docs](https://juliaarrays.github.io/FixedSizeArrays.jl/dev/#MArray-from-StaticArrays.jl): I don’t know about performance, but the use case of `FixedSizeArray` vs `StaticArrays.MArray` is slightly different. `FixedSizeArray` really wants to be a “better” `Base.Array` for numerical applications, rather than trying to optimise small arrays (`FixedSizeArray` is based on `Memory` rather than `Tuple`, so it should perform equally well at all sizes) or dispatch on array’s size (`FixedSizeArray` doesn’t allow that), which is what StaticArrays.jl does best.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 7, 2025, 6:35pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/4 "2025-06-07T18:35:39Z")

</div>

> [@giordano](#):
>
> The `Base.Array` type is very convenient and flexible, but in many applications it’s _too_ flexible: it’s a [dynamic array type](https://en.wikipedia.org/wiki/Dynamic_array), which allows you to add or remove elements from both ends. However there are many situations (most notably linear algebra applications) where this flexibily is unnecessary and actually comes with a performance cost: it prevents some compiler optimisations, since the size of the array _could_ change, even if it never does in practice.

Possibly clarified in your upcoming talk or somewhere in the devdocs, but do you mean `Vector` specifically? I had assumed that the “fixed-size” `Memory` would’ve at least allowed those fixed size optimizations for `N>=2` `Array`s. If not, how does `FixedSizeArray`’s inform the compiler that you really won’t reallocate the `Memory`? It lacks size information in the type parameters that `StaticArrays` have, so that can’t be it.

Also a couple more favorable points of comparison between `FixedSizeArray` and `MArray`:

1. The default `Memory` can leverage the `isbits`-`Union` optimization; `NTuple` and anything based on it can’t. To elaborate, a concrete `Memory` with an element type of a small `Union` of (up to 256, I think) `isbits` types can store each element in contiguous blocks of the largest type’s size like a C union, followed directly by contiguous bytes specifying the type of each element (on the same single `Memory`, unlike a struct of arrays). Concrete tuples are strictly structures of concrete types, so `NTuple{n, Union{T, Nothing}}` is strictly an abstract type and thus cannot use the `isbits`-`Union` optimization, both significantly hurting the performance and data locality of `StaticArray`s despite decent type inference of indexing.
2. `MArray` only supports `setindex!` for `isbitstype` elements. The underlying `unsafe_store!` code wouldn’t work on an abstract `NTuple` field or dense vectors with abstract element types even with the `isbits`-`Union` storage optimization. `FixedSizeArray` isn’t hacking `Tuple`s into a vector type, so it just forwards the indexing to `mem`.

`FixedSizeArray` doesn’t stand in for `SArray` for now because `Memory` can’t be reliably stored inlined due to its runtime size and mutability, but that’s a different conversation for a public immutable vector backend or a tuple variant that acts like an anonymous version of structs.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [June 7, 2025, 6:43pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/5 "2025-06-07T18:43:55Z")

</div>

> [@Benny](#):
>
> If not, how does `FixedSizeArray`’s inform the compiler that you really won’t reallocate the `Memory`?

The size is a field of an immutable struct:

> <https://github.com/JuliaArrays/FixedSizeArrays.jl/blob/598eb316def7d5411114eee3c3d7fb09f83f279d/src/FixedSizeArray.jl#L21-L27>

This is the same layout as `Base.Array`, but that’s a mutable struct:

> <https://github.com/JuliaLang/julia/blob/51214a752404a639e68a632a64a7b9e75ce1a4fa/base/boot.jl#L72-L75>

If a function depends _only_ on the size/length of a `FixedSizeArray`, that can be entirely constant-propagated, see for example [FixedSizeArrays.jl Showcase · JuliaArrays/FixedSizeArrays.jl · Discussion #62 · GitHub](https://github.com/JuliaArrays/FixedSizeArrays.jl/discussions/62#discussion-7083500).

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [June 7, 2025, 6:50pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/6 "2025-06-07T18:50:11Z")

</div>

> [@Benny](#):
>
> I had assumed that the “fixed-size” `Memory` would’ve at least allowed those fixed size optimizations for `N>=2` `Array`s.

I’m not sure how that could be implemented, though, given that `Vector === Array{T, 1} where {T}`. That is, `Vector` and `Matrix` differ just by that one type parameter, so one can’t simplify `Matrix` without affecting `Vector`, I think.

See also this PR:

- [Allow taking Matrix slices without an extra allocation by vtjnash · Pull Request #56236 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/56236)

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [June 8, 2025, 11:18pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/7 "2025-06-08T23:18:53Z")

</div>

> [@drandran12](#):
>
> Will need to benchmark this with StaticArrays.MVector and Smallcollections.MutableSmallVector soon.

Ok, I took some time to benchmark `StaticArrays.MVector` vs `FixedSizeVector`, using the benchmarks I shared in the first post:

```julia-repl
julia> using BenchmarkTools, FixedSizeArrays, StaticArrays
[Info: Precompiling StaticArraysStatisticsExt [06c1163f-768c-55d8-b451-fddc7c07223a]

julia> for n in (0, 2^0, 2^5, 2^10, 2^15)
           @info "n = $(n)"
           @eval @btime fill!(MVector{$(n),Float32}(undef), 0.0)
           @btime fill!(FixedSizeVectorDefault{Float32}(undef, $(n)), 0.0)
       end
[ Info: n = 0
  3.756 ns (1 allocation: 8 bytes)
  2.854 ns (0 allocations: 0 bytes)
[ Info: n = 1
  3.435 ns (1 allocation: 16 bytes)
  6.389 ns (1 allocation: 32 bytes)
[ Info: n = 32
  4.406 ns (1 allocation: 144 bytes)
  7.078 ns (1 allocation: 160 bytes)
[ Info: n = 1024
  82.811 ns (1 allocation: 4.06 KiB)
  88.521 ns (2 allocations: 4.04 KiB)
[ Info: n = 32768
  2.951 μs (1 allocation: 128.06 KiB)
  2.004 μs (2 allocations: 128.04 KiB)

```

I stopped at 2^15 elements because allocating a 1-milion-element `MVector` takes pretty much forever (it’s taking more than 30 minutes and using 20 GB of swap on my laptop). This is not particularly surprising: as already mentioned above, `StaticArrays` is really about small arrays, for longer ones it becomes unusable, it’s not good for a general-purpose container, which is what `FixedSizeArrays` wants to be.

For the other benchmark:

```julia-repl
julia> function g(T)
           v = T(undef, 250)
           rand!(v)
           return foldl(+, v)
       end
g (generic function with 1 method)

julia> function static_g(T)
           v = T(undef)
           rand!(v)
           return foldl(+, v)
       end
static_g (generic function with 1 method)

julia> @btime g(FixedSizeVectorDefault{Float64}) setup=(Random.seed!(1))
  226.910 ns (0 allocations: 0 bytes)
131.05489829603343

julia> @btime static_g(MVector{250, Float64}) setup=(Random.seed!(1))
  368.180 ns (1 allocation: 1.98 KiB)
135.38837641231748

```

Besides the fact the memory allocation for `MVector` is not removed, I believe the sum is slower because it’s fully unrolled and can’t be vectorised, which is what `FixedSizeVector` can do because it’s a “normal” vector which doesn’t try to outsmart the compiler.

Let’s look at `SmallCollections.MutableSmallVector` now:

```julia-repl
julia> using BenchmarkTools, FixedSizeArrays, Random, SmallCollections

julia> for n in (0, 2^0, 2^5, 2^10, 2^15)
           @info "n = $(n)"
           @eval @btime fill!(MutableSmallVector{$(n),Float32}(), 0.0)
           @btime fill!(FixedSizeVectorDefault{Float32}(undef, $(n)), 0.0)
       end
[ Info: n = 0
  3.445 ns (1 allocation: 16 bytes)
  2.864 ns (0 allocations: 0 bytes)
[ Info: n = 1
  3.906 ns (1 allocation: 16 bytes)
  6.550 ns (1 allocation: 32 bytes)
[ Info: n = 32
  4.988 ns (1 allocation: 144 bytes)
  7.499 ns (1 allocation: 160 bytes)
[ Info: n = 1024
  90.897 ns (1 allocation: 4.12 KiB)
  93.841 ns (2 allocations: 4.04 KiB)
[ Info: n = 32768
  1.962 μs (1 allocation: 128.12 KiB)
  2.066 μs (2 allocations: 128.04 KiB)

julia> function g(T)
           v = T(undef, 250)
           rand!(v)
           return foldl(+, v)
       end
g (generic function with 1 method)

julia> @btime g(FixedSizeVectorDefault{Float64}) setup=(Random.seed!(1))
  226.787 ns (0 allocations: 0 bytes)
131.05489829603343

julia> @btime g(MutableSmallVector{250, Float64}) setup=(Random.seed!(1))
  383.483 ns (1 allocation: 1.98 KiB)
135.38837641231748

```

I had again to stop at 2^15 elements because 2^20 is apparently not “small” anymore (I got an error trying to generate that array), and the memory allocation in the `g` function is again not removed.

I’m sure there will be applications where `MVector` and `MutableSmallVector` would perform better, but with these examples I wanted to stress the fact that FixedSizeArrays.jl provides a simple general-purpose fixed-size array which plays nicely with the compiler, instead of trying to trick it.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [June 9, 2025, 12:26am UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/8 "2025-06-09T00:26:39Z")

</div>

Very helpful pkg. Any thoughts on how to provide a FixedSizeFixedArray, a fixed size array with immutable elements, and gain performance advantage (saving any checks or tests that mutable elements need to provide)?

---

<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:** [June 9, 2025, 1:37am UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/9 "2025-06-09T01:37:41Z")

</div>

> [@giordano](#):
>
> allocating a 1-milion-element `MVector` takes pretty much forever

With `MutableFixedVector` (the analog of `MVector` in SmallCollections.jl) it’s quick. Without a warm-up I get:

```julia
julia> @time fill!(MutableFixedVector{1048576,Float32}(undef), 0.0)
  0.002612 seconds (1 allocation: 4.000 MiB)

```

(I’m surprised – when I wrote the package, large vectors were not on my mind.)

> [@giordano](#):
>
> ```julia
> @eval @btime fill!(MutableSmallVector{$(n),Float32}(), 0.0)
> 
> ```

This creates an empty vector. You want to have

```julia
@eval @btime fill!(MutableSmallVector{$n,Float32}(undef, $n), 0.0)

```

> [@giordano](#):
>
> 2^20 is apparently not “small” anymore (I got an error trying to generate that array)

This is because the length is stored as an `Int16`.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [June 9, 2025, 9:55am UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/10 "2025-06-09T09:55:27Z")

</div>

I’m not quite sure how to do that in a way that helpfully informs the compiler that the data is immutable. The struct `FixedSizeArray` is already immutable, but the `Memory` field itself is mutable (you can change the data it points to). I don’t think not defining the `getindex` methods is enough.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [June 9, 2025, 10:11am UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/11 "2025-06-09T10:11:54Z")

</div>

> [@JeffreySarnoff](#):
>
> immutable elements

I think @oscar_smith wrote somewhere that adding a `GenericMemory` variant that’s just like `Memory` but immutable should not be too difficult. Once something like that is added to Julia it should be easy to support in FixedSizeArrays.jl.

---

<div class="post-metadata">

**Author:** ![Salmon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/salmon/32/22968_2.png) [@Salmon](https://discourse.julialang.org/u/Salmon)\
**Post date:** [June 9, 2025, 12:31pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/12 "2025-06-09T12:31:49Z")

</div>

Thanks for this, its fantastic to finally have a package for fixed size arrays!

I am curious regarding this point in particular:

> [@giordano](#):
>
> Furthermore, to facilitate escape analysis, when possible we throw a [custom error exception](https://juliaarrays.github.io/FixedSizeArrays.jl/dev/usage/#BoundsErrorLight-exception) when accessing out-of-bounds indices: this exception does not capture the entire array, thus enabling further optimisations, such as entirely removing memory allocations for small arrays because the error path could be elided (note: this happens only in Julia v1.12+):

Does this mean there is finally a convenient solution to avoiding allocations of temporary arrays?  
Specifically: would you recommend using FixedSizeArrays.jl to make temporary allocations as opposed to the default of passing buffer arrays?

I suppose it will always be fastest to use preallocated buffers, but in some cases it can be a pain to do… If this gets rid of the majority of the cose (which is garbage collection, I presume) then this would be a nice alternative.

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [June 9, 2025, 12:34pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/13 "2025-06-09T12:34:02Z")

</div>

> [@giordano](#):
>
> most notably linear algebra applications

Is there a performance gain in linear algebra ops like matrix multiplies, BLAS, etc. ? Or this is not what you meant here?

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [June 9, 2025, 1:08pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/14 "2025-06-09T13:08:17Z")

</div>

_Only_ calling BLAS functions shouldn’t have any performance improvement, and why it should? The performance just depends on the BLAS functions you’re calling, not the container. But having a fixed-size array in your application, which does _other_ operations besides BLAS calls, can give the compiler more optimisation opportunities than with `Base.Array`.

For example, the code generated for this function

```julia
function g(T)
    N = 1024
    A = T(undef, N)
    B = T(undef, N)
    rand!(A)
    rand!(B)

    return A .+ B
end

```

doesn’t have an error path for, say, `T = FixedSizeVectorDefault{Float64}`, but it does for `T = Vector{Float64}`. Being able to let the compiler elide error paths and small memory allocations can have a non-zero impact on your overall application, even if BLAS functions alone aren’t affected. The reference to “linear algebra applications” in my message was because in numerical code you most often only need fixed-size arrays, and dynamic arrays are an overkill which only prevent optimisations.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [June 9, 2025, 1:13pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/15 "2025-06-09T13:13:06Z")

</div>

> [@Salmon](#):
>
> Does this mean there is finally a convenient solution to avoiding allocations of temporary arrays?  
> Specifically: would you recommend using [FixedSizeArrays.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/FixedSizeArrays) to make temporary allocations as opposed to the default of passing buffer arrays?

I’d say try it out! But if you need memory buffers for in-place operations I’m not sure a fixed-size array is a replacement for that.

As mentioned already in the message above, the reason why a fixed-size array is useful is because it can enable optimisations (e.g. eliding memory allocations and error paths) that are harder to achieve with a dynamic array.

---

<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:** [June 9, 2025, 1:30pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/16 "2025-06-09T13:30:53Z")

</div>

> Does this mean there is finally a convenient solution to avoiding allocations of temporary arrays?

This (currently) depends heavily on how temporary the temporaries are. Julia’s allocation escape analysis isn’t inter-procedural, so currently, this optimization won’t always remove allocations (but it sometimes will).

---

<div class="post-metadata">

**Author:** ![araujoms](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/araujoms/32/217734_2.png) [@araujoms](https://discourse.julialang.org/u/araujoms)\
**Post date:** [June 9, 2025, 1:56pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/17 "2025-06-09T13:56:10Z")

</div>

Nice package! If I understood correctly, I should expect better performance for creating arrays and mutating their elements, but not for multiplying two matrices or summing their elements?

---

<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:** [June 9, 2025, 2:05pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/18 "2025-06-09T14:05:48Z")

</div>

> [@giordano](#):
>
> ```julia
> function g(T)
> N = 1024
> A = T(undef, N)
> B = T(undef, N)
> rand!(A)
> rand!(B)
> 
> return A .+ B
> end
> 
> ```

I thought that in order to get specialization you needed to define

```julia
function g(::Type{T}) where {T}

```

Otherwise, the compiler would treat the input as just a `DataType`. Is that not the case? Or is that for dispatch, not specialization?

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [June 9, 2025, 4:13pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/19 "2025-06-09T16:13:29Z")

</div>

This seems off-topic (can a mod split these two messages to another thread maybe?), but anyway:

> [@DNF](#):
>
> I thought that in order to get specialization you needed to define
> 
> `function g(::Type{T}) where {T}`

Sure, but AFAIK the lack of specialization only means there will be no specialization for the LLVM IR. That is, the Julia compiler will still run inference with more precisely specialized argument types, if it feels it. In particular, constant propagation is not disabled (pretty sure). Often it makes sense to avoid specialization, for example in the implementation of `typejoin`:

> <https://github.com/JuliaLang/julia/blob/d6b3669621ceb18aea693d8544b2c38870d289ad/base/promotion.jl#L21-L24>

I think `typejoin` is implemented like that because it’s expected to constant fold anyway, so the machine code being too specialized is just wasted compiler effort/unnecessary latency.

There are other differences, too:

- Don’t really understand this comment by vtjnash, but it’s certainly relevant: [replace constructorof with something not UB by vtjnash · Pull Request #99 · JuliaObjects/ConstructionBase.jl · GitHub](https://github.com/JuliaObjects/ConstructionBase.jl/pull/99#discussion_r1996796031)

- In `t::Type{T}`, `t == T` is required, but not necessarily `t === T`

Anyway, none of this matters for the quoted message, so of course @giordano went with the simpler option.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [June 9, 2025, 4:30pm UTC](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724/20 "2025-06-09T16:30:49Z")

</div>

> [@araujoms](#):
>
> expect better performance for creating arrays and mutating their elements, but not for multiplying two matrices or summing their elements

Yeah, as long as the matrix multiplication is in-place, the exact same code paths (BLAS, usually) should get used for both `Array` and `FixedSizeArray`.

[Next page](https://discourse.julialang.org/t/ann-fixedsizearrays-jl-what-array-probably-should-have-been/129724.md?page=2)
