Write-once const bindings

I'd like to propose changing the way const works so that it does not require initialization at the declaration. Instead, it would behave similar to let in Rust, where you can assign a value after declaration only once, and after that, it becomes immutable. So you could do this:

const value;

if (someCondition) {
    value = 1;   // works
} else {
    value = 2;   // works
}

value = 3; // error

I've put together a longer description here:

I'm interested to hear any feedback on this idea.

Thanks!

2 Likes

Hey @nzakas! Nice to see you here.

Being a fan of only using let to signal when the value might keep changing I have found myself wanting this late assignment allowance for const.

  1. Attempting to read an uninitialized const binding before its value is set causes ReferenceError: Cannot access 'name' before initialization.. (Differs from let, which allows you to check the value before initialization.)

Of note: @shu presented last september on "TDZ, what is it good for? (slides). Pitching for a reduction in these types of check at runtime. Instead letting the runtime return undefined and leaving tools to try and detect the error cases. That said the slides do admit that it is odd to allow const to return undefined and then a different value later.

1 Like

Thanks, nice to connect!

I actually did come across that presentation, but I wasn't sure what the result might be. I figured that if my proposal was accepted, then I'd be happy to defer to whatever decision what made regarding the TDZ. I just started by describing what I thought would fit with the current behavior.

I can see the utility of being able to check a const binding to see if it's undefined as a way to determine if it has already been assigned (presumably you would not intentionally create a const binding with a value of undefined).

1 Like

I believe the intention is that this will be "fixed" by do-exprs, like:

const value = do {
  if(someCondition) 1;
  else 2;
};

Tho Pattern Matching will also suffice for this sort of simple use-case:

const value = match(0) {
  if(someCondition): 1;
  default: 2;
};

A touch weirder since you're not using the matched value (and have to supply a dummy value; 0 in this case), but still, it works as an "expression-level if".

1 Like

Yes, I mentioned both of those in my writeup further down. However, both proposals have been open for years with little movement. I think that write-once const, being a much smaller change, could be implemented a lot sooner while we wait for the larger solutions to develop.

"We should solve the problem of X not being implemented by specifying Y, which also needs to be implemented" is a pretty common failure mode for suggestions, tho. ^_^

Unless there's a good reason to believe that X will never be implemented, and that we won't regret Y if X ever does get implemented, and that Y is actually attractive enough of a solution (to an attractive enough subset of X's original problem) that it'll receive impl interest faster than X would, suggesting Y won't meaningfully solve the problem.

I don't believe this suggestion meets these criteria. There are several reasonably easy ways to deal with this problem today (use an IIAFE; use a temp let then assign to the const; use an inline conditional; etc); the suggestion is just to improve the ergonomics a little bit. That doesn't usually get implementors excited.

(That said, if this ends up falling out of Shu's attempts to reduce/eliminate TDZ, then that's just fine with me. I don't have a problem with this, per se.)

Yeah, I get that. In fact, the linked proposal covers a lot of this including all of the viable alternatives and why I still think this is valuable. To quote myself:

  • do Expressions (stage 1) were first proposed in 2018 and hasn't had an update in three years.
  • Pattern Matching (stage 1) was first proposed in 2020 and last presented in 2022.

I guess my theory was that proposals that haven't seen movement in six and four years, respectively, are probably not close to being implemented anytime soon.

Regardless, there are plenty of languages that support both immutable write-once bindings and things like the match expression (Rust, for one), so I'm not sure if these proposals needs to be mutually exclusive.

1 Like