# Why is \`Expr\` mutable?

**URL:** https://discourse.julialang.org/t/why-is-expr-mutable/129850
**Category:** Internals & Design
**Created:** [June 13, 2025, 7:25am UTC](https://discourse.julialang.org/t/why-is-expr-mutable/129850 "2025-06-13T07:25:40Z")
**Posts on this page:** 1
**Showing post:** 1

<div class="post-metadata">

### Author: ![PatrickHaecker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/patrickhaecker/32/222891_2.png) [@PatrickHaecker](https://discourse.julialang.org/u/PatrickHaecker)
#### Post date: [June 13, 2025, 7:25am UTC](https://discourse.julialang.org/t/why-is-expr-mutable/129850/1 "2025-06-13T07:25:40Z")

</div>

`Expr` does ~~not have object identity~~ have field equality, i.e.

```julia
julia> Expr(:call, println) == Expr(:call, println)
true

```

I was surprised to learn that `Expr` nevertheless is mutable. ~~I can easily imagine why `Expr` does not have object identity (“Oh, no, I do not mean to call this `println` method without arguments in the current module, I instead want to call that `println` method without arguments in the current module” does not really make sense).~~

The problem with being mutable is that an immutable struct with an `Expr` field now surprisingly ~~gets object identity~~ loses field equality:

```julia
struct MyExpr
    expr::Expr
end

julia> :block |> Expr |> MyExpr == :block |> Expr |> MyExpr
false

```

Note, that this is in contrast to `Symbol`, which I had expected to being implemented completely parallel to `Expr`, but ~~which is immutable and therefore no surprising~~  ~~object identity pops up~~ field equality gets lost:

```julia
struct MySymbol
    symbol::Symbol
end

julia> MySymbol(:a) == MySymbol(:a)
true

```

Semantically, I therefore do not understand, why `Expr` is mutable.

Looking at its memory structure presented in Julia (I haven’t checked the `C` implementation)

```julia
julia> using About

julia> Expr |> about
Concrete DataType defined in Core, 
  Expr <: Any

Struct with 2 fields:
• head Symbol     
• args Vector{Any}

julia> sizeof(Expr)
16

```

it looks like the args can be changed anyway as they are part of the mutable `Array`. Only when modifying the `head`, which might not happen in isolation too often anyway, a new object were to be constructed if `Expr` were immutable. But I think this would be as cheap as it could get for non-trivial immutable objects.

From a performance point of view, I therefore do neither understand, why `Expr` is mutable.

So why is `Expr` mutable?

---

_[View the full topic](https://discourse.julialang.org/t/why-is-expr-mutable/129850)._
