# How to mutate the value (not binding) of a scalar?

I can do the following to mutate the original memory,

``````w = ones(3)

3-element Vector{Float64}:
1.0
1.0
1.0

x = w

3-element Vector{Float64}:
1.0
1.0
1.0

x[2]=2.

2.0
``````

but I can’t find a way to mutate w if it’s a scalar,

``````1

x=w

1

x=2

2

w

1
``````

I think I need this because I want to broadcast over a function that takes a scratch or work array, and I need to modify its contents. But maybe there is a different idiom that I can use.

There is no way to mutate the value of a scalar such as `1` or `1.0` - they are immutable objects of type `Int` and `Float64` respectively.

Can you expand on what you’re trying to do? There’s certainly a way achieve the same effect without trying to mutate immutables.

I’ve settled on this idiom, which is more elegant I think,

``````geman_mcclure(d2,s) = return one(s) / (one(s)+d2/s^2)^2

geman_mcclure!(d2,s,w) = @. w = geman_mcclure(d2,s)
``````

I see - in julia, we’d typically have the mutated argument be the first argument of the function, so I’d write it like this:

``````geman_mcclure(d2, s) = one(s) / (one(s)+d2/s^2)^2
geman_mcclure!(w, d2, s) = geman_mcclure!(d2,s,w) = @. w = geman_mcclure(d2,s)
``````

May I ask, what types do you expect to put into this? Is `d2` an array?

d2 and w are Vector{T <: AbstractFloat}

Then I’d recommend implementing it like this:

``````function geman_mcclure!(w, d2, s)
@. w = one(s) / (one(s) + d2 / s^2)^2
end
geman_mcclure(d2, s) = geman_cclure!(similar(d2), d2, s)
``````

If `d2` for the non-mutating version is also expected to be a `Vector`, as otherwise the method won’t work:

``````julia> gm1(d2, s) = one(s) / (one(s)+d2/s^2)^2
gm1 (generic function with 1 method)

julia> gm1(rand(Float64, 10), rand(Float64))
ERROR: MethodError: no method matching +(::Float64, ::Vector{Float64})

Closest candidates are:
+(::Any, ::Any, ::Any, ::Any...)
@ Base operators.jl:578
+(::T, ::T) where T<:Union{Float16, Float32, Float64}
@ Base float.jl:406
+(::Union{Float16, Float32, Float64}, ::BigFloat)
@ Base mpfr.jl:414
...

Stacktrace:
[1] gm1(d2::Vector{Float64}, s::Float64)
@ Main ./REPL[7]:1
[2] top-level scope
@ REPL[8]:1
``````

Though usually, we try to avoid writing an explicitly vectorized function like `geman_mcclure!` and just directly use broadcasting inline, to allow for loop fusion to occur in longer chains (in which case your original scalar version is perfect already, and no other methods would be needed). It’s just a question of what you’d expect users to pass in.

1 Like

Thanks for the tips, but I don’t understand your last comment. In this case, geman_mcclure will be called with vectors of data passed in d2,s. Will broadcasting on the function allow the arithmetic operations to be fused? And can you give an example of what you mean by “broadcasting inline?”

And the non_mutating versions can be scalars. I’m usually writing functions for scalars and broadcast over the function at the caller level. I try not to write vectorized code at the function level, but now I see how your suggestion can accommodate both types of calls. Thanks!

Generally, yes - writing `geman_mcclure.(d2, s)` with `d2` a `Vector` and `s` a scalar (or even a vector of the same length as `d2`) is equivalent to

``````out_arr = similar(d2)
for i in eachindex(d2)
out_arr[i] = geman_mcclure(d2[i], s) # geman_mcclure(d2[i], s[i]) if `s` is broadcastable
end
out_arr
``````

which is the same as your explicitly vectorized `geman_mcclure!` function, modulo the additional allocation, which can be done ahead of time manually. If done ahead of time, you can (just with `geman_mcclure`) then write `w .= geman_mcclure.(d2, s)` , which is already equivalent to the loop above, except that `out_arr` does not have to be allocated, because it already exists.

This is a common pattern - instead of writing explicitly vectorized versions of scalar functions like `geman_mcclure!`, we usually only have the scalar version and broadcast/inplace-broadcast/map as necessary, allowing loop fusion to take place.

In comparison, `geman_mcclure!` does not allow loop fusion with broadcast outside of itself. That is, this example will not fuse loops:

``````z .= a .+ geman_mcclure!(w, ds2, s)
``````

(there will first be the inner loop inside of `geman_mcclure!`, then the outer one over `z` and `a`) whereas this will:

``````z .= a .+ geman_mcclure.(ds2, s)
``````

which is in fact equivalent to

``````for idx in eachindex(z, a, ds2)
z[idx] = a[idx] + geman_mcclure(ds2[idx], s)
end
``````

This is also what I mean with “broadcasting inline” - simply using the scalar version in a broadcast is more flexible than having `geman_mcclure!`, which is required to complete before the outer broadcast can be calculated. The general rule of thumb for when I use explicitly modifying functions is either when the operation is not a scalar operation (i.e., more than a single index is required to perform the calculation, forcing you to write a loop either way) or when there’s a truly persistent modification of a datastructure as a sideeffect happens, e.g. with `get!`:

``````help?> get!
search: get! mergewith! get getpid getkey getfield getindex getglobal

get!(collection, key, default)

Return the value stored for the given key, or if no mapping for the
key is present, store key => default, and return default.

Examples
≡≡≡≡≡≡≡≡≡≡

julia> d = Dict("a"=>1, "b"=>2, "c"=>3);

julia> get!(d, "a", 5)
1

julia> get!(d, "d", 4)
4

julia> d
Dict{String, Int64} with 4 entries:
"c" => 3
"b" => 2
"a" => 1
"d" => 4
``````
1 Like