These are 2 proposals in 1, because I think (I may be wrong) they work better together. However, they can be split into separate proposals.
Mut "expiration"
This is about limiting the number of times a variable can be assigned, either statically (syntactic and lexical) or dynamically (at runtime). Examples:
//var can only be assigned twice (after declaration) at runtime
const 2 x = 0
//loop runs twice until error is thrown
//`x === 2` before the loop halts
while (true) x += 1
//suppose the previous loop hasn't crashed...
//var can only be assigned at most 2 "places" in the code
synconst 2 y = 0
//this never crashes
//the var is only assigned at 1 "place" multiple times
for (let i = 0; i < 256; i++)
y += 1
//despite never running, it still counts as "syntactic assignment"
if (false) {y = 2}
y = 3 //syntax error
These are specially useful when a variable should be immutable but its value must be computed dynamically once or more times.
-
const 0
is identical toconst
-
synconst 0
is an stricter version ofconst
-
const Infinity
is a syntax error (becauseInfinity
is not an integer) -
synconst Infinity
is identical tolet
-
const -1
andsynconst -1
are undefined behavior (it may be defined later)
Reverse declarations
Suppose we have the following:
//"..." means "do something, but don't declare vars"
//...
{
let a = 0
//...
{
let b = 1
//...
{
let c = 2
//...
}
//...
}
//...
}
//...
This "indentation penalty" discourages the good practice of local variables. What if we could do something like?...
//...
let a = 0
//...
let b = 1
//...
let c = 2
//...
undef c
//...
undef b
//...
undef a
//...
This is equivalent to the delete
operator (and drop
in Rust), except that undef
only works on vars declared via let
& const
. Attempting to undef
a variable declared with var
or a property of globalThis
throws an error (it may be at runtime or "compile"-time)
To discourage abuse of undef
, it should have a longer name, like undeclare
. Another mechanism to enforce maintainability of code (maybe it's the opposite?, I feel this is wrong), would be to have different keywords associated with the kind of declaration: unconst
can only undeclare const
, and unlet
corresponds to let
, mismatching results in an error.
A cool feature of undef
is that it can emulate the mut-expiration feature:
let x = 0
//...
x = 1
//...
//re-declare x as a constant
const x = undef x
//undef is an operator that returns the value before deleting it
x = 1 //error
const y = 0
//...
//this is forbidden, because it would destroy the guarantee that `const` is immutable
let y = undef y //error