# On using \`=\` vs \`:=\` for assignment

**URL:** <https://discourse.julialang.org/t/on-using-vs-for-assignment/110302>\
**Category:** Offtopic\
**Created:** [February 8, 2024, 3:46pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302 "2024-02-08T15:46:21Z")\
**Posts on this page:** 16\
**Page:** 4

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 28, 2024, 6:13pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/61 "2024-02-28T18:13:29Z")

</div>

Yes, but a different meaning outside them.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 28, 2024, 6:20pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/62 "2024-02-28T18:20:36Z")

</div>

How so?

```julia
i = 0
println(i)
i = 1
println(i)
# rest of the unrolled loop goes here

```

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 28, 2024, 6:23pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/63 "2024-02-28T18:23:41Z")

</div>

```julia
julia> i=0:9; println(i)
0:9

julia> for i=0:9; print(i) end
0123456789

```

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 28, 2024, 6:41pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/64 "2024-02-28T18:41:48Z")

</div>

Hmm, so it is. I happen to prefer `in` as the operator in `for` loops, it’s a bit cleaner.

But this is not a homonym, `=` means assignment in both contexts. A word which is both an adjective and a noun is not a homonym of two words, consider “this is a red book” and “red is my favorite color”, obviously not homonyms here.

This case is similar: a `for` loop means “assign to this variable repeatedly”. It would be a poor for loop which couldn’t execute more than once.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 28, 2024, 7:03pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/65 "2024-02-28T19:03:52Z")

</div>

Extending your argument to my version, `=` is not a homonym because it means equality in all contexts. `let` and `set` merely force that relationship by associating the identifier on the left with the value on the right.

Or I could rebut your argument, but I won’t bother.

🤷‍♂️

At the end of the day what matters is whether your code is nice to write, nice to read, and nice to run, not whether we can find obscure names to describe what it’s doing

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [February 29, 2024, 6:59am UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/66 "2024-02-29T06:59:24Z")

</div>

That’s exactly why I only use `in` for iterations 🙂

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 29, 2024, 8:32am UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/67 "2024-02-29T08:32:31Z")

</div>

Then you just shift the problem around, since `in` becomes the homonym:

```julia
julia> for i in 0:9; print(i) end # iterate 0:9 and repeatedly assign i
0123456789

julia> i in 0:9 # test if i is an element of 0:9
ERROR: UndefVarError: `i` not defined

```

We’re forced to face the fact that homonyms are not actually a problem, as long as they’re reasonably coherent and reasonably obvious.

What is “reasonable” is subjective of course, but it’s not entirely arbitrary; Julia tries to maximize coherence with math syntax and with other popular programming languages, whose syntax has evolved into a pretty decent form as proven by their survival, and with a bias toward aligning with math syntax (see [Edelman talk](https://www.youtube.com/watch?v=qGW0GT1rCvs&t=485s)). I’d just prefer if Julia pushed a _little_ closer to math syntax, since that’s evolved for human-to-human communication.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [February 29, 2024, 8:34am UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/68 "2024-02-29T08:34:40Z")

</div>

Most of the time I’m not using `continue` or `break` so I like to use more restrictive structures like `foreach` or `map` which don’t have this problem.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 29, 2024, 8:53am UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/69 "2024-02-29T08:53:48Z")

</div>

I prefer `foreach` and `map` too, but for terseness and the function barrier (great for iterating over type-heterogenous collections, but be careful of #15276). Do you really use them just to avoid the homonyms? 😲

---

<div class="post-metadata">

**Author:** ![Janis\_Erdmanis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/janis_erdmanis/32/10869_2.png) [@Janis\_Erdmanis](https://discourse.julialang.org/u/Janis_Erdmanis)\
**Post date:** [February 29, 2024, 12:48pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/70 "2024-02-29T12:48:30Z")

</div>

I do actually find the code harder to read as `let`, `for` and `set` are of the same length, but I do find it more consistent with respect to `set a += i` VS nonequivalent way of doing that with `:=`.

An alternative I would like to have have is that every assignment by default would be a `let` binding and if one needs to reassign variable it shall be declared with `var`:

```julia
var s = 0
for i in 1:10
	s += i
end

```

This would solve the issue of accidental variable reasignment which bites me occasionally while leaving the code clean.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 29, 2024, 2:17pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/71 "2024-02-29T14:17:46Z")

</div>

> [@carstenbauer](#):
>
> That’s exactly why I only use `in` for iterations 🙂

Yep, and `∈` | `∉` for inclusion a la `if x ∈ [1,3,5]`. In `for` and `if` blocks, `=` | `in` | `∈` are _synonyms_†, three different ways of saying the same thing. So I take the opportunity to use them distinctly: `=` for declaration/assignment (which makes `=` in assignment expressions a _homonym_, QED), `in` for iteration, `∈` for inclusion in a collection.

It’s purely a style thing, but these are three distinct semantics, and this usage makes that difference stand out on the screen. Having been until recently a professional Lua programmer, where `for x =` and `for x in` are different constructs (numeric and generic), it’s natural for me to write iteration in the latter. I do sometimes use `for x = 1:9` specifically for ranges, for the same reason (Lua habit), but I’ve been changing those to `in` when I find them, Julia and Lua being different languages after all.

† Of course `=` isn’t legal in `if` statements, at least without parentheses, in which case it doesn’t do the same thing as the other two. But none of this is confusing, because none of these are _homonyms_. You can’t say one while thinking it means the other. Someone coming from a language where the predicate in `if` takes parentheses might typo a `=` when they mean `==`, but this is one of the reasons the style guide says not to do that.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 29, 2024, 6:31pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/72 "2024-02-29T18:31:59Z")

</div>

> [@mnemnion](#):
>
> none of this is confusing, because none of these are _homonyms_. You can’t say one while thinking it means the other

Lack of confusion is largely an artifact of our prior familiarity with languages which use these constructs. Imagine being a kid again, learning your first programming language: to the untrained eye, `(a=b)` is nearly indistinguishable from `(a==b)`—I know I messed it up. I think we’re just over-indexing on homonyms here, when there are plenty of ways code is confusing.

However you slice it, the visual “hamming distance” between declarations, assignments, and equality tests isn’t large (unless we stop using the `=` character). However, the `let` and `set` statements make the intent to assign in plain English, which is nice to readers.

Also, I think your fear of bugs in this case is overblown. Most of the time, assignments are on their own line and their return value isn’t of interest; if a comparison is seen on its own line within a basic block, not assigned and not returned so it’ll be elided, we could throw a warning or error (since you _probably_ wanted to assign the variable). I’d also be tempted to make `let` and `set` statements return `nothing` to encourage them to be placed on their own line; assignments embedded in clever one-liners are clever, but not nice to readers. (I’d still allow multiple assignments, e.g. `let a=b=1`, but `let` doesn’t need to have a return value.)

> [@Janis\_Erdmanis](#):
>
> I do find it more consistent with respect to `set a += i` VS nonequivalent way of doing that with `:=`.

Another attractor is that if we wish to add a new keyword sometime later, it can simply be added. For example, maybe someday in the future you want `let dynamic a=1` for dynamically-scoped variables: you could simply decide `dynamic` is a context-dependent keyword now and make it happen.

---

<div class="post-metadata">

**Author:** ![mnemnion](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mnemnion/32/206596_2.png) [@mnemnion](https://discourse.julialang.org/u/mnemnion)\
**Post date:** [February 29, 2024, 7:27pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/73 "2024-02-29T19:27:16Z")

</div>

> [@uniment](#):
>
> Another attractor is that if we wish to add a new keyword sometime later, it can simply be added. For example, maybe someday in the future you want `let dynamic a=1` for dynamically-scoped variables: you could simply decide `dynamic` is a context-dependent keyword now and make it happen.

`something x = y` for all values of `something` other than `global`, `local`, and (top-scope) `const`, is a parse error, so adding `dynamic` or any other keyword there is already possible. `global`/`local`/`const` _could_ be context-dependent rather than lexer keywords. This would involve a token of lookahead, but that’s easy enough. They don’t happen to be, which is also fine, but means that if they became contextual, it wouldn’t invalidate any existing programs, you can’t have `global = 5`, let alone `global global = 5`. But these constructs could certainly be parsed if that was desired. It would be an unusual choice, but I kind of like it.

By contrast, having `let` as a variable modifier would be undecidable in linear time, since `let x = y` begins a `let` block in Julia. You’d need to scan the entire program to count `end` tokens and see if you came up short, for every `let`, which is awful. I understand that you have a solution to this but don’t really care to relitigate that particular disagreement.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 29, 2024, 7:39pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/74 "2024-02-29T19:39:07Z")

</div>

> [@mnemnion](#):
>
> You’d need to scan the entire program to count `end` tokens and see if you came up short, for every `let`, which is awful.

I’m repeating myself, but I’d use `with...end` to serve the role of `let...end`, and repurpose the keyword `let` for single-line declaration/assignment statements.

---

<div class="post-metadata">

**Author:** ![sadish-d](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sadish-d/32/48058_2.png) [@sadish-d](https://discourse.julialang.org/u/sadish-d)\
**Post date:** [October 18, 2024, 2:21pm UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/75 "2024-10-18T14:21:09Z")

</div>

I hope this does not count as reviving a dead thread.

First terminology: There’s variable declaration, assignment, and variable definition, which I define as declaration and assignment (possibly with a single operator).

A non-breaking way to use `:=`, as also mentioned by @mkitti and @mnemnion, is to use it for variable definition and have it throw an error if the variable is already in scope. I think this is a good compromise for those of us (I feel the pain @jar1 ) who are concerned about hard-to-catch bugs introduced when `=` inadvertently reassigns to an existing variable.

With such a `:=`, there is no “spooky action at a distance”, no having to think too hard about variable names when you don’t need to.

Is there any opposition to using `:=` as non-breaking definition operator on grounds OTHER THAN aesthetics?

---

<div class="post-metadata">

**Author:** ![kapple](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kapple/32/218915_2.png) [@kapple](https://discourse.julialang.org/u/kapple)\
**Post date:** [October 21, 2024, 5:35am UTC](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302/76 "2024-10-21T05:35:49Z")

</div>

Just throwing my 2 cents in to say, I like Odin’s use of `:=` as a ternary operator.

```julia
x : Float64 # declare
x : Float64 = 3.14 # declare and initialise
x := 3.14 # infer type from literal
x = 3.14 # reassignment throws if not yet declared

```

On a tangential note, their loop semantics are nice as well.

[Previous page](https://discourse.julialang.org/t/on-using-vs-for-assignment/110302.md?page=3)
