Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is `Object.freeze(Object.prototype)` only the hazard for extending `Object.prototype` with Symbols?

Tags:

javascript

So, fundamentally, this question is Not opinion-based. I seriously pursuit this issue objectively without feeling mostly arisen from the predominant opinion - Why is extending native objects a bad practice?

and this quesion is related but unanswered questions:

If Object.prototype is extended with Symbol property, is it possible to break code without specifically designed APIs to access Symbol in JavaScript?

Should the extension of built-in Javascript prototypes through symbols also be avoided?

The first question is already closed as they say it's opinion based, and as you might know in this community once a question is Banned, however we modified it, moderators will never bother to re-open. That is the way how the things work here.

For the second question. For some unknown reason, the question has been taken more seriously and not considered as opinion based although the context is identical.

There are two parts to the "don't modify something you don't own" rule:

  1. You can cause name collisions and you can break their code.

    By touching something you don't own, you may accidentally overwrite something used by some other library. This will break their code in unexpected ways.

  2. You can create tight dependencies and they can break your code.

    By binding your code so tightly to some other object, if they make some significant change (like removing or renaming the class, for example), your code might suddenly break.

Using symbols will avoid #1, but you still run into #2. Tight dependencies between classes like that are generally discouraged. If the other class is ever frozen, your code will still break. The answers on this question still apply, just for slightly different reasons.

Also, I've read opinions(how can we discuss such a thing here without "opinion" base?), they claim

a) Library code Using Symbols exists and they may tweak Symbol API (such as Object.getOwnPropertySymbols())

b) extending object property with Symbol is not different from non-Symbol property fundamentally.

Here, for the major rationale of untouching Object.prototype is due to #1, almost all answers I saw claimed that and we don't have to discuss if there is no Symbol usage.

However, Using symbols will avoid #1 as they say. So most of the traditional wisdom won't apply anymore.

Then, as #2 says,

By binding your code so tightly to some other object, if they make some significant change (like removing or renaming the class, for example), your code might suddenly break.

well, in principle, any fundamental API version upgrade will break any code. The well-known fact is nothing to do with this specific question. #2 did not answer the question.

Only considerable part is Object.freeze(Object.prototype) can be the remaining problem. However, this is essentially the same manner to upgrade the basic API by some other unexpectedly.

As the API users not as API providers, the expected API of Object.prototype is not frozen.

If some other guys touch the basic API and modifies it as frozen, it is he/she who broke the code. They upgraded the basic API without notice.

For instance, in Haskell, there are many language extensions. Probably they solve the collision issue well, and most importantly, they won't "freeze" the basic API because freezing the basic API would brake their eco.

Therefore, I observe that Object.freeze(Object.prototype) is the anti-pattern. It cannot be justified as a matter of course to prevent Object.prototype extension with Symbols.

So here is my question. Although I observe this way, is it safe to say:

In case of that Object.freeze(Object.prototype) is not performed, which is the anti-pattern and detectable, it is safe to perform extending Object.prototype with Symbols?

If you don't think so, please provide a concrete example.

like image 934
sailsky Avatar asked Oct 14 '25 16:10

sailsky


2 Answers

Is it safe? Yes, if you are aware of all the hazards that come with it, and either choose to ignore them, shrug them off, or invest effort to ensure that they don't occur (testing, clear documentation of compatibility requirements), then it is safe. Feel free to do it in your own code where you can guarantee these things.

Is it a good idea? Still no. Don't introduce this in code that other people will (have to) work with.

If some other guys touch the basic API and modifies it as frozen, it is he/she who broke the code. Therefore, I observe that Object.freeze(Object.prototype) is the anti-pattern.

Not quite. If you both did something you shouldn't have done, you're both to blame - even if doing only one of these things gets away with working code. This is exactly what point #2 is about: don't couple your code tightly to global objects that are shared with others.

However, the difference between those things is that freezing the prototype is an established practice to harden an application against prototype pollution attacks and generally works well (except for one bit), whereas extending the prototype with your own methods is widely discouraged as a bad practice (as you already found out).

In Haskell, there are many language extensions. Probably they solve the collision issue well, and most importantly, they won't "freeze" the basic API because freezing the basic API would brake their eco.

Haskell doesn't have any global, shared, mutable object, so the whole problem is a bit different. The only collision issue is between identifiers from "star-imported" modules, including the prelude from the base API. However, this is per module, not global, so it doesn't break composability as you can resolve the same identifier to different functions in separate modules.

Also yes, their base API is frozen and versioned, so they can evolve it without breaking old applications (who can continue using old dependencies and old compilers). This is a luxury that JavaScript doesn't have.

Is it safe to extend Object.prototype with a pipe symbol so that something[pipe](f) does f(something), like something |> f in F# or the previous proposal of pipe-operator?

No, it's not safe, not for arbitrary values of something. Some obvious values where this doesn't work are null and undefined.

However, it doesn't even work for all objects: there are objects that don't have Object.prototype on their prototype chain. One example is Object.create(null) (also done for security purposes), another example are objects from other realms (e.g. iframes). This is also the reason why you shouldn't expect .toString() to work on all objects.

So for your pipe operator, better use a static standalone method, or just use a transpiler to get the syntax you actually want. An Object.prototype method is only a bad approximation.

like image 94
Bergi Avatar answered Oct 17 '25 04:10

Bergi


Extending the Object prototype is a dangerous practice.

You have obviously done some research and found that the community of javascript developers overwhelmingly considers it to be a very bad practice.

If you're working on a personal project all by yourself, and you think the rest of us are all cowards for being unwilling to take the risk, then by all means: go ahead and modify your Object prototype! Nobody can stop you. It's up to you whether you will be guided by our advice. Sometimes the conventional wisdom is wrong. (Spoiler: in this case, the conventional wisdom is right.)

But if you are working in a shared repository, especially in any kind of professional setting, do not modify the Object prototype. Whatever you want to accomplish by this technique, there will be alternative approaches that avoid the dangers of modifying the base prototypes.

The number one job of code is to be understood by other developers (including yourself in the future), not just to work. Even if you manage to make this work, it is counterintuitive, and nobody who comes after you will expect to find this. That makes it unacceptable by definition, because what matters here is reasonable expectations, NOT what the language supports. Any person who fails to recognize that professional software development is a team effort has no place writing software professionally.

You are not going to find a technical limitation to extending the Object prototype. Javascript is a very flexible language -- it will give you plenty of rope with which to hang yourself. That does not mean it's a good idea to place your head in the noose.

like image 35
Tom Avatar answered Oct 17 '25 04:10

Tom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!