Hacker News new | ask | show | jobs
by conaclos 1228 days ago
I could like to have a kind of rust edition for JavaScript.

You could opt in to an edition by adding a JavaScript directive at the start of the file — like the "use strict" directive. e.g.

  ```js
  "use edition2023"
  ```
This could enable to remove obsolete features and improve strictness.

EDIT: I forgot the "use" before "strict".

5 comments

I don't know much about this, but I thought this was a solved problem in the JS ecosystem.

You write Typescript or CoffeeScript or Clojurescript or ES6 or in this case "JS edition2023". You have a preprocessing step that compiles this into code that works on everyone's browser. Your new language has the features and quirks you want, without having to solve the problem of deploying a new runtime to a billion older machines.

A lot of people are still writing raw JS code, including me, because the tooling around this is way more lightweight and straightforward, or because of over things.

But yeah, as a preprocessing step, I'd argue a linter rule would be one of the best way to handle such a quirk if you are using bare JS (or TypeScript, which inherits this quirk, by the way)

What I propose is introducing breaking changes via editions.

For instance, we could freeze class prototypes making impossible to dynamically replace a method or adding a method to it.

This what "use strict" did by forbidding `with` statements for example.

Browsers still have to support the older editions for backwards compatibility, so each new edition increase complexity.
You never break user space.
Only a Sith deals in absolutes. Presumably that is why proposed mechanism requires the user to explicitly opt-in, just like with `"use strict";`.
If you want a version of typeof without this quirk it is trivially easy to write a typeof2023() function with the desired behavior. And it would be fully backwards compatible with existing code and existing browsers.

No need to fork the language for this!

"use strict" was for fixing some fundamental mistakes which couldn't be fixed in a backwards-compatible way.

In JavaScript this is best done using linters to warn against deprecated features.

“Use strict” was necessary because it changed runtime semantics in a non-backwards compatible way. But browser vendors does not like to support multiple incompatible modes, it is much preferrable to introduce improvents in a backwards-compatible manner.

I've thought of something like that before for js. For this precise case, I guess the directive could forbid the use of typeof, or its use on null (and make it a runtime error). And your code ought to not accept values returned by typeof from foreign code, or to be careful with the "object" case.

I don't think it can be a complete solution for making typeof return "null" for null for two reasons.

1) If you call f(typeof v) where f is defined in a module written in a different version, you are screwed. Contrived but within spec and we all know https://xkcd.com/1172/ (if you didn't, now you do).

2) Moreover, old engines will ignore your directive and behave differently (return "object" instead of "null"), so now your code is incorrect depending on what engine runs it.

In the end, it could as well be a linter rule that forces you to test v === null before calling typeof v and I think it would be the best option. If you care about this kind of stuff, you are probably already using a linter. The same kind of tool that complains about "==", which sets the same kind of traps, and you don't need to wait for something wrong to happen during execution, it's already warned statically before even running the code.

(1) Yes this makes interoperability hard. However, `typeof` is generally used to test the type of value. It is unlikely to pass its value to a function

If you use a function declared in a module with a distinct edition, you have to comply to its contract. And its contract certainly state that "null" is not a valid value to pass through.

Moreover, a type checker or linter could error/warn about this.

(2) You are right.

Another solution might be to introduce a new keyword:

  ```js
  use "edition2023"
  ```
Old browser could thus crash. In the same way that they did for ESM.

  In the end, it could as well be a linter rule that forces you to test v === null
  before calling typeof v and I think it would be the best option. If you care
  about this kind of stuff, you are probably already using a linter.
Yes. However, this does not allow performing more advanced optimizations. Bundlers, Transpilerss minifiers, and compilers must handle all this complexity making some optimizations unsafe or even impossible.
That's basically what "use strict" is, isn't it?
I think it is a bit different, because with "use strict" we have already some rules and the typeof null is object there and now is too late to change that. The same for any other feature we don't want to have in a language.

Maybe it was a mistake to introduce "use strict" without any other identifier, we need "use strict" with a version to be able to deprecate things and eventually remove from JS. Then JS engine could read it in the beginning of the file and know which version of js it is. Because in current JS we can only add new features without removing them. I am sure it is very complicated problem since we don't want to break the internet and browsers still have to work with old websites.

Yep. We could then disable more feature and change some historical errors like "use strict" did.