# Why is bang(!) indicating argument mutation a convention, but not enforced?

**URL:** https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783
**Category:** Internals & Design
**Created:** [November 8, 2020, 11:23am UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783 "2020-11-08T11:23:12Z")
**Posts on this page:** 16
**Page:** 1

<div class="post-metadata">

### Author: ![bilderbuchi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bilderbuchi/32/13562_2.png) [@bilderbuchi](https://discourse.julialang.org/u/bilderbuchi)
#### Post date: [November 8, 2020, 11:23am UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/1 "2020-11-08T11:23:12Z")

</div>

As a Julia beginner/neophyte, I am wondering why using a `!` name suffix for functions that _may_ mutate their arguments is merely a [convention](https://docs.julialang.org/en/v1/manual/style-guide/#bang-convention), but is not enforced by the compiler?

It is nice to have this indication available when using language/package functions, but on the other hand I cannot _rely_ on it (except maybe in the stdlib?), which I think somewhat diminishes its value.  
At the same time, if this were strictly enforced, beside increasing clarity of the affected APIs, would that not also afford some avenues for internal optimisations by the compiler?

I’m sure this already came up before, but I searched both the docs and the forum and could not find a relevant discussion/information. 🤔

---

<div class="post-metadata">

### Author: ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)
#### Post date: [November 8, 2020, 11:54am UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/2 "2020-11-08T11:54:45Z")

</div>

The only reasonable interpretation would be “no pointer derived from any argument is written to”.

Consider e.g., `map(fun, arr)` – what happens if `fun` has side-effects that write to memory? What if some methods of fun have side-effects and some don’t? Is this call violating a mutability contract? Do you want functions typed by purity?

In short: Neither Julia’s type system nor Julia conventions are a good fit for that kind of stuff. I guess haskell or idris might be languages where this makes more sense (either do some monadic dance or get a compiler error).

Btw, a variety of similar annotations make a lot of sense – on the method level, not the function level, and as hints to the optimizer (hints as in axioms / assumptions that the optimizer may trust). One of then is `@pure`, which is almost impossible to safely use, even for core developers (inofficial definition: “a method is @pure if and only if jameson says so”). Some others are available in llvm.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [November 8, 2020, 1:17pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/3 "2020-11-08T13:17:45Z")

</div>

Also, the bang notation is not ideal, it does not indicate: which parameters risk being mutated, if some mutation always occurs or it depends on parameter values; and is, for example, ignored by all the `IO` functions in `Base`, because basically everything there would need a bang.

It is a great convention for distinguishing between two alternative functions (one which copy and the other that works inplace) and also as a `danger sign` for function that are often misused because the users assume they did not change the arguments. But I think trying to make it more than that would take a lot of effort which would not be worth.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [November 8, 2020, 1:35pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/4 "2020-11-08T13:35:24Z")

</div>

> [@bilderbuchi](#):
>
> on the other hand I cannot _rely_ on it

In this sense, you cannot really rely on _anything_ a package claims to do, because the compiler does not check algorithmic correctness.

---

<div class="post-metadata">

### Author: ![bilderbuchi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bilderbuchi/32/13562_2.png) [@bilderbuchi](https://discourse.julialang.org/u/bilderbuchi)
#### Post date: [November 9, 2020, 7:26am UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/5 "2020-11-09T07:26:03Z")

</div>

Thank you for clearing this up for me, this all sounds reasonable! In a way this then seems similar in purpose to Python type annotations - optional, and not checked by the interpreter, mainly meant to ease the work of IDEs/linters/static analysers, and developers.  
I’ll think on this some more… 🙂

---

<div class="post-metadata">

### Author: ![ErikE](https://avatars.discourse-cdn.com/v4/letter/e/e9a140/32.png) [@ErikE](https://discourse.julialang.org/u/ErikE)
#### Post date: [November 10, 2020, 1:47pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/6 "2020-11-10T13:47:02Z")

</div>

It could very well be that, in practice, banning functions who’s name don’t end in ‘!’ from modifying their arguments is too difficult to be sensible - I don’t know enough about Julia to tell (I’m new too). But Tamas\_Papp’s comment still made me want to express some thoughts.

I cannot rely on comments or (other) documentation being correct. I cannot rely on conventions being followed. I cannot rely on code being bug-free. But, barring bugs in the compiler, I _can_ rely on rules of the language being followed. For instance, if a variable is declared `const`, I can rely on it not being modified. Or, if a procedure argument in Fortran is declared `INTENT(IN)`, I can rely on it not being modified by the procedure. (In C, declaring a pointer argument to a function as `const` isn’t a guarantee, but gets you pretty close)

If I can declare what some code does or does not do, using language features rather than using comments or conventions, I strongly prefer that. Because comments can be wrong, and conventions can be broken, but language rules cannot. They can be relied upon. It’s nice not just for the user/reader of some code, but also for its writer, as it may catch bugs. What if I really didn’t intend to modify a function argument, but by mistake did anyway?

Obviously, there will always be uncertainty about what some unfamiliar code does, or whether your own code have bugs. But while less uncertainty isn’t as good as no uncertainty, it is still better than more uncertainty. Let’s not refuse to reduce uncertainty just because we can’t eliminate it.

If there was a way of declaring “INTENT” for function arguments in Julia, be it with exclamation marks at the end of function names or through some other means, I think it would be nice. Not something I can’t live without, and if it’s decided it isn’t worth the trouble, I can accept that, but still - it would be nice.

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [November 10, 2020, 1:59pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/7 "2020-11-10T13:59:48Z")

</div>

> [@ErikE](#):
>
> For instance, if a variable is declared `const` , I can rely on it not being modified.

I think you misunderstand what `const` does — its _your_ promise to the _compiler_, not the other way round. Cf

```julia
julia> const a = 1
1

julia> a = 2
WARNING: redefinition of constant a. This may fail, cause incorrect answers, or produce other errors.
2

```

---

<div class="post-metadata">

### Author: ![johnmyleswhite](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/johnmyleswhite/32/31_2.png) [@johnmyleswhite](https://discourse.julialang.org/u/johnmyleswhite)
#### Post date: [November 10, 2020, 2:32pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/8 "2020-11-10T14:32:44Z")

</div>

If someone really cares about this, it would be interesting to see a prototype of a linter that does whole program analysis to verify that a nominally non-mutating function never invokes any mutating functions in any given codebase.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [November 10, 2020, 3:03pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/9 "2020-11-10T15:03:51Z")

</div>

In addition to Tamas point that you can misunderstand the documentation, I would like to point out that Julia patch versions exist exactly because the language failed to guarantee its own rules. I myself have already found an _unreachable_ bug in Julia 1.0.5 and had to change versions because the correction would not be back-ported, so the only implementation of the language rules (for some major-minor version) may be broken and without prospect of repairs.

---

<div class="post-metadata">

### Author: ![ErikE](https://avatars.discourse-cdn.com/v4/letter/e/e9a140/32.png) [@ErikE](https://discourse.julialang.org/u/ErikE)
#### Post date: [November 10, 2020, 4:41pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/10 "2020-11-10T16:41:07Z")

</div>

> [@Tamas\_Papp](#):
>
> > [@ErikE](#):
> >
> > For instance, if a variable is declared `const` , I can rely on it not being modified.
> 
> I think you misunderstand what `const` does — its _your_ promise to the _compiler_, not the other way round. Cf
> 
> ```julia
> julia> const a = 1
> 1
> 
> julia> a = 2
> WARNING: redefinition of constant a. This may fail, cause incorrect answers, or produce other errors.
> 2
> 
> ```

Oh? It seems I’ve learned something new today, then - thanks! 🙂

But let me point out that it still gives a warning. If you would declare that `a` is meant to be a constant only through some naming convention or a comment, you would get neither errors nor warnings when it’s modified.  
It’s not an unimportant difference.

---

<div class="post-metadata">

### Author: ![BioTurboNick](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bioturbonick/32/6380_2.png) [@BioTurboNick](https://discourse.julialang.org/u/BioTurboNick)
#### Post date: [November 10, 2020, 5:57pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/11 "2020-11-10T17:57:33Z")

</div>

While the request here might not be enforceable, perhaps a useful extension would be for the function signature to document which arguments are mutable as well?

Something like

```julia
function push!(collection!, item)
    # do stuff
end

a = [1,2]
push!(a!, 3)

```

Though I guess that would require changing ! from just a character that can be part of a symbol to an optional decorator, which would break things.

---

<div class="post-metadata">

### Author: ![BioTurboNick](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bioturbonick/32/6380_2.png) [@BioTurboNick](https://discourse.julialang.org/u/BioTurboNick)
#### Post date: [November 10, 2020, 6:06pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/12 "2020-11-10T18:06:36Z")

</div>

But here’s a discussion on a related topic that is helpful: [https://github.com/JuliaLang/julia/issues/26484](https://github.com/JuliaLang/julia/issues/26484)

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [November 11, 2020, 8:48am UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/13 "2020-11-11T08:48:09Z")

</div>

> [@ErikE](#):
>
> It’s not an unimportant difference.

No one is arguing that. But a feature like this a lot of work and will probably be implemented only when someone wants it bad enough to invest the work.

While using `!` in function names is not a 100% perfect solution, it is good enough for in practice for a lot of things.

---

<div class="post-metadata">

### Author: ![bilderbuchi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bilderbuchi/32/13562_2.png) [@bilderbuchi](https://discourse.julialang.org/u/bilderbuchi)
#### Post date: [November 18, 2020, 7:27pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/14 "2020-11-18T19:27:41Z")

</div>

Thank you all for the interesting inputs and perspective. And especially @ErikE for formulating my intention in a much more eloquent way - I am more or less 100% aligned with what you say, about language features like `INTENT`, or `const` (at least the non-Julia one), or Modelica’s `constant`/`parameter`/`variable` variability indication, language features vs. convention vs. comments, etc. (btw, I was also surprised about the “direction” of the const-promise 😃 - thanks!)

I am wondering - what mechanism triggers these warnings when you modify a `const` object, and how well does that work (is there a limit to the detection heuristic)?  
Can’t this same mechanism be adapted to warn if your function-without-bang mutates any of its arguments? After all, doesn’t a function-without-bang essentially correspond to having only `const` arguments (at least in the function’s scope)? Could that be leveraged somehow? E.g. could the compiler just slap `const`s in front of all function arguments if there is no bang at the end of the function name? (Surely it’s not as easy as that)

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [November 18, 2020, 7:43pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/15 "2020-11-18T19:43:07Z")

</div>

> [@bilderbuchi](#):
>
> Can’t this same mechanism be adapted to warn if your function-without-bang mutates any of its arguments?

No–it really doesn’t work this way. The warning happens when you _assign a new value_ to a variable which has been marked as `const`. That’s completely different than _mutating_ an existing value, which is what the `!` suffix refers to.

Try this:

```julia
julia> const x = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

julia> x[1] = 10
10

```

`x` has been mutated, but there is no warning, and the resulting code will work correctly with no issues. That’s exactly as intended: the `const` label has nothing to do with mutation of an existing value. Instead, the warning occurs if you assign a _new_ value:

```julia
julia> x = [4, 5, 6]
WARNING: redefinition of constant x. This may fail, cause incorrect answers, or produce other errors.

```

> [@bilderbuchi](#):
>
> After all, doesn’t a function-without-bang essentially correspond to having only `const` arguments (at least in the function’s scope)?

No, definitely not, and for the same reason. A function with `!` may _mutate_ its arguments (which is not something `const` cares about).

As an exercise, consider:

```julia
function f1(x)
  x = [1, 2, 3]
end

```

and

```julia
function f2!(x)
  x[1] = 1
  x[2] = 2
  x[3] = 3
end

```

Both are perfectly legal functions, but only `f2` will modify the value which was passed into it. `f1` just creates a brand-new value with the same name in its local scope and has no effect on the value you pass in.

---

<div class="post-metadata">

### Author: ![bilderbuchi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bilderbuchi/32/13562_2.png) [@bilderbuchi](https://discourse.julialang.org/u/bilderbuchi)
#### Post date: [November 18, 2020, 7:48pm UTC](https://discourse.julialang.org/t/why-is-bang-indicating-argument-mutation-a-convention-but-not-enforced/49783/16 "2020-11-18T19:48:48Z")

</div>

Perfectly clear, thanks for indulging this greenhorn! 🙂
