# Why no := operator for initializing variables

**URL:** <https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949>\
**Category:** Internals & Design\
**Created:** [June 15, 2021, 2:08pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949 "2021-06-15T14:08:23Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [June 17, 2021, 9:45pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/21 "2021-06-17T21:45:44Z")

</div>

This was a lot more necessary in Perl because if you do `$x = 123` inside of a function body, it would assign to / create a global variable. So the only non-breaking option given that was to introduce a new syntax for assigning a new local variable, which was `my $x = 123`. The next evolution was to introduce `our $x = 123` to explicitly ask to assign to the global. Once you have that, you can introduce `use strict` disallowing creating a new variable implicitly by assignment. But note that they didn’t get there very intentionally, it was a bit of a rambling path.

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [June 17, 2021, 10:52pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/22 "2021-06-17T22:52:39Z")

</div>

My recollection is that `local $x` to create a dynamically scoped local variable came very early. I know that `my $x` for lexically scoped variables came quite a bit later. I don’t recall if `strict` came before `my`. But yes, it was more useful in perl than it is for Julia (and probably python).  
I agree that introducing lexically scoped variables a few years down the road was probably not planned. But, perl was originally designed with simplicity in mind; and not thinking about scope at all is simplest. `local` could be used by more advanced users. This is just guesses based on my recollection of perl culture.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [June 18, 2021, 11:29am UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/23 "2021-06-18T11:29:42Z")

</div>

> [@oheil](#):
>
> Could this type of syntax help for easier compiling and linking of standalone executables (slim executables without the julia runtime included) ?

No, the syntax for declaring variables has no impact on standalone executables.

> [@peteole](#):
>
> However there I see the issue that casting should be somehow allowed, else
> 
> ```julia-auto
> x:=1
> x=1.5
> 
> ```
> 
> would throw an error which may be undesired.  
> I would only fix a type if the type is explicitly specified.

Without the type-stable globals, this idea doesn’t seem very appealing to me. Then all it does is trade one way of declaring new variables (by `x =` when an outer local named `x` doesn’t exist) for another one (by `x :=`). I can guarantee that this would also confuse people and my guess is that it would be more confusing to more people than what we do now. What we do now has the property of mostly doing what people want without them having to think about the difference between declaration an assignment.

> [@dlfivefifty](#):
>
> But if `:=` becomes possible it will appear all over the place, and require a careful explanation (that no one will actually understand) very early on the docs… so the more verbose version with `let` sounds much better to me.

It’s just an interesting thought experiment — we can’t practically do this even in a 2.0 release. It would be a _massively_ breaking change: we would need to disallow implicit declaration of locals by assignment, which breaks all Julia code everywhere. I also think that what we do now is good and less annoying for new users since they will be accustomed to just assigning to initialize and declare new locals if they are coming from Python, R, Matlab or Ruby (to mention just a few).

---

<div class="post-metadata">

**Author:** ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)\
**Post date:** [June 18, 2021, 11:34am UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/24 "2021-06-18T11:34:05Z")

</div>

> [@oxinabox](#):
>
> Why not add this feature to the language now?

Reminds of an adventure game I played. It started with a joke. This person keep answering questions with another question. So this other person asked him, “why do you always answer a question with another question”, to which the person replied “Why not?”

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [June 18, 2021, 12:00pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/25 "2021-06-18T12:00:13Z")

</div>

I should maybe add that the _only_ change I think we should make to the local scope behavior as [documented here](https://docs.julialang.org/en/v1/manual/variables-and-scoping/#Local-Scope) is that this sentence:

> - in _non-interactive_ contexts (files, eval), an ambiguity warning is printed and a new local is created;

should instead be changed to this:

> - in _non-interactive_ contexts (files, eval), an ambiguity warning is printed and the existing global is assigned;

Of course, that makes the interactive and non-interactive behavior the same except for the ambiguity warning so I would probably change that section to this:

> 1. **Soft scope:** If `x` is _not already a local variable_ and all of the scope constructs containing the assignment are soft scopes (loops, `try` / `catch` blocks, or `struct` blocks), the behavior depends on whether the global variable `x` is defined:
> - If global `x` is _undefined_ , a new local named `x` is created in the scope of the assignment;
> - If global `x` is _defined_ , the global variable `x` is assigned.
> 
> The assignment in the last case (soft scope, existing global) is considered ambiguous: it is not clear from local syntactic context alone whether the assignment is meant to assign to the global or create a new local as it would if there were not already a global by that name. Therefore, when this code is evaluated in a file or other non-interactive context, an ambiguity warning is printed, prompting you to explicitly declare the assignment to be global or local (or rename the variable to avoid the name collision). In interactive contexts the global is assigned without any warning.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [June 18, 2021, 12:35pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/26 "2021-06-18T12:35:44Z")

</div>

> [@StefanKarpinski](#):
>
> It’s just an interesting thought experiment — we can’t practically do this even in a 2.0 release. It would be a _massively_ breaking change: we would need to disallow implicit declaration of locals by assignment, which breaks all Julia code everywhere.

One mitigating factor that might make it just barely plausible to make a change like this is that it is a purely syntactic change, so it is highly amenable to automatic upgrading: you can parse the old syntax just generate the new syntax completely reliably. That said, there’s a lot of Julia code in the world at this point — and there will be even more by the time we get to 2.0 — and I really don’t think it’s a good idea to break all of it.

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [June 18, 2021, 4:50pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/27 "2021-06-18T16:50:10Z")

</div>

To answer some of the historical question: I consider a distinction like `:=` vs. `=` to be a “fussy” language feature. They are almost the same thing, there is little natural intuition about what the difference might be, and yet you sometimes must use one, and sometimes the other. It makes matters worse that Python has now added `:=` with a different meaning. To review, we would have

1. Algol / Pascal: `:=` is updating assignment
2. Python: `:=` is an expression yielding a value, `=` is a statement (both are just `=` in julia)
3. Go / Julia (proposed): `:=` declares a variable

Of these, I’m a _bit_ sympathetic to Algol, since mutating a binding is arguably very different from establishing a mathematical equality.

Ok, so I need to randomly pepper my code with colons. Faced with something like that, I like to ask “could the compiler insert them for me?” And yes it can, so why bother me with it. The motivating example is

```julia
x = 0

function f()
    x = 1
    ...
end

```

I claim that you basically NEVER want the assignment to `x` inside the function to modify the global. The asymmetry here is massive. Thousands of functions look like this, and all of them except 1 or 2 rare cases want a new local variable. I absolutely do not want to tell somebody “aha, you forgot the colon, so this assigns a global instead!” It is very, very bad for the simplest, most obvious syntax to do something horrible that you never want to do.

I realize this is partly subjective. I dislike “fussy syntax”, others dislike “magic implicit stuff” more.

---

<div class="post-metadata">

**Author:** ![dlfivefifty](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlfivefifty/32/1959_2.png) [@dlfivefifty](https://discourse.julialang.org/u/dlfivefifty)\
**Post date:** [June 19, 2021, 7:27pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/28 "2021-06-19T19:27:38Z")

</div>

I would add

Mathematica := is a lazy version of = where the value changes when referenced variables do

This is actually a much more concrete difference between = and := and something I’ve found useful, but not something that I see working in Julia.

---

<div class="post-metadata">

**Author:** ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)\
**Post date:** [June 21, 2021, 4:13am UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/29 "2021-06-21T04:13:23Z")

</div>

> [@peteole](#):
>
> Like this one would know exactly when an entirely new variable shall be introduced (and one could also think about fixing a variable’s type at creation, maybe this would avoid some strange errors and enable further optimization).

Actually we can already do this by a small macro:

```julia
macro stable(x)
  if x.head == :(=)
    return quote
      local tmp =$(esc(x.args[2]))
      local $(esc(x.args[1]))::(typeof(tmp)) = tmp
    end
   end
end

```

A small test:

```julia
# type is y is String
function f(x)
  @stable y = "212"
end
# multiple declaration is a syntax error
# ERROR: syntax: multiple type declarations for "y"
function f(x)
  @stable y = "212"
  @stable y = 1
end

```

Edit: There are three limitations about this approach:

1. not work in global scope
2. type conversion is still allowed
3. introduce an additional variable `tmp`, which might make `code_typed` or `code_warntype` hard to read.  
1 is not a huge limitation unless type declaration is supported on global variable. 2 and 3 do require some special language supports.

---

<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:** [June 21, 2021, 4:15am UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/30 "2021-06-21T04:15:24Z")

</div>

Unfortunately it only works in the local scope, not global scope.

---

<div class="post-metadata">

**Author:** ![anon56330260](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@anon56330260](https://discourse.julialang.org/u/anon56330260)\
**Post date:** [June 21, 2021, 4:21am UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/31 "2021-06-21T04:21:56Z")

</div>

Yes. But global variable doesn’t even allow type declaration, it’s quite natural for this macro not to work in global scope (since global variables have no stable types…).

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [June 21, 2021, 10:19am UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/32 "2021-06-21T10:19:41Z")

</div>

This is “just” a missing feature that someone needs to implement. Hard enough that it hasn’t been done yet but not difficult in principle.

---

<div class="post-metadata">

**Author:** ![ParadaCarleton](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/paradacarleton/32/20005_2.png) [@ParadaCarleton](https://discourse.julialang.org/u/ParadaCarleton)\
**Post date:** [June 21, 2021, 4:40pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/33 "2021-06-21T16:40:59Z")

</div>

Seems alright, but not quite as short or elegant as `x := 1`.

---

<div class="post-metadata">

**Author:** ![cngilbreth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cngilbreth/32/31146_2.png) [@cngilbreth](https://discourse.julialang.org/u/cngilbreth)\
**Post date:** [November 27, 2021, 1:46am UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/34 "2021-11-27T01:46:59Z")

</div>

I think it would be very nice to differentiate between variable declaration and updating with different operators as you describe, perhaps swapping ‘=’ with ‘:=’. The updating operator could then be a function with user-defined methods, such as operator= in C++… Any time you have a nontrivial struct which you want to update and don’t want to completely re-allocate, you currently need to use prefix notation (myupdate!(x, …)) instead of infix notation such as x = … or x := … to re-use the allocated memory in x, which is cumbersome.

This is a separate topic, but: if you add to it the ability to overload fused operations, you could express all the linear algebra operations with infix notation, e.g. something like (ignoring for the moment issues with aliased arguments)

function (:=,\*,+)(A :: Matrix, B::Matrix, C::Matrix, D::Matrix)  
# Implement A = B \*C + D efficiently here, using existing storage in A  
end

So this could be done with dense matrices, sparse matrices, tensors, other data structures, etc.

It seems you could just use ‘:=’ as the updating operator without breaking things, rather than redefining ‘=’. (Although I admit I like the other way better.)

Separating declaration from updating would also just make code easier to reason about, in my opinion.

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [November 27, 2021, 3:12pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/35 "2021-11-27T15:12:05Z")

</div>

For arrays there is already `A .= B*C .+ D` doing what you want.

---

<div class="post-metadata">

**Author:** ![cngilbreth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cngilbreth/32/31146_2.png) [@cngilbreth](https://discourse.julialang.org/u/cngilbreth)\
**Post date:** [November 27, 2021, 3:42pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/36 "2021-11-27T15:42:48Z")

</div>

Yes, I’m aware of that. Two comments:

1. In this particular case, will B\*C cause a memory allocation?

2. The more general notation will work with other data structures than simple arrays.

---

<div class="post-metadata">

**Author:** ![cngilbreth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cngilbreth/32/31146_2.png) [@cngilbreth](https://discourse.julialang.org/u/cngilbreth)\
**Post date:** [November 27, 2021, 3:54pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/37 "2021-11-27T15:54:34Z")

</div>

Here is an example illustrating the memory allocation:

```julia

julia> function f()
          A = zeros(10,10)
          B = ones(10,10)
          C = 2 .* ones(10,10)
          D = 3 .* ones(10,10)
          @time A .= B*C .+ D
          return nothing
       end
f (generic function with 1 method)

julia> f()
  0.000005 seconds (1 allocation: 896 bytes)

```

In fact it allocated 896 bytes, whereas I was expecting 8\*10^2 = 800 bytes.

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [November 27, 2021, 3:59pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/38 "2021-11-27T15:59:52Z")

</div>

I recently stumbled upon [this](https://github.com/JuliaLang/julia/blob/b4dafb84fb89e8fe34501a1a51c151b201280360/stdlib/LinearAlgebra/src/matmul.jl#L1115). It looks related, although I don’t know how to use it.

---

<div class="post-metadata">

**Author:** ![roflmaostc](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/roflmaostc/32/30123_2.png) [@roflmaostc](https://discourse.julialang.org/u/roflmaostc)\
**Post date:** [November 27, 2021, 4:11pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/39 "2021-11-27T16:11:03Z")

</div>

Have a look at `mul!` (it overwrites the first argument):

```julia
julia> using LinearAlgebra, BenchmarkTools

julia> @btime $A .= mul!($D, $B, $C)
  793.755 ns (0 allocations: 0 bytes)

```

(maybe better add `D` to `A` first and then `mul!(A, B, C) `)

But I feel that should be discussed further elsewhere since it is not really related to `:=`.

If you want memory efficient functions, there is already the convention with a trailing `!`.  
For example, how would you push a number to a vector with `:=`?  
We have `push!` and `pop!` (and many more) defined for those operations which is much more expressive than `:=`.

---

<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:** [November 27, 2021, 6:17pm UTC](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949/40 "2021-11-27T18:17:11Z")

</div>

> [@roflmaostc](#):
>
> `julia> @btime $A .= mul!($D, $B, $C)`

Did you mean to suggest `mul!(D, B, C, 1, 1)`? `mul!(D, B, C)` doesn’t quite do the same as `D = B * C + D`. Also, this overwrites `D` in-place, which may or may not be desired.

[Previous page](https://discourse.julialang.org/t/why-no-operator-for-initializing-variables/62949.md?page=1)
