archives

« Bugzilla Issues Index

#2979 — B.2.5.1 RegExp.prototype.compile: Consider removing extensible check


B.2.5.1 RegExp.prototype.compile (pattern, flags ), steps 3-4:

IIRC the [[IsExtensible]] check was only introduced to avoid property invariant violations (non-configurable, non-writable property changes its value). Now that RegExp.prototype reflects regular expression flags through accessor properties, the violation is no longer possible, so the extensible check could be removed.


Is RegExp.prototype a RegExp in ES6?

IIRC, the only "Foo.prototype"s which are still "Foo"s in ES6 are Array and Function. But I don't remember if that's the complete list.

The reason I ask is that if it is RegExp, then freezing the RegExp.prototype still needs to prevent it from being a global communications channel. OTOH, if RegExp.prototype is a regular object, then this change is worth considering.


(In reply to comment #1)
> Is RegExp.prototype a RegExp in ES6?

No.

>
> IIRC, the only "Foo.prototype"s which are still "Foo"s in ES6 are Array and
> Function. But I don't remember if that's the complete list.
>

Even better, only Function.prototype is still an instance of its type. From 22.1.3:

> The Array prototype object is itself an ordinary object. It is not an Array
> instance and does not have a length property .


I don't see any harm in keeping this restriction. If somebody freezes a RegExp the presumably are thinking they are making the RegExp value immutable. Why shouldn't the compile method (which is the only way to actually mutate a RegExp) respect that request?


My counter arguments in favour of removing the test:

(1) The same argument can be applied to Date/(Weak)Map/(Weak)Set/ArrayBuffer/... objects. That is, explicitly freezing a Date object should mean its date value will remain unchangeable.

(2) Also, the current check does not actually test for frozen objects, but non-extensible objects. And replacing "frozen" with "non-extensible" makes the argument somewhat unsound:
---
If somebody makes a RegExp "non-extensible" they presumably are thinking they are making the RegExp value immutable.
---

(3) If the [[IsExtensble]] check won't be removed, it should at least happen after side-effects. For example:
---
re = /abc/;
re.compile({toString() {
// RegExp is now observably non-extensible, value will change nonetheless
Object.preventExtensions(re);
return "ghi";
}});
---

(4) And RegExp.prototype.compile should no longer be able to initialize an uninitialized RegExp object:
---
(new class extends RegExp {
constructor() { super("ab") }
}).test("ab"); // Returns true

(new class extends RegExp {
constructor() { Object.preventExtensions(this); super("ab") }
}).test("ab"); // Returns true

(new class extends RegExp {
constructor() { this.compile("ab") }
}).test("ab"); // Returns true

(new class extends RegExp {
constructor() { Object.preventExtensions(this); this.compile("ab") }
}).test("ab"); // Throws TypeError
---


ok, I'm sold.

Fixed in rev27 editor's draft


fixed in rev27 editor's draft

except as noted above or no longer applicable.


fixed in rev27 draft