Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit syntax for reassigning a variable #51223

Open
jariji opened this issue Sep 6, 2023 · 5 comments
Open

Explicit syntax for reassigning a variable #51223

jariji opened this issue Sep 6, 2023 · 5 comments
Labels
breaking This change will break code feature Indicates new feature / enhancement requests parser Language parsing and surface syntax
Milestone

Comments

@jariji
Copy link
Contributor

jariji commented Sep 6, 2023

This is inspired by #51107 and #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
Copy link
Member

LilithHafner commented Sep 6, 2023

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
Copy link
Sponsor Member

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.

@JeffBezanson JeffBezanson added the breaking This change will break code label Sep 6, 2023
@JeffBezanson JeffBezanson added this to the Potential 2.0 milestone Sep 6, 2023
@jariji
Copy link
Contributor Author

jariji commented Sep 6, 2023

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

@nsajko nsajko added parser Language parsing and surface syntax feature Indicates new feature / enhancement requests labels Jun 21, 2024
@JanisErdmanis
Copy link

Regarding the strict mode discussion #54903, I would much prefer that variables be non-reassignable by default. But in contrast to using := for explicit reassignment, I would suggest reusing local to declare that the variable is going to be reassigned within its scope like in the following example:

function f(x)

	local y = 4
	y = 5 # allowed

	z = 5
	z = 6 # errors

	x = 8 # errors
	local x = 7 # allowed
	
	return 
end

The benefit is that the local is already being used when declaring a loop-running variable or a variable set in a try-catch clause.

@StefanKarpinski
Copy link
Sponsor Member

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

I don't think I did. What I've suggested a few times is that we could use := for "declare and initialize" and I think also "declare with the concrete type of the assigned value" which would match Go's meaning. This would make x := expr roughly equivalent to

tmp = expr
x::typeof(tmp) = tmp

Except with tmp gensymmed so it doesn't leak.

I recently also proposed that we could have a strict pragma disallowing implicit variable declaration with =, thereby requiring either global, local or :=.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking This change will break code feature Indicates new feature / enhancement requests parser Language parsing and surface syntax
Projects
None yet
Development

No branches or pull requests

6 participants