# Mutating function-like objects, enforcing "!"?

**URL:** https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825
**Category:** General Usage
**Tags:** question, function, functions, function-like-object
**Created:** [July 20, 2023, 8:49am UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825 "2023-07-20T08:49:59Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![tamasgal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamasgal/32/27946_2.png) [@tamasgal](https://discourse.julialang.org/u/tamasgal)
#### Post date: [July 20, 2023, 8:49am UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825/1 "2023-07-20T08:49:59Z")

</div>

For many users, this is probably a minor bike-shed thing but I wanted to dump it `;)` maybe it’s even a bug or let’s say, design flaw (see at the end), no idea.

I use function-like objects a lot in my packages and I constantly bump into this.

Given the following simple example

```julia
julia> struct Foo
         buffer::Vector{Float64}
         Foo() = new(Float64[])
       end
julia> function (f::Foo)(arr)
         resize!(f.buffer, length(arr))
         # do some stuff, use the `buffer`, mutate `arr` etc.
         reverse!(arr) # just that we mutate...
       end

```

we will end up with:

```julia
julia> f = Foo()
Foo(Float64[])

julia> f([1,2,3])
3-element Vector{Int64}:
 3
 2
 1

```

My problem is that there is of course no `!` to indicate that `f` is mutating, so the only way to make it look nicer (i.e. signal that it’s mutating) is **discipline** , which is a source of error in the sense that users of the package will likely name their `Foo()` whatever they like and not realise that calling it will mess with the input values, so they will not even think about adding an `!`.

So this is the “discipline” which is required, when creating `Foo()`:

```julia
julia> f! = Foo()
Foo(Float64[])

julia> f!([2,3,4]) # add the !
3-element Vector{Int64}:
 4
 3
 2

```

What I find confusing however (this is the bug or design flaw part) is that you can defeine `(f::Foo)!(arr) and will not give any error, but then nothing is callable:

```julia
julia> struct Foo
         buffer::Vector{Float64}
         Foo() = new(Float64[])
       end

julia> function (f::Foo)!(arr)
         resize!(f.buffer, length(arr))
         # do some stuff, use the `buffer`, mutate `arr` etc.
         reverse!(arr) # just that we mutate...
       end
#16 (generic function with 1 method)

julia> f = Foo()
Foo(Float64[])

julia> f!([2,3,4])
ERROR: UndefVarError: `f!` not defined
Stacktrace:
 [1] top-level scope
   @ REPL[4]:1

julia> f([2,3,4])
ERROR: MethodError: objects of type Foo are not callable
Stacktrace:
 [1] top-level scope
   @ REPL[5]:1

```

So I am wondering what happens when defining `(f::Foo)!(arr)`, where is the `!`? `;)`

To me it would make sense that however `Foo()` is named later, I can call `however!(arr)` when defining `(f::Foo)!(arr)`.

I assume this would not be a breaking change since it did not work before, so maybe something for Julia 1.10 or 1.11, unless I am overlooking something.

Any thoughts?

---

<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 20, 2023, 9:23am UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825/2 "2023-07-20T09:23:36Z")

</div>

```julia
function (f::Foo)!(arr)
  arr
end

```

is equivalent to

```julia
function (f::Foo) # anonymous function
  !(arr) # undefined arr
  arr
end

```

`@macroexpand` shows these expressions are equivalent, can also put these expressions through `dump` to display them as ASTs.

You can’t append a character to a name from outside parentheses `(f::Foo)!`, you must write it with the name `(f!::Foo)`. And like all other methods belonging to `Foo`, `f!::Foo` is a local variable like the other arguments, not a global variable you can use to call.

---

<div class="post-metadata">

### Author: ![tamasgal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamasgal/32/27946_2.png) [@tamasgal](https://discourse.julialang.org/u/tamasgal)
#### Post date: [July 20, 2023, 9:34am UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825/3 "2023-07-20T09:34:46Z")

</div>

Yes you are right, I just realised that the syntax would then obviously be a breaking change `;)`

---

<div class="post-metadata">

### Author: ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)
#### Post date: [July 20, 2023, 9:42am UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825/4 "2023-07-20T09:42:39Z")

</div>

Maybe you could at least name your struct `Foo!`, which might act as a little reminder for your users that callable instances of it mutate their arguments?

```julia
julia> struct Foo!
           buffer::Vector{Float64}
           Foo!() = new(Float64[])
       end

julia> function (f::Foo!)(arr)
           resize!(f.buffer, length(arr))
           # do some stuff, use the `buffer`, mutate `arr` etc.
           reverse!(arr) # just that we mutate...
       end

# Seeing the ! in the type name might remind me (as a user)
# to append a ! to the instance name as well
julia> f! = Foo!()
Foo!(Float64[])

julia> a= [1,2,3]
3-element Vector{Int64}:
 1
 2
 3

julia> f!(a); a
3-element Vector{Int64}:
 3
 2
 1

```

---

<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 20, 2023, 10:12am UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825/5 "2023-07-20T10:12:06Z")

</div>

> [@ffevotte](#):
>
> name your struct `Foo!`

That would make me think it’s the constructor method that mutates the arguments, not the callable instances.

---

<div class="post-metadata">

### Author: ![HanD](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hand/32/213908_2.png) [@HanD](https://discourse.julialang.org/u/HanD)
#### Post date: [July 20, 2023, 2:06pm UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825/6 "2023-07-20T14:06:25Z")

</div>

You just explained why the callable object function should _not_ be a mutating function. In case you want to mutate your object, create a standalone mutating function and pass the object as the first argument.

```julia
julia> function use!(f::Foo, arr)
         resize!(f.buffer, length(arr))
         # do some stuff, use the `buffer`, mutate `arr` etc.
         reverse!(arr) # just that we mutate...
       end

```

There. Keep callable object functions for stuff without side effects.

---

<div class="post-metadata">

### Author: ![tamasgal](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamasgal/32/27946_2.png) [@tamasgal](https://discourse.julialang.org/u/tamasgal)
#### Post date: [July 21, 2023, 11:38am UTC](https://discourse.julialang.org/t/mutating-function-like-objects-enforcing/101825/7 "2023-07-21T11:38:28Z")

</div>

I guess that’s the best workaround 😉
