Make JavaScript real ESNext language

It is very interesting that you think that versioning is bad, but at the same time you do not see that type="module" is exactly the same new version of Js, because it change semantic and run-time behavior !!

I'm with you @redradist that it would be nice to get rid of some of these language oddities, but I do think the points @claudiameadows brought up (about dependencies using older versions, etc) make this difficult to do.

Maybe we need to tone down the idea a bit, and not think of these as "different versions of javascript", there's really no practical way to get rid of some parts of javascript (like user's using undefined†). Rather, if we instead think of it has "different versions of use strict", where future versions of use strict can restrict more and more bad behavior as better alternatives come into existance.

If we, for example, put 'es2021' or 'use strict 2', or whatever at the top of a function body (or module), then it will limit what javascript features we can use, forcing users to use safer alternatives that the language provides (pretty much what a linter already does). I wouldn't want it to modify behavior though, that would make the language much more confusing. For example, instead of modifying typeof's behavior to remove its oddities, and thus having two versions of typeof that behave differently depending on the javascript version you're working in, just ban it within these strict blocks and force users to use something else to get the type of an object. A different typeof operator could be provided without the oddities, that can be used in normal javascript or in these strict modes, though convincing the committee to implement a newer typeof operator would need to come first, before convincing them to make a directive that bans the old one. (I'm not actually in favor of this change - typeof has oddities, but they aren't dangerous oddities, so I'm personally fine with it). With newer versions of use-strict, you could also "ban" type coercion. Here I'm assuming you're talking about how '' + {} === '[object Object]'. (though, again, I'm not really in favor of that either. If someone wants type-safety, they should use typescript - I presume typescript bans this behavior, and if not, a feature request could be made with them. While type-coercion is more dangerous, so are all other type-unsafe things we do in type-unsafe languages).

In general, 'use strict' already does a good job of removing some of the worst foot-guns from the language. I'm not sure if there are currently very many features that can be removed by a use-strict-v2 that would warrant it (for now). I wouldn't be surprised if, as the language progresses, it would eventually obtain enough old baggage that would make a 'use strict 2' a desirable choice.

† as an aside, the reason undefined can't really be versioned, is because it needs to be possible to pass data between strict and unstrict code. So, if you have a 'use strict 2' identity function (i.e. strictIdentityFn = data => { 'use strict 2'; return data }), then you call it from a non-strict script with the object { x: undefined, y: null }, what would you get back? When the object enters the strict function, does it normalize all undefines to nulls, giving you back { x: null, y: null }? That would be unexpected for an identity function. Does it leave them untouched, resulting in user-provided undefined values being allowed in some scenarios? How would we deal with that? What about when a newer strict-mode function calls out to a non-strict-mode function that makes a distinction between undefined and null parameters? These are arguably badly-designed functions, but they should still be useable from a strict-mode function.

@theScottyJam @claudiameadows @septs Based on what I proposed I created "SafeScript" - runtime that allow only subset of "safe" operations at runtime GitHub - redradist/SafeScript: This package intent is to make "safe" JavaScript runtime by checking types at runtime and disallowing most of implicit coercion

Based on work I did there I will add support of operator overloading in JavaScript very easier
Also with this subset rules operator overloading mechanism would be very predictable ;)

1 Like

Thanks @redradist - concrete examples are always helpful :).

It looks like this SafeScript is only dealing with type-coercion, and not touching typeof, undefined, etc - which is fine - it might be easier to hone in on one particular issue and discuss what that might look like in javascript.

I can see the advantage of having type coercion be a runtime check, as a linter can't catch everything. And this kind of feature is something that should be achievable with a module-level directive.

As a side note - I think it might be possible to implement a watered-down version of this concept in vanilla javascript, once the realm proposal gets through. Based on my understanding, it should be possible to modify .toString() and .valueOf() on the prototype of primitives, so that they throw an error when called within your realm, and behave as normal when called from outside (they detect which realm they're being called in, maybe by checking for a globally defined dissallowTypeCoercion symbol). This probably isn't what's wanted here, but I just found this idea interesting - that with an npm package and a realm, users could safely modify globals to disallow certain behaviors within their own codebase. This could even be used to disallow other things such as the implicit eval behavior of setTimeout, etc. If this is really how realms work, I think I have some ideas for future npm packages :).

Yeah, the idea was also to be able integrate it in my own projects, to write safe code
If you will look closer you will see that I allow only safe behavior, I mean that if .toString() returns string and .valueOf() returns value then exception is not thrown, otherwise again an exception will be thrown