# Unexpected behaviour when using Pluto with StaticArrays

**URL:** https://discourse.julialang.org/t/unexpected-behaviour-when-using-pluto-with-staticarrays/130690
**Category:** Pluto
**Tags:** question, pluto, staticarrays
**Created:** [July 14, 2025, 4:08am UTC](https://discourse.julialang.org/t/unexpected-behaviour-when-using-pluto-with-staticarrays/130690 "2025-07-14T04:08:33Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![azeredo-e](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/azeredo-e/32/208402_2.png) [@azeredo-e](https://discourse.julialang.org/u/azeredo-e)
#### Post date: [July 14, 2025, 4:08am UTC](https://discourse.julialang.org/t/unexpected-behaviour-when-using-pluto-with-staticarrays/130690/1 "2025-07-14T04:08:33Z")

</div>

Hello everyone.

I’ve found this weird behaviour when using StaticArrays within a begin … end block Pluto.

I have this cell

```julia
begin
     xᵢ = collect(range(0, 10, length=n)) |> SVector{n}
     yᵢ = @SVector [β₀ + β₁ * i + rand() for i in xᵢ]
end

```

where β₀ and β₁ are just normal floats, and `n` is an int. The problem is that, when I run the code like this it wont work! It returns me a `UndefVarError: xᵢ not defined in Main.var"workspace#3"`. If I run the variable declaration for xᵢ and yᵢ separetely, that is, in different cells, everything works fine. It is only when they are together.

Does anyone knows what might be going on?

My `versioninfo()` and `]status`. Pluto version=v0.20.8.

```julia
julia> versioninfo()
Julia Version 1.11.5
Commit 760b2e5b739 (2025-04-14 06:53 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin24.0.0)
  CPU: 10 × Apple M4
  WORD_SIZE: 64
  LLVM: libLLVM-16.0.6 (ORCJIT, apple-m1)
Threads: 4 default, 0 interactive, 2 GC (on 4 virtual cores)
Environment:
  JULIA_REVISE_WORKER_ONLY = 1

julia> import Pkg; Pkg.status()
Status `/private/var/folders/05/16l0_s8d0g3680ryypw6qw7r0000gn/T/jl_IBJiAk/Project.toml`
  [6e4b80f9] BenchmarkTools v1.6.0
  [31c24e10] Distributions v0.25.120
  [38e38edf] GLM v1.9.0
⌃ [91a5bcdd] Plots v1.40.13
  [90137ffa] StaticArrays v1.9.13
  [10745b16] Statistics v1.11.1
  [f3b207a7] StatsPlots v0.15.7
  [9d95f2ec] TypedTables v1.4.6
  [44cfe95a] Pkg v1.11.0
  [9a3f8284] Random v1.11.0
Info Packages marked with ⌃ have new versions available and may be upgradable.

```

---

<div class="post-metadata">

### Author: ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)
#### Post date: [July 14, 2025, 7:13am UTC](https://discourse.julialang.org/t/unexpected-behaviour-when-using-pluto-with-staticarrays/130690/2 "2025-07-14T07:13:16Z")

</div>

I don’t think this is a Pluto issue. Running this `begin ... end` block in a fresh REPL gives the same error:

```julia
using StaticArrays

begin
     xᵢ = collect(range(0, 10, length=10)) |> SVector{10}
     yᵢ = @SVector [i for i in xᵢ]
end

# ERROR: LoadError: UndefVarError: `xᵢ` not defined

```

Not sure if the details/nomenclature here are technically correct, but macros are expanded before actual code is run in the expression you are trying to evaluate. So the whole expression in the block is parsed first, then the macros get replaced by the expressions they generate, and only then the code will run.

The error happens in the second step when the `@SVector` macro is trying to generate the expression that takes the values of `xᵢ` and use them to create `yᵢ`. Since the code to define `xᵢ` has not been run yet (happens after macro expansion), this cannot work. When generating an `@SVector` from the comprehension above, it basically reads all the values directly from the vector in the expansion (so `xᵢ`) and pastes them into the new expression (see below). But `xᵢ` hasn’t been defined yet, so the values cannot be read at the time of macro expansion.

I wonder if technically the `SVector` macro could do something else and just use the variable name `xᵢ` when generating the expression for the new vector, but apparently this doesn’t work (?). It might be because e.g. the length of the vector would have to be inferred somehow, probably only possible with `length(xᵢ)` at which point you would loose type stability.

One solution would be to just use `SVector{n}` as in the line above, since you already know the length and don’t really need to fall back to the convenience constructor. This will allocate the array `[... for i in xᵢ]` first and then convert it, but that doesn’t sound like a performance bottleneck.

```julia
begin
    xᵢ = collect(range(0, 10, length=10)) |> SVector{10}
    yᵢ = SVector{10}([i for i in xᵢ])
end

```

> **\`@macroexpand\`**
>
> This is the `@macroexpand`ed `@SVector` expression (after `xᵢ` has been successfully defined). The values from `xᵢ` are pasted literally in the vector:
> 
> ```julia
> let
> var"#3#f"(i) = begin
> i
> end
> (SVector){10}((tuple)(var"#3#f"(0.0), var"#3#f"(1.1111111111111112), var"#3#f"(2.2222222222222223), var"#3#f"(3.3333333333333335), var"#3#f"(4.444444444444445), var"#3#f"(5.555555555555555), var"#3#f"(6.666666666666667), var"#3#f"(7.777777777777778), var"#3#f"(8.88888888888889), var"#3#f"(10.0)))
> end
> 
> ```
> 
> If the expression would return this expression
> 
> ```julia
> (SVector){10}((tuple)(var"#3#f"(xᵢ[1]), var"#3#f"(xᵢ[2]), var"#3#f"(xᵢ[3]), ... ))
> 
> ```
> 
> It might work, but at the moment I don’t understand the implications of doing that.

---

<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: [July 14, 2025, 7:36am UTC](https://discourse.julialang.org/t/unexpected-behaviour-when-using-pluto-with-staticarrays/130690/3 "2025-07-14T07:36:52Z")

</div>

> [@Sevi](#):
>
> Not sure if the details/nomenclature here are technically correct, but macros are expanded before actual code is run in the expression you are trying to evaluate. So the whole expression in the block is parsed first, then the macros get replaced by the expressions they generate, and only then the code will run.

This is also why we can’t put the import of a macro in the same expression as a macro call; the macro call happens before the expression, including the import, is evaluated.

```julia
julia> begin
       using BenchmarkTools
       @btime $1+$1
       end
ERROR: LoadError: UndefVarError: `@btime` not defined in `Main`

```

Note that more often than not, you _can_ use a global variable defined in the same block as a macro call:

```julia
julia> begin
       x = 1
       @time 10x
       end
  0.000008 seconds
10

```

because macros usually just transform expressions to be evaluated with the rest of the expression later. `@SVector` (and related `StaticArrays` macros) are unusual in that the macros evaluate the symbol in the global scope to get a value first. Although this makes the macros useless for variables in local scopes:

```julia
julia> let z=3;
       SVector{z}(i for i in 1:z)
       end
3-element SVector{3, Int64} with indices SOneTo(3):
 1
 2
 3

julia> let z=3;
       @SVector [i for i in 1:z]
       end
ERROR: LoadError: UndefVarError: `z` not defined in `Main`
...

```

it allows you to not provide a length parameter in the global scope (see there’s only one `z` in the macro call) and the macro will hardcode the elements into an `SVector{#=length=#}` call instead of allocating an intermediate array for the comprehension. Of course, the non-macro `SVector` supports generator expressions, so that’s another way to skip that allocation.
