# Why is BigFloat mutable?

**URL:** <https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918>\
**Category:** General Usage\
**Tags:** question\
**Created:** [January 19, 2025, 12:32pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918 "2025-01-19T12:32:21Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 19, 2025, 12:32pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/1 "2025-01-19T12:32:21Z")

</div>

In adding more tests to BorrowChecker.jl, I ran into the weird cases of BigInt and BigFloat. Apparently these are actually mutable:

```julia
julia> x = big(1.0)
1.0

julia> y = x
1.0

julia> y.prec *= 2
512

julia> x # [Original float changed]
0.711763059342694544306441584158307023432639792317636119656901806469269447295820159150765983076895562999055705307595782779072780864355582835926727856355473418

```

Does anybody know why this is? Are there any operations that take advantage of this? I noticed that standard operations still create new objects:

```julia
julia> x = big(1.0)
1.0

julia> y = x
1.0

julia> y *= 2
2.0

julia> x
1.0

```

So I wasn’t sure where the mutability actually came into play, if at all. I mean, even `String` is immutable.

---

<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:** [January 19, 2025, 12:41pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/2 "2025-01-19T12:41:43Z")

</div>

They’re mutable because they need to carry around a reference for GC and whatnot. They’re managed by external libraries.

Some packages do take advantage of this yes: [GitHub - jump-dev/MutableArithmetics.jl: Interface for arithmetics on mutable types in Julia](https://github.com/jump-dev/MutableArithmetics.jl), [GitHub - tkluck/InPlace.jl: InPlace.jl - in-place operations where possible](https://github.com/tkluck/InPlace.jl)

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 19, 2025, 12:54pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/3 "2025-01-19T12:54:01Z")

</div>

Does the entire object need to be mutable for that though?

```julia
# gmp.jl
mutable struct BigInt <: Signed
    alloc::Cint
    size::Cint
    d::Ptr{Limb}
end

```

---

<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:** [January 19, 2025, 1:23pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/4 "2025-01-19T13:23:20Z")

</div>

Fields are modified in-place in the [source code](https://github.com/JuliaLang/julia/blob/cbc47c9fb852773e379cce062d6bd2aec743a7cf/base/gmp.jl), so yes.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 19, 2025, 1:31pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/5 "2025-01-19T13:31:00Z")

</div>

So… just these?

```julia
ZERO.alloc, ZERO.size, ZERO.d = 0, 0, C_NULL
ONE.alloc, ONE.size, ONE.d = 1, 1, pointer(_ONE)

```

Why couldn’t this be done at instantiation time? Why does the entire object need to be mutable in user space?

---

<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:** [January 19, 2025, 1:34pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/6 "2025-01-19T13:34:48Z")

</div>

> [@MilesCranmer](#):
>
> Why couldn’t this be done at instantiation time?

That’s modifying in-place only two globals, that has to be done during ` __init__ `.

I see also

> <https://github.com/JuliaLang/julia/blob/cbc47c9fb852773e379cce062d6bd2aec743a7cf/base/gmp.jl#L942-L950>

> <https://github.com/JuliaLang/julia/blob/cbc47c9fb852773e379cce062d6bd2aec743a7cf/base/gmp.jl#L339>

and haven’t looked much further

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 19, 2025, 1:39pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/7 "2025-01-19T13:39:42Z")

</div>

Well `sync_rational!` could be rewritten as

```julia
function sync_rational!(xq::_MPQ)
    xq.rat.num = BigInt(xq.num_alloc, xq.num_size, xq.num_d)
    xq.rat.den = BigInt(xq.den_alloc, xq.den_size, xq.den_d)
    return xq.rat
end

```

and the `unsafe_store!` should already be fine since `z.d` is a `Ptr`. It isn’t assigning `z.d` there.

> [@giordano](#):
>
> That’s modifying in-place only two globals, that has to be done during ` __init__ `.

I think it’d be better to just make those constants references then

```julia
const ZERO = Ref{BigInt}()
const ONE = Ref{BigInt}()

```

instead of making `BigInt` mutable everywhere for all users

---

<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:** [January 19, 2025, 1:43pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/8 "2025-01-19T13:43:48Z")

</div>

`BigFloat` isn’t mutable any more on v1.12, since [make faster BigFloats by vtjnash · Pull Request #55906 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/55906)

> [@MilesCranmer](#):
>
> even `String` is immutable.

Not really. It’s meant to be immutable, but that’s not enforced at all levels. And:

```julia-repl
julia> ismutable("")
true

julia> ismutabletype(String)
true

```

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 19, 2025, 1:44pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/9 "2025-01-19T13:44:42Z")

</div>

Ah, that’s great!! Thanks.

(I guess someone should make a similar PR for BigInt?)

---

<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:** [January 19, 2025, 1:48pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/10 "2025-01-19T13:48:48Z")

</div>

But keep in mind the underlying data is still mutable, it’s just that `BigFloat` isn’t a `mutable struct` any more. In particular, MutableArithmetics.jl, an important low-level package, still works fine for `BigFloat`, on nightly too:

```julia-repl
julia> using MutableArithmetics: MutableArithmetics as MA

julia> x = big(.1)
0.1000000000000000055511151231257827021181583404541015625

julia> MA.operate!(+, x, x)
0.200000000000000011102230246251565404236316680908203125

julia> x
0.200000000000000011102230246251565404236316680908203125

```

That said, MutableArithmetics.jl needs to trespass on implementation details of `Base` to work on `BigInt` or `BigFloat`, a public interface to do the mutation has never existed: [mutating APIs for BigInts and BigFloats? · Issue #31342 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/31342)

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 19, 2025, 3:45pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/11 "2025-01-19T15:45:01Z")

</div>

Thanks! I guess the good news is that `BorrowChecker.is_static` already flags these for moves (since the `Ptr` is mutable), so no changes are needed.

Though it’s a bit frightening that doing `copy` on an array of `BigFloat` will result in an array that is aliased to the original 😱

```julia
julia> x = big.(randn(32));

julia> y = copy(x); # shallow copy not enough

julia> MA.operate!(+, y[1], 3);

```

I guess this would modify `x[1]` too, which is kinda terrifying. At what point do the perf gains outweigh this much debugging difficulty… For this reason I feel like there probably shouldn’t ever be a public interface?

---

<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:** [January 19, 2025, 3:57pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/12 "2025-01-19T15:57:53Z")

</div>

I’m not sure if this is actually documented, but the official story for `Number` (thus `BigInt` and `BigFloat`) is “treat it as immutable”. That justifies the behavior of `copy(::BigFloat)` being the identity.

On the other hand, the MutableArithmetics.jl interfaces are perfectly sane, too, in particular, `mutable_copy` and `copy_if_mutable` are provided:

- [`MutableArithmetics.copy_if_mutable`](https://jump.dev/MutableArithmetics.jl/stable/#MutableArithmetics.copy_if_mutable-Tuple%7BAny%7D)
- [`MutableArithmetics.mutable_copy`](https://jump.dev/MutableArithmetics.jl/stable/#MutableArithmetics.mutable_copy)

---

<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:** [January 19, 2025, 11:51pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/13 "2025-01-19T23:51:00Z")

</div>

> [@nsajko](#):
>
> > [@MilesCranmer](#):
> >
> > even `String` is immutable.
> 
> Not really. It’s meant to be immutable, but that’s not enforced at all levels.

It is enforced throughout the public API, even going so far as to special case `===` and `objectid` to compare by value instead of memory address. `String` is clearly meant to behave as an immutable type in every respect. I suppose you can grab a pointer and go wild, but it’s probably not a relevant design goal for BorrowChecker.jl to accommodate such experiments.

The fact that `ismutable` seems to disagree is explicitly flagged in a note in the docstring: [Essentials · The Julia Language](https://docs.julialang.org/en/v1/base/base/#Base.ismutable)

> NOTE: For technical reasons, `ismutable` returns `true` for values of certain special types (for example `String` and `Symbol`) even though they cannot be mutated in a permissible way.

---

<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:** [January 19, 2025, 11:59pm UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/14 "2025-01-19T23:59:57Z")

</div>

The main reason `String` is treated as mutable is that any operation that creates a string requires mutating a String using some internal and slightly hacky functionality.

---

<div class="post-metadata">

**Author:** ![magister-ludi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/magister-ludi/32/4003_2.png) [@magister-ludi](https://discourse.julialang.org/u/magister-ludi)\
**Post date:** [January 20, 2025, 12:26am UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/15 "2025-01-20T00:26:04Z")

</div>

> [@MilesCranmer](#):
>
> ```julia
> julia> y = x
> 1.0
> 
> julia> y *= 2
> 2.0
> 
> julia> x
> 1.0
> 
> ```

Off -topic, really, but it’s worth noting that this doesn’t suggest that `y` is mutable. The reference has changed, not the object itself.

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 20, 2025, 12:36am UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/16 "2025-01-20T00:36:10Z")

</div>

Thanks. Just curious: why would a low-level string precursor necessitate marking the resultant `String` object as mutable in user-space? Or does it actually create a `String` and then mutate it from within Julia?

---

<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:** [January 20, 2025, 1:03am UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/17 "2025-01-20T01:03:30Z")

</div>

> Or does it actually create a `String` and then mutate it from within Julia?

yes.

```julia
string(a::Union{Char, String, SubString{String}, Symbol}...) = _string(a...)

function _string(a::Union{Char, String, SubString{String}, Symbol}...)
    n = 0
    for v in a
        # 4 types is too many for automatic Union-splitting, so we split manually
        # and allow one specializable call site per concrete type
        if v isa Char
            n += ncodeunits(v)
        elseif v isa String
            n += sizeof(v)
        elseif v isa SubString{String}
            n += sizeof(v)
        else
            n += sizeof(v::Symbol)
        end
    end
    out = _string_n(n)
    offs = 1
    for v in a
        if v isa Char
            offs += __unsafe_string!(out, v, offs)
        elseif v isa String || v isa SubString{String}
            offs += __unsafe_string!(out, v, offs)
        else
            offs += __unsafe_string!(out, v::Symbol, offs)
        end
    end
    return out
end

```

---

<div class="post-metadata">

**Author:** ![MilesCranmer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/milescranmer/32/21070_2.png) [@MilesCranmer](https://discourse.julialang.org/u/MilesCranmer)\
**Post date:** [January 20, 2025, 1:08am UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/18 "2025-01-20T01:08:31Z")

</div>

Thanks. I wonder if making a special internal `_MutableString` type for mutation at that stage would be better? That way `String` could actually be marked as immutable so that the compiler could do constant folding in user code (??)

---

<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:** [January 20, 2025, 1:29am UTC](https://discourse.julialang.org/t/why-is-bigfloat-mutable/124918/19 "2025-01-20T01:29:33Z")

</div>

> [@danielwe](#):
>
> `String` is clearly meant to behave as an immutable type in every respect.

Yes, “meant to”. That’s what I said in the first place:

> [@nsajko](#):
>
> It’s meant to be immutable
