Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

When does indexOf work ?

1 view
Skip to first unread message

John J. Barton

unread,
Apr 7, 2008, 1:10:08 AM4/7/08
to
Based on someone's advice I started doing pick-from-a-list like this:

var i = this.innerScripts.indexOf(script);

But I don't find if innerScripts is an array of jsdIScripts.

This however works:

if (i < 0)
{
for (var j = 0; j < this.innerScripts.length; j++)
{
if (script.tag == this.innerScripts[j].tag)
{
return this.innerScripts[j];
}
}
}

Now I am confused, shouldn't indexOf work?

John.

Boris Zbarsky

unread,
Apr 7, 2008, 1:12:37 AM4/7/08
to
John J. Barton wrote:
> Based on someone's advice I started doing pick-from-a-list like this:
>
> var i = this.innerScripts.indexOf(script);

innerScripts is a JS Array, right? Where did it come from?

What exactly is |script| here?

> Now I am confused, shouldn't indexOf work?

Not if the actual objects don't test ==. I assume they don't, given your .tag test?

-Boris

John J. Barton

unread,
Apr 7, 2008, 11:26:11 AM4/7/08
to
Boris Zbarsky wrote:
> John J. Barton wrote:
>> Based on someone's advice I started doing pick-from-a-list like this:
>>
>> var i = this.innerScripts.indexOf(script);
>
> innerScripts is a JS Array, right? Where did it come from?

sourceFile.innerScripts = [];

>
> What exactly is |script| here?

These come from jsdIStackFrame script field, they are jsdIScript objects.

>
>> Now I am confused, shouldn't indexOf work?
>
> Not if the actual objects don't test ==. I assume they don't, given
> your .tag test?

When (script.tag == this.innerScripts[j].tag) is true,
then (script == this.innerScripts[j]) is true but indexOf < 0 (in FF3pre).

>
> -Boris

Boris Zbarsky

unread,
Apr 7, 2008, 12:09:34 PM4/7/08
to
John J. Barton wrote:
> When (script.tag == this.innerScripts[j].tag) is true,
> then (script == this.innerScripts[j]) is true but indexOf < 0 (in FF3pre).

Is |script === this.innerScripts[j]| in this case? It looks like that's what
indexOf actually uses as a test, now that I look at it.

-Boris

Boris Zbarsky

unread,
Apr 7, 2008, 12:10:35 PM4/7/08
to
John J. Barton wrote:
>> innerScripts is a JS Array, right? Where did it come from?
>
> sourceFile.innerScripts = [];

Note that this doesn't really answer my question; I want to know where the
entries come from too.

-Boris

Mike Shaver

unread,
Apr 7, 2008, 1:13:02 PM4/7/08
to John J. Barton, dev-pl...@lists.mozilla.org

indexOf doesn't know anything about .tag, it only knows strict
equality (===), per
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf#Description
.

If you want to find the entry, rather than the index, then you could
use filter with a predicate checking .tag:

http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter

Mike

John J. Barton

unread,
Apr 7, 2008, 8:05:39 PM4/7/08
to

script === this.innerScripts[j] is false, so the problem is not indexOf.
The question then is why can't we compare two jsdIScript objects with ===?

>>> innerScripts is a JS Array, right? Where did it come from?
>>
>> sourceFile.innerScripts = [];

>Note that this doesn't really answer my question; I want to know where

>the entries come from too.

The entries come from jsdIDebuggerService
onScriptCreated: function(script)
The script objects are passed from a component into a window if that
matters.

John J. Barton

unread,
Apr 7, 2008, 8:09:08 PM4/7/08
to
Mike Shaver wrote:
> On Mon, Apr 7, 2008 at 1:10 AM, John J. Barton
> <johnj...@johnjbarton.com> wrote:
>> Based on someone's advice I started doing pick-from-a-list like this:
>>
>> var i = this.innerScripts.indexOf(script);
>>
>> But I don't find if innerScripts is an array of jsdIScripts.
>>
>> This however works:
>>
>> if (i < 0)
>> {
>> for (var j = 0; j < this.innerScripts.length; j++)
>> {
>> if (script.tag == this.innerScripts[j].tag)
>> {
>> return this.innerScripts[j];
>> }
>> }
>> }
>>
>> Now I am confused, shouldn't indexOf work?
>
> indexOf doesn't know anything about .tag, it only knows strict
> equality (===), per
> http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf#Description
> .

Ok, so why don't jsdIScript objects compare with ===? Or how can I
predict when === and indexOf will work and will not work?

>
> If you want to find the entry, rather than the index, then you could
> use filter with a predicate checking .tag:
>
> http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:filter
>
> Mike

I know there are other ways to solve this problem but I want to
understand why indexOf does not work so I know in future whether to use it.

Boris Zbarsky

unread,
Apr 7, 2008, 9:01:19 PM4/7/08
to
John J. Barton wrote:
> The question then is why can't we compare two jsdIScript objects with ===?

The precise answer to that in your case depends on where they come from. But in
brief, XPConnect will map the same underlying C++ nsISupports to multiple
XPCWrappedNatives if they are being wrapped in different scopes. The equality
hook for the class unwraps and compares the underlying pointers, but that's only
used for the == operator. === does strict JSObject identity (modulo the
inner/outer hack, iirc).

> The entries come from jsdIDebuggerService
> onScriptCreated: function(script)
> The script objects are passed from a component into a window if that
> matters.

Which means they're wrapped in the scope of the component, I would expect. I
assume that your jsdIStackFrame access to get the script you're calling indexOf
on happens somewhere outside that component?

-Boris

John J. Barton

unread,
Apr 7, 2008, 11:11:17 PM4/7/08
to
Boris Zbarsky wrote:
> John J. Barton wrote:
>> The question then is why can't we compare two jsdIScript objects with
>> ===?
>
> The precise answer to that in your case depends on where they come
> from. But in brief, XPConnect will map the same underlying C++
> nsISupports to multiple XPCWrappedNatives if they are being wrapped in
> different scopes. The equality hook for the class unwraps and compares
> the underlying pointers, but that's only used for the == operator. ===
> does strict JSObject identity (modulo the inner/outer hack, iirc).

and, in this case, the JSObjects are actually wrappers around the
objects that I am reasoning about. Hence === fails.

Therefore, I can't count on any normal object comparisons. I won't be
able to figure out what kind of wrapper I have (there is no test for the
wrapper kind and they are created under circumstances I don't control or
even know about).

>
>> The entries come from jsdIDebuggerService
>> onScriptCreated: function(script)
>> The script objects are passed from a component into a window if that
>> matters.
>
> Which means they're wrapped in the scope of the component, I would
> expect. I assume that your jsdIStackFrame access to get the script
> you're calling indexOf on happens somewhere outside that component?

Yep. The array is filled on one code path and the test is made on
another. The XPConnect crossing can be, well, anywhere.

So, I need to approach this differently.

Boris Zbarsky

unread,
Apr 8, 2008, 12:03:45 PM4/8/08
to
John J. Barton wrote:
> and, in this case, the JSObjects are actually wrappers around the
> objects that I am reasoning about.

If you're reasoning about the C++ objects, yes. Clearly, some sort of wrapping
needs to happen to expose a C++ object to JS....

> I won't be able to figure out what kind of wrapper I have

You have an XPCWrappedNative. This is the way that C++ objects are exposed to
JS in Gecko.

> they are created under circumstances I don't control or
> even know about).

XPCWrappedNatives are created when a C++ object needs to be reflected into JS.

That said, your conclusion seems correct. You can't rely on === for JS
reflections of C++ objects unless all your code runs in a single scope.

-Boris

John J. Barton

unread,
Apr 8, 2008, 12:21:58 PM4/8/08
to
Boris Zbarsky wrote:
> John J. Barton wrote:
>> and, in this case, the JSObjects are actually wrappers around the
>> objects that I am reasoning about.
>
> If you're reasoning about the C++ objects, yes. Clearly, some sort of
> wrapping needs to happen to expose a C++ object to JS....
>
>> I won't be able to figure out what kind of wrapper I have
>
> You have an XPCWrappedNative. This is the way that C++ objects are
> exposed to JS in Gecko.

Sure about the first bit? I'm not after pondering
http://developer.mozilla.org/en/docs/XPConnect_wrappers
In addition to XPCWrappedNative there are other wrappers and wrapper
wrappers and soon the room was filling the wrappers. Or at least that's
how it comes across to me.

Boris Zbarsky

unread,
Apr 8, 2008, 12:23:11 PM4/8/08
to
John J. Barton wrote:
>> You have an XPCWrappedNative. This is the way that C++ objects are
>> exposed to JS in Gecko.
>
> Sure about the first bit?

Yes.

> I'm not after pondering http://developer.mozilla.org/en/docs/XPConnect_wrappers
> In addition to XPCWrappedNative there are other wrappers and wrapper
> wrappers

Most of those have to do with either directly interacting with other scopes or
directly interacting with content DOMs. Doesn't sound like you're doing any of
that.

-Boris

0 new messages