Closed Bug 313637 Opened 19 years ago Closed 16 years ago

RegExp objects do not implement call or apply

Categories

(Core :: JavaScript Engine, enhancement, P4)

enhancement

Tracking

()

RESOLVED WONTFIX

People

(Reporter: erik, Assigned: brendan)

Details

In Spidermonkey one can use a regular expression object like a function:

var re = /f./;
re('foo'); // returnd 'fo'

Also 'typeof re' returns 'function' (all other browsers return 'object'). If this kind of behavior is supposed to be supported 'call' and 'apply' should really work on regexp objects.
typeof returning "function" is just a result of having a [[Call]] property and doesn't mean it is an instance of Function. As far as I can tell we implement ECMA 3 properly here.

What you are asking for is an enhancement to add more Function type properties to RegExp. What is the benefit considering the other browsers don't consider a regular expression instance to be calleable?
Severity: normal → enhancement
OS: Linux → All
Hardware: PC → All
Agreed. Shouldn't we be able to use call and apply from scripts then?

re.call -> undefined
re.apply -> undefined

The problem is with code like this:

if (typeof obj == 'function') {
   obj.call(...);
}
This seems more like a bug against ECMA-262.  It may be useful to prototype some possible fixes here, but really, we (or at least I) need to interact with ECMA TG1 about the lack of a universal apply (call is an optimization) operator.  Such an operator, if done right, should be a combinator with operator new, so that one can construct using an array of arguments.

/be
Assignee: general → brendan
(In reply to comment #2)
> Agreed.

With which comment?

> Shouldn't we be able to use call and apply from scripts then?
> 
> re.call -> undefined
> re.apply -> undefined
> 
> The problem is with code like this:
> 
> if (typeof obj == 'function') {
>    obj.call(...);
> }

ECMA-262 does *not* guarantee that you can do that.

/be
Status: NEW → ASSIGNED
Priority: -- → P4
Target Milestone: --- → mozilla1.9beta
(In reply to comment #2)
 if (obj instanceof Function) {
    obj.call(...);
 }
(In reply to comment #1)
> typeof returning "function" is just a result of having a [[Call]] property and
> doesn't mean it is an instance of Function. As far as I can tell we implement
> ECMA 3 properly here.

Except that ECMA does not specify [[Call]] as a shorthand for exec for RegExp objects.  Except that extensions to the spec are allowed.

typeof is a mess, we'll try to clean it up for Ed. 4.

/be
I'll add a test when this is resolved.
Flags: testcase?
15.3.4.4 Function.prototype.call(thisArg [ , arg1 [ , arg2, ... ] ] ) 
| The call method takes one or more arguments, thisArg and (optionally)
| arg1, arg2 etc, and performs a function call using the [[Call]] property
| of the object. If the object does not have a [[Call]] property,
| a TypeError exception is thrown. The called function is passed
| arg1, arg2, etc. as the arguments.

The spec does not require RegExp instances to have call() method.
However, Function.prototype.call() should accept any object
that has [[Call]] property as |this| value, shouldn't it?

var rx = /x/;
rx.call = Function.prototype.call;
rx.call(null, "x"); // currently, throws an exception
(In reply to comment #8)
> 15.3.4.4 Function.prototype.call(thisArg [ , arg1 [ , arg2, ... ] ] ) 
> | The call method takes one or more arguments, thisArg and (optionally)
> | arg1, arg2 etc, and performs a function call using the [[Call]] property
> | of the object. If the object does not have a [[Call]] property,
> | a TypeError exception is thrown. The called function is passed
> | arg1, arg2, etc. as the arguments.
> 
> The spec does not require RegExp instances to have call() method.

Right, see comment 6 and section 16 of the spec.  Extensions are allowed, but adding [[Call]] to other objects does not imply Function.prototype.apply/call work on those other objects, in the spec.  But I agree this is desirable.

> However, Function.prototype.call() should accept any object
> that has [[Call]] property as |this| value, shouldn't it?
> 
> var rx = /x/;
> rx.call = Function.prototype.call;
> rx.call(null, "x"); // currently, throws an exception

Yeah, this could work.  Even better would be Function.call(rx, "x") in the same way we've made generic static method counterparts to Array and String prototype methods.  Better yet would be an apply operator.  This is the bug for all such [[Call]] goodness to be recorded, fed into ECMA TG1, and fixed.

/be
Just so I don't have to open a new bug about this...

Why does typeof /some regexp/ == "function", but /some regexp/ instanceof Function == false? From a user's perspective, if typeof x == "function", then it should act as though it were an instance of Function. I know Bob cleared up the implementation aspect of this in the second comment, but this is the first object I've discovered across browsers that hasn't acted as such.

(By the way, isn't /rgx/("test") acting the same as /rgx/.exec("test") nonstandard behavior?)
(In reply to comment #10)
> Why does typeof /some regexp/ == "function", but /some regexp/ instanceof
> Function == false?

It's two separate mechanisms.  For typeof == "function" the object merely has to implement [[Call]].  Nothing says that RegExp doesn't implement it (and the spec explicitly allows extensions), except cross-engine compatibility and user expectations.  For instanceof, |O instanceof F| just walks up O's prototype chain and returns true if it finds an object P such that |P === F.prototype|.  For a regular expression, the chain is RegExp.prototype->Object.prototype->null, so |/f/ instanceof Function| returns false.


> From a user's perspective, if typeof x == "function", then
> it should act as though it were an instance of Function.

The spec's type-determination mechanisms may be specified, but that doesn't mean they're specified in the most user-intuitive way.


> (By the way, isn't /rgx/("test") acting the same as /rgx/.exec("test")
> nonstandard behavior?)

Again, it's an extension allowed by section 16 of ECMA-262 3rd ed.  SpiderMonkey and other JS engines have lots of extensions like these, some of which are moderately cross-browser (__proto__ for one) and some of which are not (like the function-call shorthand for exec).
(In reply to comment #11)
> (In reply to comment #10)
> > From a user's perspective, if typeof x == "function", then
> > it should act as though it were an instance of Function.
> 
> The spec's type-determination mechanisms may be specified, but that doesn't
> mean they're specified in the most user-intuitive way.

In this case, though, what Scott wrote: "instance of Function", directly translates to instanceof, not to typeof.

The idea with typeof x == "function" was to enable "can I call x?" tests. Better in hindsight to add a callable(x) predicate, but that ship sailed long ago.

/be
Not sure they should: re.call(thisre, arg1, ... argN) where thisre is another regexp object (and re could be RegExp.prototype) should just be thisre(arg1, ... argN). For apply, the proposed JS2 / ES4 "splat" operator is universal: re.apply(thisre, argsArray) becomes thisre(...argsArray).

This goes for all callable objects; nothing special about regexps. However it's not clear making regexp callable as a short-hand for exec is worth the trouble. We have backed off on typeof /hi/ == "function". RegExp and Function are related only to Object as a supertype.

/be
Target Milestone: mozilla1.9alpha8 → ---
Sentiment even before ES4 fell was negative on callable regexps being standardized. As David-Sarah Hopwood has pointed out, ES3 does not allow regexps to implement [[Call]] -- its definitions for internal methods and native objects is exhaustive. So this is WONTFIX (or WFM, but I'll stick with WONTFIX).

/be
Status: ASSIGNED → RESOLVED
Closed: 16 years ago
Resolution: --- → WONTFIX
You need to log in before you can comment on or make changes to this bug.