JuliaLang / julia

The Julia Programming Language
https://julialang.org/
MIT License
44.95k stars 5.42k forks source link

Explicit syntax for reassigning a variable #51223

Open jariji opened 9 months ago

jariji commented 9 months ago

This is inspired by https://github.com/JuliaLang/julia/issues/51107 and https://github.com/JuliaLang/julia/issues/51183 where there is ambiguity between defining and reassigning. I still dislike that when writing x = inside a function I have to worry about whether x is defined in the enclosing scope.

I like how Fortress distinguished reassignment with := from defining with = so it couldn't happen by accident (and as a one-character "tax" on reassignment). In Scheme/Racket assignment is (set! x 2).

Suppose I want to always be explicit about whether I'm defining a new variable or changing the old one and have a linter disallow ambiguous cases. For defining a new variable there is local x. Could Julia also have a syntax for explicitly reassigning, like x := 2 ?

Example

julia> function f()
           x = 1
           function g()
               x = 2
           end
           g()
           x
       end
f (generic function with 1 method)

julia> f()
2

Update: Pointed out on Discourse, a problem with the proposed syntax is that in Golang the rule is the other way around: := is definition and = is assignment. This could potentially cause confusion for some users. However, only 3% of Julia users use Go (2023 Julia survey) and, sociologically speaking, afaict Go's market doesn't have too much overlap with Julia's. Moreover, SQL and Mathematica, which share far more users with Julia, already use = for different meanings without problem. Definition syntax is so ubiquitous everybody's gonna understand very quickly what the rule is. So I suspect it’s relatively unlikely to cause excessive confusion in practice. Also, having the slightly shorter = syntax be for definition rather than reassignment is a nice mild encouragement in the right direction.

Stefan suggested an opt-in to requiring := for reassignment, or using <- for reassignment.

LilithHafner commented 9 months ago

Seems like something for a macro?

julia> macro update!(x, v)
           esc(:($x; $x = $v))
       end
@set! (macro with 1 method)

julia> @update! foo 17
ERROR: UndefVarError: `foo` not defined
Stacktrace:
 [1] top-level scope
   @ REPL[38]:2

julia> foo = 17

julia> @update! foo 4
4

julia> foo
4
JeffBezanson commented 9 months ago

This is a reasonable proposal but obviously cannot be considered in 1.x (most of the value comes from disallowing some uses of =, not just from adding :=). Several scope-related changes have been proposed for a theoretical 2.0, e.g. #48434.

jariji commented 9 months ago

@LilithHafner I want to change the normal syntax for reassignment. If it's long or unintuitive nobody will adopt it. That's why I like Fortress's := so much -- it looks right and only adds one extra character.

@JeffBezanson

most of the value comes from disallowing some uses of =, not just from adding :=

I believe within the next couple years there will be a good customizable linter, so it will be possible for codebases to disallow reassignments that don't explicitly use :=. That way there is no need for a language-level breaking change in 1.x. Language support for := is enough.