typeof(/regExp/) should return "object", not "function"

VERIFIED FIXED

Status

()

Core
JavaScript Engine
P3
normal
VERIFIED FIXED
17 years ago
9 years ago

People

(Reporter: Andreas Franke (gone), Assigned: Brian Crowder)

Tracking

Trunk
Points:
---

Firefox Tracking Flags

(Not tracked)

Details

(URL)

Attachments

(2 attachments, 2 obsolete attachments)

(Reporter)

Description

17 years ago
Found on http://www.oreilly.com/news/petition_1100.html :

> November 13th, 2000   8:29 AM 
> 
>  Here's one I hadn't encountered before...
>
>  Per ECMA 262, typeof should only return "function" if the object is native 
> and implements a .call() method (printed page 47-48; PDF page 58-59). Regular
> expressions are a native object type and do not implement a call method. 
> Therefore, this JavaScript URL:
> 
>  javascript:alert(typeof(/regExp/));< /a>
> 
>  should return "object", not "function". It does return "object" in Explorer
> and Opera, but returns "function" in Navigator (4.7 and 6pr3).
> 
>  Dave Brown

I am submitting this just so that it doesn't get lost. I don't know if it's a
valid bug, but I verified that mozilla mtrunk from 11/26 shows "function".

Comment 1

17 years ago
Andreas, thanks - 





For convenience, here is the ECMA reference:





11.4.3 The typeof Operator



The production UnaryExpression:typeof UnaryExpression is evaluated as follows:

1. Evaluate UnaryExpression.

2. If Type(Result(1)) is not Reference, go to step 4.

3. If GetBase(Result(1)) is null, return "undefined".

4. Call GetValue(Result(1)).

5. Return a string determined by Type(Result(4)) according to the following table



Type                                               Result



Undefined                                         "undefined"

Null                                              "object"

Boolean                                           "boolean"

Number                                            "number"

Object (native and doesn’t implement [[Call]])    "object"

Object (native and implements [[Call]])           "function"

Object (host)                                     Implementation-dependent

Comment 2

17 years ago
I believe the bug is invalid. RegExp objects are "callable" in this sense:


                    js> var re = new RegExp('abc')
                    js>
                    js> re.exec("Learn your abc's")
                    abc


I don't think the ECMA spec is saying they have to have a method named "call" 
in order to be considered of function type; they just have to be "callable".


cc'ing Brendan to make sure this bug is indeed invalid -
phil: re("learn your abc's") shows how a regexp is callable; that's short for a
call to re.exec passing the same arguments.  This is all well-specified in ECMA
Edition 3.  The "Dave" who complained in the oreilly.net petition misstates the
standard, which talks only about a [[Call]] internal method, not any named .call
method.

/be
Status: NEW → RESOLVED
Last Resolved: 17 years ago
Resolution: --- → INVALID
Oops.  ECMA-262 Edition 3 does *not* specify a [[Call]] internal method for
RegExp objects.  Was that an oversight, or intentional?

/be
Status: RESOLVED → REOPENED
Resolution: INVALID → ---
waldemar, pls. advise and reassign to rogerl or mark INVALID.  Thanks,

/be
Assignee: rogerl → waldemar
Status: REOPENED → NEW

Comment 6

17 years ago
It's a judgment call here.  The standard doesn't say anything about an
implementation adding extra internal properties to an object, but I believe that
this is allowed, just as adding extra properties is allowed.  As long as our
implementation has the [[call]] property on RegExp instances, their type should
be "function".  Were the standard interpreted as disallowing defining [[call]]
on RegExp instances, then we'd have to remove [[call]] and change the type to
"object".  That would break many scripts.

I'm going with the first interpretation and marking INVALID.
Status: NEW → RESOLVED
Last Resolved: 17 years ago17 years ago
Resolution: --- → INVALID

Comment 7

17 years ago
Marking Verified - 
Status: RESOLVED → VERIFIED

Comment 8

16 years ago
*** Bug 93589 has been marked as a duplicate of this bug. ***

Comment 9

11 years ago
*** Bug 353448 has been marked as a duplicate of this bug. ***

Comment 10

11 years ago
I believe the resolution of this bug was a mistake.

As Brendan realized in comment #4, ECMA-262 does not define [[Call]] for regexp instances. 

"Extending the standard" in this manner is going against the spirit of the standard and is simply hurting developers and causes confusion. I have never seen /reg/(str) used anywhere and I don't see why it's useful. In a scenario where a function expects either an object or a function reference as argument, Gecko would misbehave here for no good reason.

Other browsers do this properly, including IE, Opera, Safari and Omniweb. I strongly believe this should be changed to conform more fully, since this extension is not just another method or property added to the object, it actually has consequences.

And finally, to quote the standard (not in an exact context, but it demonstrates the spirit of it): "Implementations that add additional capabilities to the set of built-in functions are encouraged to do so by adding new functions".
I think we should match other browsers.  We should return "function" for Function objects, and little else.  Comment 10's final paragraph citing standard verbiage is on target.

/be
BTW, alert should be a function object, although this is outside the scope of ECMA-262.  IE should not make alert an alien "host object" lacking .apply, etc.

/be
(Assignee)

Comment 13

11 years ago
I'm not seeing any other gripes in bugzilla about Bad Things that happened when we made typeof(/re/) == object, so a patch is coming right up.  There is another bug in the database that looks, sounds and smells a lot like this one, though it is clearly a different breed of duck:  bug 268945.  Should this be fixed, also?  Is the "alert" remark an action-item for us, or just an observation of IE wonkiness?
Status: VERIFIED → REOPENED
Resolution: INVALID → ---
(Assignee)

Updated

11 years ago
Status: REOPENED → ASSIGNED
See bug 289933 comment 10.  I found that bug via cvs annotate jsapi.c | less and searching for TypeOfValue and looking for recent changes to-do with the logic governing "function" type.

My alert comment was more about how even though I agree that typeof /a/ should not be function, my statement that typeof should return "function" pretty much only for Function objects should not be taken so narrowly that "host" functions such as alert are not function objects.  That alert is not a function object in IE is a bug in IE, and any DOM level 0 standard should say so.

/be
(Assignee)

Comment 15

11 years ago
Created attachment 239320 [details] [diff] [review]
Removed regexp class from this special case

So this isn't so much a bug (in the sense of an unintended or unexpected behavior in the code) as a matter of interpretation of the spec.  I have not pored over the spec for many moons as have others, no doubt.  We essentially implemented our own interpretation very deliberately, this patch reverses that interpretation in the case of regular expressions (only).  Does this reversal cause problems elsewhere?  Who relies on regexp being functions and not objects?  Hopefully browser people or embedders who care will chime in.  I personally think matching other browsers (if the spec doesn't provide a specific answer) is the Right Thing to Do.
Assignee: waldemar → crowder
Attachment #239320 - Flags: review?(mrbkap)
(Assignee)

Comment 16

11 years ago
(In reply to comment #14)
> See bug 289933 comment 10.  I found that bug via cvs annotate jsapi.c | less
> and searching for TypeOfValue and looking for recent changes to-do with the
> logic governing "function" type.

Bleah.  I suppose it would be easy to debate one way or another over which assumption is wrong.  RegExp are more than functions (since they are, in fact, objects internally) and more than objects (since they have syntactic sugar that makes them behave like functions sometimes).  It seems that the Right Thing to Do is get closer to the behavior supported by other browsers, until the spec is more explicit, and try to offer some viable workable for people who otherwise need to distinguish regexp from other object types.  Perhaps an "isRegexp" function in the RegExp class?

Comment 17

11 years ago
Brian,

The reason typeof currently thinks a regexp instance is a function is because it has what the standard calls a [[Call]] member (not sure what you call it internally in your code). According to previous comments, someone mapped [[Call]] in regexp instances to the .exec method. This is totally non-standard and not useful in any way.

My recommendation is to remove that mapping and you will not need to do anything else (because no [[Call]] will be defined, typeof will realize it should return "object" and not "function", according to the standard).

Distinguishing between objects is already well taken care of by instanceof and .constructor, there's really no need to add a method (see obj instanceof RegExp and obj.constructor==RegExp).
(Assignee)

Comment 18

11 years ago
Actually this fix doesn't concern itself with the [[Call]] member (check out the patch).  We were actually going out of our way to special-case regexp to be reported as typeof == function.  This patch stops doing that.  instanceof is, as you suggest, a much better solution for the other bug, imho.
QA Contact: pschwartau → general
(Assignee)

Updated

11 years ago
Attachment #239320 - Flags: review?(mrbkap) → superreview?(brendan)
Comment on attachment 239320 [details] [diff] [review]
Removed regexp class from this special case

>-                if ((ops == &js_ObjectOps)
>-                    ? (clasp->call
>-                       ? (clasp == &js_RegExpClass || clasp == &js_ScriptClass)
>-                       : clasp == &js_FunctionClass)
>+                if ((ops == &js_ObjectOps) 

Trailing space added on this line.

>+                    ? (clasp->call ? (clasp == &js_ScriptClass)

Nits: don't parenthesize == unnecessary; do keep the ? term on its own line as it was before.

/be
(Assignee)

Comment 20

11 years ago
Created attachment 241749 [details] [diff] [review]
cleanup

per brendan's suggestions
Attachment #239320 - Attachment is obsolete: true
Attachment #241749 - Flags: superreview?(brendan)
Attachment #239320 - Flags: superreview?(brendan)
(Assignee)

Comment 21

11 years ago
Probably still need the code from comment #2 to land, then mark fixed?
Whiteboard: [checkin needed]
(Assignee)

Comment 22

11 years ago
> Probably still need the code from comment #2 to land, then mark fixed?

Sorry wrong window, disregard.
Comment on attachment 241749 [details] [diff] [review]
cleanup

Cool, a one-liner.

r+me (no super-review required or even optional typically in js/src -- occasionally someone requests it, but most often cuz bugzilla makes it hard to ask for second-review from the get-go).

/be
Attachment #241749 - Flags: superreview?(brendan) → review+
(Assignee)

Updated

11 years ago
Blocks: 355044
Flags: blocking1.8.1.1?
mozilla/js/src/jsapi.c 	3.284
Status: ASSIGNED → RESOLVED
Last Resolved: 17 years ago11 years ago
Resolution: --- → FIXED
Whiteboard: [checkin needed]
Maybe it's just me, but this doesn't seem like a fix which should go on a stable branch which promises some level of behavioral compatibility with 1.5.  (See also bug 289933 comment 10.)  I suspect the only way to find out for sure would be to try it and see if anything breaks, which seems shaky to me since I doubt point version nightlies get the testing trunk nightlies get, which still might not even be enough to catch something here.
Yes, this should be trunk only.

/be
No longer blocks: 355044
Flags: blocking1.8.1.1?

Comment 27

11 years ago
modify test to test for typeof regexp == object. This will fail on pre 1.9.0 builds.

Checking in regexparg-1.js;
/cvsroot/mozilla/js/tests/js1_2/function/regexparg-1.js,v  <--  regexparg-1.js
new revision: 1.5; previous revision: 1.4

Comment 28

10 years ago

(In reply to comment #17)
> Brian,
> 
> The reason typeof currently thinks a regexp instance is a function is because
> it has what the standard calls a [[Call]] member (not sure what you call it
> internally in your code). According to previous comments, someone mapped
> [[Call]] in regexp instances to the .exec method. This is totally non-standard
> and not useful in any way.
> 
Then why not remove it?

> My recommendation is to remove that mapping and you will not need to do
> anything else (because no [[Call]] will be defined, typeof will realize it
> should return "object" and not "function", according to the standard).
> 
I agree. It makes no sense. Nobody calls a RegExp with (); that is what exec() is for. 

> Distinguishing between objects is already well taken care of by instanceof and
> .constructor, there's really no need to add a method (see obj instanceof RegExp
> and obj.constructor==RegExp).
> 
Not between frames.

isPrototypeOf has the same problem there, too. Typeof is necessary. 


I'm not sure if this can really be RESOLVED FIXED. The behavior seems wrong to me.

Mozilla/5.0 (Macintosh; U; PPC Mac OS X Mach-O; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7

var r = /foo/;
typeof r; // "function" <-- THIS SEEMS WRONG.
r("foo"); // <-- This should not be possible.
Function.prototype.call.call(x, x, "bar")// <-- error.

Function.prototype.call called on incompatible /bar/
[Break on this error] undefined

Comment 29

10 years ago
Created attachment 285135 [details]
Call RegExp with Function.prototype.call throws TypeError

Testcase showing how RegExp cannot be called using Function.prototype.call. 

========================================================================
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.
========================================================================

Comment 30

10 years ago
Created attachment 285138 [details]
Call RegExp with Function.prototype.call throws TypeError

Better conditional check for window.console vs. alert.
Attachment #285135 - Attachment is obsolete: true
Pay attention! This bug is indeed fixed in the CVS trunk for Mozilla 1.9 / Firefox 3. The patch is not going into a Firefox 2.0.0.x update.

Also, the latest from ECMA TG1 on JS2/ES4:

* typeof f == "function" iff f instanceof Function *for some Function constructor* (i.e., works when f was created in another window from the one loading the script doing the typeof test).

* ES4 is making regexps callable as shorthand for exec, based on the SpiderMonkey extension. This is convenient as shorthand; love it or live with it. But per the first point, typeof /hi/ == "object" in ES4.

* If you want to test whether arbitrary x is callable, write

  if (x is Callable) ...

/be
Status: RESOLVED → VERIFIED
I forgot to mention two more ES4 bits of news:

* Function call and apply will work on any x for which (x is Callable).

* There will be static generic Function.call and Function.apply counterparts to the Function.prototype call and apply, for shorter invocation on non-functions.

/be
You need to log in before you can comment on or make changes to this bug.