Make JavaScript real ESNext language

JavaScript language has been evolving in good direction over the time, but there is still some drawbacks that do not allow write a "safe" code by default:

  1. "implicit" type coercion - this feature was added in "ancient" time mostly for designers and by impact of C language where some type could be evaluated in if statement
    But nowadays almost all understands that this feature is harmful and makes code less safe due to unpredictable behavior during "implicit" type coercion ...
    Of course there are precise rules that describes conversion, but this rules is not consistent each other, I mean that if you know one rule, then you could not guess how it works with another type, because another type have different rule for coercion ... it make harder to reason about the code ... (
    Also this feature make harder to implement the Operator Overloading Propousal I mentioned it in
  2. Fix type of null as null
  3. Use only null value as "empty" type or "nothing" type, undefined should be internal language value that user cannot set or read, if property is not available then should be raised exception (This is similar to Python where if symbol absent then would be raised error and there is exist only one "empty" type None)
  4. All scripts is run as module such that this is undefined
  5. All objects that was created with specific keyword should be shown in typeof operator:
class SomeClass {
console.log(`SomeClass is ${typeof SomeClass}`); // SomeClass is class

It is consistent, because if we introcude a new keyword, then programmer would expect it as type:

// Future ...
interface ISome {
console.log(`ISome is ${typeof ISome}`); // ISome is interface

My suggestion is to remove inconsistencies and harmful features from language (those was described above) with adding esnext type

It would be possible to do in browser:

<script type="es2021">
  // ...

and in node environment with:

    "type": "es2021",

type="es2021" could be the same thing that Rust use with edition, if over time developers realized that some features are harmful than it could be safely removed without breaking backward compatibility
Fortunately there is not so many Language Core issue nowadays from my opinion ;)
If all this changes will be fixed, then I think I would call JavaScript - SafeScript ;)

Also I want to mention that I want to discuss this here and all these suggestions was impacted by my work with other languages such as C++, Python, Java, C#, Rust and so on

1 Like

Why not es[year]?

es2020, es2021, esnext and etc

1 Like

@septs Agree with you, fixed to es[year] ;)

I have questions and concerns:

  1. You'd inevitably have to encode past versions into the spec, and without the impetus to move on, you'd risk fragmenting web tech (again). And deprecating old versions is hard. (Currently, where I work, our build system is stuck on Node 8 because some dependencies break if we upgrade to Node 10 and upgrading them has proved torturous. Now imagine web apps that themselves are comprised of similar infrastructure. Oh, and by the way, 1/4 of your dependencies haven't been updated in the last 5 years, their maintainers have abandoned them, and they're using an old version pragma.) If you remove that needed pressure to update while also increasing effort whenever one does desire to update, you will frequently struggle to get rid of old, outdated versions - it was an impressive feat in of itself to successfully remove just arguments.caller, a single property that seriously slowed down function calls. And for non-strict code, standards people still couldn't successfully remove func.caller, func.arguments, or func.callee.
  2. On the same token, how would one enable such a feature per-script (necessary for global script-driven web apps/sites) or even per-function (necessary for bundled web apps)?
1 Like

@claudiameadows I do not think that will change old version of language in case if you will add something like editions ...

You each time will update JavaScript version with specific edition like es2015 and all new features will be applied to this edition, but then if you will decide to make new edition like es2021, then you will update each time es2021 edition with each standard

I consider it like this:
"non-strict" -> "strict" (not actually edition) -> "module" (ES6, ES7 ...) -> "esnext/es2021" (...)

Issue with update to new version, all will work as expected because old scripts will work in old mode "non-strict" -> "strict"
If user will set type to "es2021" then will be applied new edition of the language, but only to your code, not libraries (packages)

Also I think bad code in JavaScript deserve to be broken ... not because I like this code or not, but because this bad code can cause issues with human life, safety, issue can have high cost !! ;)

All person that work with this language should feel this responsibility ...

I think this could be solved with new directive prologues ("pragmas"), but IIRC TC39 is uneasy about introducing a lot of new ones for exactly the reasons you mention.

That is the job of linters, type checkers, and specialized code practices. And in general, secure and maximally error-tolerant design requires things that run into the limits of even type checkers - after a point, you'd get better bang for your buck validating your application design in TLA+ and then implementing it in JS or TS with maybe some autogenerated tests.

And trust me when I say this: after a point, language hardly matters in that domain. It's all about discipline and rigor. (Also, this is why things like stream processors, file system drivers, databases, and operating systems are so hard to get right, yet so critical, and why Rust and Go are being so seriously considered in these circles.)

@claudiameadows I do not think this is a job of linter if some language constructs f**k up ... Because otherwise linter become a new language version ...

If we will rely on linter then every one could say: "Which version of ES do you use and what linter ?" ... it fragiles the ecosystem and relay on fact that someone should use some linter ... It is good for ads, but in real world application it is bad ...

To convince you I will tell some story of mine ...
I have a lots of experience in low level code writing like C++, Rust
For a long time C++ do not check life-time and every time when some body propose to track the life-time, everyone scrim: "No, it could be good in some situation to no track life-time ... it time consuming ..." and so one, not wanting to do something in this area ...
But then came Rust and shows that it possible and now there is exists Life-time propousal by Herbert Sutter that suggest to track life-time of object in obvious cases and even more

This example shows that people usually do not see more than one step forward and do not want to think in this area little-bit, mostly decision of the persons is described by its experience and they sceptically thik about experiance of others ...
Most of the time people argue about 1% of useful cases vs 99% of bad cases to leave feature

The summary is the following, of course linter could check every bad feature of language, but at some case linter become like a language without which code would not work

Lets not save feature that is useful in 1% cases and impact safity and realibility, but remove it and in such way make code even better

Also I would like to add some words that Douglas Crockford said

Also he mentioned that it took a lot of time to convince people that "go to" is bad idea ... but as for me "implicit" type coercion is even worst that "go to" )

Also I think that undefined can be useful if it will show complete absence of property of value ...
For example when user will set property to undefined:

obj.q = undefined;

for (let key in obj) {
    console.log(`key is ${key}`); // No q key is printed

This property should not be shown in for-in loop and it should be deleted completely, meaning that user really do not need this property and in such way it would be equivalent delete obj.q;
Or maybe it could be done more explicit and we should not allow to use setting undefined like this:

obj.q = undefined; // Syntax error, undefined is internal value, you cannot set it, use instead delete obj.q
delete obj.q; // Proper behaviour

for (let key in obj) {
    console.log(`key is ${key}`); // No q key is printed

Also user should not be able to create object literal with undefined:

let obj = {
  k: undefined, // Syntax error, use null instead for property without value

It will make behavior of undefined consistent and predictable and also eliminate users to use undefined instead of null

obj.q = null;

for (let key in obj) {
    console.log(`key is ${key}`); // q key is printed with value null

@claudiameadows @septs What do you think about all above statements that I did ?

freeze edition, i think not a good idea.

@septs But why ? What is your arguments ? As for me it is only way in which we can fix basic issues of language

if target not supported, it is denial of service. (unless everyone understand this DESIGN USAGE)

if there is feature detect api, i think it will be better.

@septs Can you explain what do you mean that it would be denial of service and why ?

your expected es2021, target browser unimplemented.

but this problem should ask WHATWG and W3C workgroup.

@septs This issue could be solved by server that will check browser version that ask page and return page with proper script ... I do not see any issue with this solution )


@redradist In any case, with the core versioning idea, please read up on the history of Firefox's application/javascript;version=... and on why it was eventually abandoned. (There were many reasons, multiple of which were cited here.)

This set of lessons learned was one of the biggest reasons why the Web abandoned explicit versioning entirely.

1 Like