allen at wirfs-brock.com
Sat Jun 13 23:16:30 UTC 2015
On Jun 13, 2015, at 1:18 PM, C. Scott Ananian wrote:
> To throw some more paint on the bikeshed:
> The "instanceof RegExp" and "RegExp(...)" parts of the "perfect" implementation of `RegExp.tag` should also be fixed to play nicely with species.
> I think Allen and I would say that you should *not* use the species pattern for instantiating the new regexp (because this is a factory), but you should be doing `new this(...)` to create the result, instead of `RegExp(...)`. (Domenic might disagree, but this is the pattern the ES6 spec is currently consistent with.)
Absolute, `new this(...)` is a pattern that everyone who whats to create inheritable "static" factory methods needs to learn. It's how such a factory says: I need to create an instance of the constructor I was invoked upon.
`species` is very different. It is how an instance method says: I need to create an new instance that is similar to this instance, but lack its specialized behavior.
> The `instanceof RegExp` test might also be reviewed. It might be okay, but perhaps you want to invoke a `toRegExp` method instead, or just look at `source`, so that we used duck typing instead of a fixed inheritance chain. You could even define `String#toRegExp` and have that handle proper escaping. This pattern might not play as nicely with subtyping, though, so perhaps using `this.escape(string)` (returning an instance of `this`) is in fact preferable. Everything other than a string might be passed through `new this(somethingelse).source` which could cast it from a "base RegExp" to a subclass as necessary. You could handle whatever conversions are necessary in the constructor for your subclass.
Originally, ES6 had a @@isRegExp property that was used to brand objects that could be used in context's where RegExp instances were expected. It was used by methods like String.prototype.match/split/search/replace to determine if the "pattern" argument was an "regular expression" rather than a string. Latter @@isRegExp was eliminated and replaced with @@match, @@search, @@split, and @@replace because we realized that the corresponding methods didn't depend upon the full generality of regular expressions, but only upon the more specific behaviors. When we did that, we also decided that we would use the present of @@match a property as the brand to identify regular expression like objects. This is captured in the ES6 spec. by the IsRegExp abstract operation http://people.mozilla.org/~jorendorff/es6-draft.html#sec-isregexp which is used at several places within the ES6 spec.
So, the property ES6 way to do a cross-realm friendly check for RegExp like behavior is to check for the existence of a property whose key is Symbol.match
> If we did want to use the species pattern, the best way (IMO) would be to expose the fundamental alternation/concatenation/etc operators. For example, `RegExp.prototype.concat(x)` would use the species pattern to produce a result, and would also handle escaping `x` if it was a string. The set of instance methods needed is large but not *too* large: `concat`, `alt`, `mult`, and `group` (with options) might be sufficient.
Again, the key difference is whether we are talking about a request to a constructor object or a request to an instance object.
MyArraySubclass.of(1,2,3,4) //I expect to get an instance of MyArraySubclass, not of Array or some other Array-like species
aMyArraySubclassObject.map(from=>f(from)) //I expect to get something with Array behavior but it may not be an instance of MyArraySubclass
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the es-discuss