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

Yes, but a different meaning outside them.

How so?

i = 0
println(i)
i = 1
println(i)
# rest of the unrolled loop goes here
julia> i=0:9; println(i)
0:9

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

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.

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.

:man_shrugging:

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

Thatā€™s exactly why I only use in for iterations :slight_smile:

5 Likes

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

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). Iā€™d just prefer if Julia pushed a little closer to math syntax, since thatā€™s evolved for human-to-human communication.

2 Likes

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.

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? :astonished:

1 Like

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:

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.

2 Likes

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.

3 Likes

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.)

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.

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.

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?

5 Likes

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

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.

1 Like