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

Should isHostMethod be added to the FAQ?

29 views
Skip to first unread message

RobG

unread,
Jun 29, 2009, 10:36:13 PM6/29/09
to
<FAQENTRY>

There has been frequent mention of the legendary "isHostMethod"
function in this group over the last 18 months or so in conjunction
with statements that "boolean type conversion is out" for testing host
method availability. While that may be so, trying to find the elusive
method in all the noise is pretty difficult.

I discovered this version posted by Thomas in February 2008[1]:

function isHostMethod(o, m)
{
var t = typeof o[m];
return (/^(function|object)$/.test(t) && o[m])
|| t == "unknown";
}

It is also difficult to find posts on why it is preferred to the more
common type converting tests. Perhaps it's time to add an FAQ entry
about testing host methods that briefly states why isHostMethod should
be used and includes the code (with appropriate attribution) so it can
be referenced and found more easily.

</FAQENTRY>

1. <URL: http://groups.google.com/group/comp.lang.javascript/msg/eceaf3fa529973ec
>


--
Rob

David Mark

unread,
Jun 29, 2009, 10:55:34 PM6/29/09
to
On Jun 29, 10:36 pm, RobG <robg...@gmail.com> wrote:
> <FAQENTRY>
>
> There has been frequent mention of the legendary "isHostMethod"
> function in this group over the last 18 months or so in conjunction
> with statements that "boolean type conversion is out" for testing host
> method availability.  While that may be so, trying to find the elusive
> method in all the noise is pretty difficult.
>
> I discovered this version posted by Thomas in February 2008[1]:
>
>   function isHostMethod(o, m)
>   {
>     var t = typeof o[m];
>     return (/^(function|object)$/.test(t) && o[m])
>            || t == "unknown";
>   }
>

That specific version from My Library, but to be fair, it's just
Thomas' old isMethodType with a few tweaks. Probably the most
important addition (and the simplest) is the detection of the
legendary "unknown" types, which MS has subjected Web developers to
since IE4. Most important thing to document is that is expected to be
passed (e.g. a host object and the name of a property known to be
implemented as a method.)

> It is also difficult to find posts on why it is preferred to the more
> common type converting tests.

There were a lot of discussions around when the CWR repository was
created (winter of 2007-2008 I think.)

> Perhaps it's time to add an FAQ entry
> about testing host methods that briefly states why isHostMethod should
> be used and includes the code (with appropriate attribution) so it can
> be referenced and found more easily.
>
> </FAQENTRY>
>
> 1. <URL:http://groups.google.com/group/comp.lang.javascript/msg/eceaf3fa529973ec

I think it is a great idea. There are a couple of other variations as
well (e.g. isHostObjectProperty.) Peter's article(s) on the subject
summarize the pros and cons and offers different versions of each,
IIRC.

RobG

unread,
Jun 30, 2009, 12:47:45 AM6/30/09
to
On Jun 30, 12:55 pm, David Mark <dmark.cins...@gmail.com> wrote:
> On Jun 29, 10:36 pm, RobG <robg...@gmail.com> wrote:
>
> > <FAQ***RY>

>
> > There has been frequent mention of the legendary "isHostMethod"
> > function in this group over the last 18 months or so in conjunction
> > with statements that "boolean type conversion is out" for testing host
> > method availability.  While that may be so, trying to find the elusive
> > method in all the noise is pretty difficult.
[..]

> > Perhaps it's time to add an FAQ entry
> > about testing host methods that briefly states why isHostMethod should
> > be used and includes the code (with appropriate attribution) so it can
> > be referenced and found more easily.
>
> > </FAQ***RY>

>
> > 1. <URL:http://groups.google.com/group/comp.lang.javascript/msg/eceaf3fa529973ec
>
> I think it is a great idea.  There are a couple of other variations as
> well (e.g. isHostObjectProperty.)  Peter's article(s) on the subject
> summarize the pros and cons and offers different versions of each,
> IIRC.

I guess you mean this one:

Feature Detection: State of the Art Browser Scripting
<URL: http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
>

If on one volunteers in the meantime, I'll make a start and post it
later. Been kinda busy lately and have been spending most of my spare
time sailing.


--
Rob

Garrett Smith

unread,
Jun 30, 2009, 3:05:04 AM6/30/09
to
RobG wrote:
> On Jun 30, 12:55 pm, David Mark <dmark.cins...@gmail.com> wrote:
>> On Jun 29, 10:36 pm, RobG <robg...@gmail.com> wrote:
>>

[...]

>
> I guess you mean this one:
>
> Feature Detection: State of the Art Browser Scripting
> <URL: http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
>
> If on one volunteers in the meantime, I'll make a start and post it

No, don't.

> later. Been kinda busy lately and have been spending most of my spare
> time sailing.

Yes, do that :-)

Garrett
--
comp.lang.javascript FAQ: http://jibbering.com/faq/

wilq

unread,
Jun 30, 2009, 4:07:48 AM6/30/09
to


I was curious why the hell use regexp, so I made a test for that and
It is how I suppose to work... RegExp is slower than comparing to
simple strings. (Tested on firefox 3.06, Opera 9.63, Chrome 2.0.172,
IE 6).

Comparing to string has one main advantage: in case of first true
test, any next is not fired. So worst case is when we have a string
"object" in this case. But even for 3 diffrent strings for worst case
regexp solution is still 2 times slower (or even more - depending on
browser engine). This regexp solution might be speedup a little by
storing regexp function, and not create it every time isHostMethod
function is called, but surprisingly it does not change alot in
function execution time.

So I asking... where is this "ineficient" that Thomas speak about?

Thomas 'PointedEars' Lahn

unread,
Jun 30, 2009, 5:59:39 AM6/30/09
to
RobG wrote:
> <FAQENTRY>
>
> There has been frequent mention of the legendary "isHostMethod"
> function in this group over the last 18 months or so in conjunction
> with statements that "boolean type conversion is out" for testing host
> method availability. While that may be so, trying to find the elusive
> method in all the noise is pretty difficult.
>
> I discovered this version posted by Thomas in February 2008[1]:

My JSdoc™ says:

* @author
* (C) 2003-2009 Thomas Lahn &lt;obje...@PointedEars.de&gt;

I presume Google Groups still has the first version, either here or in
de.comp.lang.javascript.

> function isHostMethod(o, m)
> {
> var t = typeof o[m];
> return (/^(function|object)$/.test(t) && o[m])
> || t == "unknown";
> }

The version in <news:4A48837E...@PointedEars.de> is more efficient and
less error-prone.

The local version of object.js (0.1.5a.2009062116) currently features
jsx.object.isMethod() which allows to pass an object reference plus an
arbitrary number of string arguments. This allows e.g. isMethod(Array,
"prototype", "slice", "call") and avoids repeated calls of isMethod().
However, it also precludes flags from being used as third, fourth aso.
argument which could help make this method more flexible (in particular, I'm
thinking about evaluation of a first string argument as in previous versions
which would avoid explicit `typeof ... != "undefined"' of the first argument
before call.) Although that could be accomodated with properties of the
Function object itself, or properties of jsx.object as well, I have not
decided on this yet. Suggestions?

Since the `typeof' operation has to be done in any case, I'm not sure if a
special method for host methods is really needed; currently I am only using
(jsx.object.)isMethod() for testing all methods. What do you think?

> It is also difficult to find posts on why it is preferred to the more
> common type converting tests.

Host objects tend to throw exceptions on type conversion when they don't on
`typeof', in particular host methods for which `typeof' results in "unknown".

In addition, host objects tend to "lie" about their features on type
conversion; they tend not to with type detection. For example, IIRC for a
time `document.all' type-converted to `true' in Gecko's Quirks Mode
(evidently that is no longer the case as of Firefox 3.0.11/Gecko 1.9.0.11);
by contrast, `typeof document.all' evaluated to "undefined" (and still
does). That was a reasonable approach, given that document.all.foo worked
(and works; for whatever twisted reasoning), but document.all.tags("div")
didn't (and doesn't, throws a TypeError).


PointedEars

Richard Cornford

unread,
Jun 30, 2009, 6:20:52 AM6/30/09
to
On Jun 30, 9:07 am, wilq wrote:
<snip>

> I was curious why the hell use regexp, so I made a test
> for that and It is how I suppose to work... RegExp is
> slower than comparing to simple strings. (Tested on
> firefox 3.06, Opera 9.63, Chrome 2.0.172, IE 6).
<snip>

The question of relative performance of regular expressions compared
with string comparison has come up before and on one occasion testing
revealed a significant factor that almost never seems to be considered
when people test the relative speeds' of things. I turned out that the
posted test-case (you have failed to post your test-case) showed
opposite results for different people running it. Having verified
that the browser/JS environments were equivalent in each case interest
widened to the hardware environment, where it turned out that the CPU
appeared to be a significant factor, with P-III processors producing
the results where string comparison was fastest and P-IV processors
producing the results where regular expressions were fastest.

The (unproven) theory was that the P-IV's longer pipeline was
favouring the regular expressions and hindering the simpler comparison
operations (with the overheads of flushing the pipeline after the
comparison). Intel has been shortening their CPU pipelines since the P-
IV, which would suggest the advantages might swing back to simple
comparison (though the machine I am sitting at right now has a P-IV
CPU).

Richard.

Jorge

unread,
Jun 30, 2009, 7:08:11 AM6/30/09
to
On Jun 30, 12:20 pm, Richard Cornford <Rich...@litotes.demon.co.uk>
wrote:
> (...)

> The (unproven) theory was that the P-IV's longer pipeline was
> favouring the regular expressions and hindering the simpler comparison
> operations (with the overheads of flushing the pipeline after the
> comparison). Intel has been shortening their CPU pipelines since the P-
> IV, which would suggest the advantages might swing back to simple
> comparison (though the machine I am sitting at right now has a P-IV
> CPU).

See "The MegaHertz Myth" :
http://www.youtube.com/watch?v=PKF9GOE2q38

--
Jorge.

Richard Cornford

unread,
Jun 30, 2009, 7:36:02 AM6/30/09
to
On Jun 30, 12:08 pm, Jorge wrote:
<snip>

> See "The MegaHertz Myth" :
> http://www.youtube.com/watch?v=PKF9GOE2q38

I would appreciate it if you would not keep posting links to non-
functional/usable web pages. It severs no purpose and wastes my time
following them.

Richard.

Jorge

unread,
Jun 30, 2009, 10:43:07 AM6/30/09
to

Ohhh, that's truly pitiable. Please, excuse me.

--
Jorge.

RobG

unread,
Jun 30, 2009, 7:44:35 PM6/30/09
to
On Jun 30, 5:05 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> RobG wrote:
> > On Jun 30, 12:55 pm, David Mark <dmark.cins...@gmail.com> wrote:
> >> On Jun 29, 10:36 pm, RobG <robg...@gmail.com> wrote:
>
> > I guess you mean this one:
>
> > Feature Detection: State of the Art Browser Scripting
> > <URL:http://peter.michaux.ca/articles/feature-detection-state-of-the-art-b...

>
> > If on one volunteers in the meantime, I'll make a start and post it
>
> No, don't.

I suppose that means you wish to write the article yourself, however
given the recent thread[1] where the in operator and isHostMethod were
discussed as alternatives, I'd request that you post it here first for
discussion. That thread is a very messy way for anyone to discover
the issues associated with detection of host features, I'm not sure
they'd come to a suitable conclusion from reading it.

What the FAQ item needs to convey is that it is practically impossible
to write a general "isObjectPropertyCallable" function to detect if a
method is callable or not (leaving out the use of try..catch as a
general solution). What is reasonable is to use typeof for native
methods, and to use isHostMethod for host methods that should be
callable and available if the UA supports certain W3C DOM
specifications. The isHostMethod as discussed in clj is not intended
to be used as a general tool to determine if any random object or
property name is callable.


1. <URL:
http://groups.google.com/group/comp.lang.javascript/browse_frm/thread/1cf03766658a8850/c66df69280fcdaf6?lnk=gst&q=%22is+host+method%22#c66df69280fcdaf6
>


--
Rob

Message has been deleted

wilq

unread,
Jul 1, 2009, 3:59:57 AM7/1/09
to
On Jun 30, 12:20 pm, Richard Cornford <Rich...@litotes.demon.co.uk>
wrote:

I dont have access to mine profiling function so I create own one
from
scratches. Its not great because I do this in hurry, if you have time
to test it - please do. If you have idea on what might interferee
with
test cases - i'm open to hear :) Cheers:
// ************** CUT HERE *********************

<html>
<body>
<script type="text/javascript">

(function(){
var times=[];
function addTime(){
times.push((new Date()).getTime());
}

var someTemp;
var iterationCount=500000;
var a="function";
var b="object";

var regExp=/^function|object$/;

function reg(){
for (var i=0;i<iterationCount;i++)
{
someTemp = regExp.test(a);
someTemp = regExp.test(b);
}}

function str(){
for (var i=0;i<iterationCount;i++)
{
someTemp = (a==="function"||a==="object");
someTemp = (b==="function"||b==="object");
}}

// UNCOMMENT THIS LINE TO profile IN FIREBUG
// console.profile("regExp vs string comp");

addTime();
reg();
addTime();
str();
addTime();

// UNCOMMENT THIS LINE TO profile IN FIREBUG
// console.profileEnd();

document.write("Time for regexp: "+(times[1]-times[0])+"<br>");
document.write("Time for string comparsion: "+(times[2]-times[1]));
})();

</script>
</body>
</html>

Thomas 'PointedEars' Lahn

unread,
Jul 1, 2009, 11:08:54 AM7/1/09
to
wilq wrote:
> I dont have access to mine profiling function so I create own one
> from scratches. Its not great because I do this in hurry, if you have
> time to test it - please do. If you have idea on what might interferee
> with test cases - i'm open to hear :) Cheers:
> [...]

> (function(){
> var times=[];
> function addTime(){
> times.push((new Date()).getTime());

Why, +new Date() suffices.

> }
>
> var someTemp;
> var iterationCount=500000;

Several script engines might consider a script with that many iterations as
blocking, depending on accumulated runtime.

> var a="function";
> var b="object";
>
> var regExp=/^function|object$/;

As written in e-mail, this will match either "function" at the start of
input, or "object" at the end of input (which I imagine to be slow), and
so is not equivalent to `either "function" or "object"'. You'll need

var regExp=/^(function|object)$/;

but, again, that does not consider leading or trailing whitespace.

> function reg(){
> for (var i=0;i<iterationCount;i++)
> {
> someTemp = regExp.test(a);
> someTemp = regExp.test(b);

Cheater! :) Here both tests will be performed always (worst case), but that
is not necessary with /^\s*unknown\s*/i and /^\s*(object|function)\s*/i as
in `is(Host)Method'. Hence my reversing the order of tests since; shortcut
evaluation of boolean expressions will do the rest.

> }}
>
> function str(){
> for (var i=0;i<iterationCount;i++)
> {
> someTemp = (a==="function"||a==="object");

Cheater! :) With your input, the second operand will never be evaluated,
and type conversion does not take place (best case).

> someTemp = (b==="function"||b==="object");

With this approach, type conversion does not take place but might be
necessary with a `typeof' result when a host object is the operand. And
with your input, both operands will always be evaluated here (worst case).

> }}

When you have set up a test of roughly equivalent approaches we can talk
about the shortcomings of simple string comparison as compared to RegExp
matching. In particular when host objects and unknown input is involved.


PointedEars

wilq

unread,
Jul 1, 2009, 1:32:11 PM7/1/09
to
On Jul 1, 5:08 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> wilq wrote:
> > I dont have access to mine profiling function so I create own one
> > from scratches. Its not great because I do this in hurry, if you have
> > time to test it - please do. If you have idea on what might interferee
> > with test cases - i'm open to hear :) Cheers:
> > [...]
> > (function(){
> > var times=[];
> > function addTime(){
> >   times.push((new Date()).getTime());
>
> Why, +new Date() suffices.

If we use it every time when measuring - it is counted inside
measurement time for both operation (regexp and string)... so what
diffrence?

>
> > }
>
> > var someTemp;
> > var iterationCount=500000;
>
> Several script engines might consider a script with that many iterations as
> blocking, depending on accumulated runtime.
>

Yes of course - because of this is an argument that you can change.

> > var a="function";
> > var b="object";
>
> > var regExp=/^function|object$/;
>
> As written in e-mail, this will match either "function" at the start of
> input, or "object" at the end of input (which I imagine to be slow), and
> so is not equivalent to `either "function" or "object"'.  You'll need
>
>   var regExp=/^(function|object)$/;
>
> but, again, that does not consider leading or trailing whitespace.


You can add those bracers to mine profiling function. As you probably
notice this does not change alot.

>
> > function reg(){
> > for (var i=0;i<iterationCount;i++)
> >     {
> >            someTemp = regExp.test(a);
> >            someTemp = regExp.test(b);
>
> Cheater! :)  Here both tests will be performed always (worst case), but that
> is not necessary with /^\s*unknown\s*/i and /^\s*(object|function)\s*/i as
> in `is(Host)Method'.  Hence my reversing the order of tests since; shortcut
> evaluation of boolean expressions will do the rest.
>

Cheater ? I dont think so - I compare here cases that will occur
mostly - "function" and "object". But I do the same for string
solution so there is no cheat. In fact its very fair comparsion in
mine opinion. I open to see a best + worst case as you said that is in
string comparsion.

> >    }}
>
> > function str(){
> > for (var i=0;i<iterationCount;i++)
> >     {
> >            someTemp = (a==="function"||a==="object");
>
> Cheater! :)  With your input, the second operand will never be evaluated,
> and type conversion does not take place (best case).
>

Yes - this is a idea of this test. I propose this test as a answer to
post from some time ago that You were involved in:

Correct me if I'm wrong, you changed:

basically you changed there

(t=='function' || t=='object')

to:

/^(function|object)$/.test(t)


So here I also did the test. And in post before I explained why this
string comparsion would be better - exacly that if a first boolean
structure will be true, second wont be computed at all. You can try
diffrent cases (both worst, both good) with a="object", b="object" and
a="function", b="function" to see that this is still faster than
regexp...


> >            someTemp = (b==="function"||b==="object");
>
> With this approach, type conversion does not take place but might be
> necessary with a `typeof' result when a host object is the operand.  And
> with your input, both operands will always be evaluated here (worst case).
>

If this is really so big diffrence for you ? Then please consider this
for the code that I gave:

var a=typeof (function(){});
var b=typeof ({someObject:0});


> >    }}
>
> When you have set up a test of roughly equivalent approaches we can talk
> about the shortcomings of simple string comparison as compared to RegExp
> matching.  In particular when host objects and unknown input is involved.
>
> PointedEars

Basically you pointed out some elements in code, but generally that
has nothing to do with really results of test. Also you did not
provide anything that would show that this approach is completly
wrong. Please then provide code that proves what you saying is true :)
I really like seeing things working than only talking. Then I can
judge your solution :)

dhtml

unread,
Jul 1, 2009, 2:10:43 PM7/1/09
to

No, it is not a matter of wanting to write it myself.

Function isHostMethod is not a frequently asked question.

Arguments about isHostMethod function don't seem to be likely to
contribute suitable or appropriate material for the FAQ. It may very
lead to pedandtry, quibbling or even irrational zealotry and flames.

The code in that misnamed method pretends to imply that the property
is a method. I can't recommend that.

I am not incapable of writing, and do like help with the FAQ, but I am
busy with various things, including recent threads here (dynamic
loading), other things that are related to programming, and yet other
things in my life that are unrelated. Not sailboats, but good stuff
nonetheless.

kangax

unread,
Jul 1, 2009, 4:57:05 PM7/1/09
to
Thomas 'PointedEars' Lahn wrote:
> wilq wrote:
[...]

>> var a="function";
>> var b="object";
>>
>> var regExp=/^function|object$/;
>
> As written in e-mail, this will match either "function" at the start of
> input, or "object" at the end of input (which I imagine to be slow), and
> so is not equivalent to `either "function" or "object"'. You'll need
>
> var regExp=/^(function|object)$/;
>
> but, again, that does not consider leading or trailing whitespace.

Which clients produce leading and/or trailing white spaces around
"function" and/or "object" for typeof?

[...]

--
kangax

Thomas 'PointedEars' Lahn

unread,
Jul 1, 2009, 5:08:41 PM7/1/09
to

Those in unknown/not sufficiently tested runtime environments. After all,
`typeof' is specified to be implementation-dependent with host objects, and
it is impossible to test all host objects -- past, present, and future. If
you want to wait for the script to fail/break in favor of supposed greater
runtime efficiency instead, that is your decision.


PointedEars

kangax

unread,
Jul 1, 2009, 5:15:04 PM7/1/09
to
Thomas 'PointedEars' Lahn wrote:
> RobG wrote:
>> <FAQENTRY>
>>
>> There has been frequent mention of the legendary "isHostMethod"
>> function in this group over the last 18 months or so in conjunction
>> with statements that "boolean type conversion is out" for testing host
>> method availability. While that may be so, trying to find the elusive
>> method in all the noise is pretty difficult.
>>
>> I discovered this version posted by Thomas in February 2008[1]:
>
> My JSdoc™ says:
>
> * @author
> * (C) 2003-2009 Thomas Lahn &lt;obje...@PointedEars.de&gt;
>
> I presume Google Groups still has the first version, either here or in
> de.comp.lang.javascript.
>
>> function isHostMethod(o, m)
>> {
>> var t = typeof o[m];
>> return (/^(function|object)$/.test(t) && o[m])
>> || t == "unknown";
>> }
>
> The version in <news:4A48837E...@PointedEars.de> is more efficient and
> less error-prone.
>
> The local version of object.js (0.1.5a.2009062116) currently features
> jsx.object.isMethod() which allows to pass an object reference plus an
> arbitrary number of string arguments. This allows e.g. isMethod(Array,
> "prototype", "slice", "call") and avoids repeated calls of isMethod().

This sounds useful. Another common need is to test multiple methods on
the same base object, so these two (i.e. your n-level `isMethod` and
`areMethods`) might cover most of the use cases:

boolean isMethod(base, prop1[, prop2[, ...]])
boolean areMethods(base, methodName[, methodName2[, ...]])

// e.g.

isMethod(document, 'body', 'appendChild');
areMethods(document.body, 'appendChild', 'removeChild');

// or maybe both can be combined:

areMethods(document, 'body', ['appendChild', 'removeChild']);

// compare to something like:

if (document &&
document.body &&
isMethod(document.body, 'appendChild') &&
isMethod(document.body, 'removeChild')) { ... }


[...]

--
kangax

kangax

unread,
Jul 1, 2009, 5:23:19 PM7/1/09
to
Thomas 'PointedEars' Lahn wrote:
> kangax wrote:
>> Thomas 'PointedEars' Lahn wrote:
>>> wilq wrote:
>>>> var a="function";
>>>> var b="object";
>>>>
>>>> var regExp=/^function|object$/;
>>> As written in e-mail, this will match either "function" at the start of
>>> input, or "object" at the end of input (which I imagine to be slow), and
>>> so is not equivalent to `either "function" or "object"'. You'll need
>>>
>>> var regExp=/^(function|object)$/;
>>>
>>> but, again, that does not consider leading or trailing whitespace.
>> Which clients produce leading and/or trailing white spaces around
>> "function" and/or "object" for typeof?
>
> Those in unknown/not sufficiently tested runtime environments. After all,

Unless such environments are known to exist, there's a little reason to
construct regex matching " function " but not, say, "__function__",
"host-function", "function-e3a642b119ff" aso.

Therefore my question about particular clients.

[...]

--
kangax

Thomas 'PointedEars' Lahn

unread,
Jul 1, 2009, 6:55:40 PM7/1/09
to
kangax wrote:
> Thomas 'PointedEars' Lahn wrote:
>> The local version of object.js (0.1.5a.2009062116) currently features
>> jsx.object.isMethod() which allows to pass an object reference plus an
>> arbitrary number of string arguments. This allows e.g. isMethod(Array,
>> "prototype", "slice", "call") and avoids repeated calls of isMethod().
>
> This sounds useful. Another common need is to test multiple methods on
> the same base object, so these two (i.e. your n-level `isMethod` and
> `areMethods`) might cover most of the use cases:
>
> [...]

> areMethods(document, 'body', ['appendChild', 'removeChild']);

Conceptionally, I like this approach best. Not much overloading and very
flexible. However, an Array object reference (which requires a reliable
Array test¹) should only be allowed as last argument to avoid expensive
backtracking; or do you have an idea for that as well?

¹ Regarding the cross-frame issue: what about a property referring
to the current Array object to be set and reset before/after call
as needed?

> // compare to something like:
>
> if (document &&
> document.body &&
> isMethod(document.body, 'appendChild') &&
> isMethod(document.body, 'removeChild')) { ... }

`if (foo)' (here: foo === document) is not very reliable in any case,
though: Implicit type conversion on a host object (which may throw any
exception) using a property that may not even exist (which may throw a
TypeError). Therefore, I suggested allowing for the evaluation of primitive
strings that match /Identifier/ or property accessor for the first argument,
per flag so that methods of String objects could still be tested. What do
you think about that?


PointedEars

RobG

unread,
Jul 1, 2009, 8:10:30 PM7/1/09
to
On Jul 2, 4:10 am, dhtml <dhtmlkitc...@gmail.com> wrote:
> RobG wrote:
> > On Jun 30, 5:05 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> >> RobG wrote:
> >>> On Jun 30, 12:55 pm, David Mark <dmark.cins...@gmail.com> wrote:
> >>>> On Jun 29, 10:36 pm, RobG <robg...@gmail.com> wrote:
> >>> I guess you mean this one:
> >>> Feature Detection: State of the Art Browser Scripting
> >>> <URL:http://peter.michaux.ca/articles/feature-detection-state-of-the-art-b...
> >>> If on one volunteers in the meantime, I'll make a start and post it
> >> No, don't.
>
> > I suppose that means you wish to write the article yourself,
[...]

> > What the FAQ item needs to convey is that it is practically impossible
> > to write a general "isObjectPropertyCallable" function to detect if a
> > method is callable or not (leaving out the use of try..catch as a
> > general solution). What is reasonable is to use typeof for native
> > methods, and to use isHostMethod for host methods that should be
> > callable and available if the UA supports certain W3C DOM
> > specifications. The isHostMethod as discussed in clj is not intended
> > to be used as a general tool to determine if any random object or
> > property name is callable.
>
>
> No, it is not a matter of wanting to write it myself.
>
> Function isHostMethod is not a frequently asked question.

A search in GG for "isHostMethod" returns over 230 responses, the
first in February 2008. I think that qualifies at least as a frequent
topic. I don't think an FAQ is necessarily based on actual questions
being asked, but rather frequent answers that are, or are expected to
be, given. When was the last time someone asked "Why are my rollovers
so slow?".

No one has posted to this thread to say there is no need for the item,
it represents a step forward in feature detection of host methods and
the topic has come up a number of times recently. That is sufficient
to prompt consideration for inclusion in the FAQ - so that it can be
referenced and provide a definitive statement about the topic.


> Arguments about isHostMethod function don't seem to be likely to
> contribute suitable or appropriate material for the FAQ. It may very
> lead to pedandtry, quibbling or even irrational zealotry and flames.

It takes a draft FAQ item for that? ;-)

The only minor quibble I see here is over whether a regular expression
should be used or not - that is a relatively trivial matter related to
performance, not the purpose or overall design. I know you have a
personal opinion that the in operator should be used, but that is a
minority view.


> The code in that misnamed method pretends to imply that the property
> is a method. I can't recommend that.

That is your opinion, and while you may be the FAQ maintainer, that
does not make you sole arbiter of what it should or should not
contain. The purpose and limitations of the function have been
expressed (and summarised previously in this thread), they should be
part of the entry.


> I am not incapable of writing, and do like help with the FAQ, but I am
> busy with various things, including recent threads here (dynamic
> loading), other things that are related to programming, and yet other
> things in my life that are unrelated. Not sailboats, but good stuff
> nonetheless.


There is no need for you to participate in the discussion, there are
half a dozen regulars who have already done so since the topic was
first raised. It only requires someone to post a draft, discussion to
occur, and suitable agreement be reached. It is then up to the FAQ
maintainer to put it in the FAQ.


--
Rob

kangax

unread,
Jul 1, 2009, 10:58:57 PM7/1/09
to
Thomas 'PointedEars' Lahn wrote:
> kangax wrote:
>> Thomas 'PointedEars' Lahn wrote:
>>> The local version of object.js (0.1.5a.2009062116) currently features
>>> jsx.object.isMethod() which allows to pass an object reference plus an
>>> arbitrary number of string arguments. This allows e.g. isMethod(Array,
>>> "prototype", "slice", "call") and avoids repeated calls of isMethod().
>> This sounds useful. Another common need is to test multiple methods on
>> the same base object, so these two (i.e. your n-level `isMethod` and
>> `areMethods`) might cover most of the use cases:
>>
>> [...]
>> areMethods(document, 'body', ['appendChild', 'removeChild']);
>
> Conceptionally, I like this approach best. Not much overloading and very
> flexible. However, an Array object reference (which requires a reliable
> Array test¹) should only be allowed as last argument to avoid expensive
> backtracking; or do you have an idea for that as well?

Yes, an array as last argument is what I had in mind. Allowing it as any
argument seems impractical and unnecessarily expensive (i.e.
backtracking cost which you mentioned).

>
> ¹ Regarding the cross-frame issue: what about a property referring
> to the current Array object to be set and reset before/after call
> as needed?

I suppose you're talking about so-called Miller device (i.e. comparing
value of [[Class]] to "Array"). From what I remember (per Richard's
observations), it was *cross-window issue*, not cross-frame one.

In any case, I'm not sure I understand what you mean by resetting
property and "current Array object". Would you please clarify?

>
>> // compare to something like:
>>
>> if (document &&
>> document.body &&
>> isMethod(document.body, 'appendChild') &&
>> isMethod(document.body, 'removeChild')) { ... }
>
> `if (foo)' (here: foo === document) is not very reliable in any case,
> though: Implicit type conversion on a host object (which may throw any
> exception) using a property that may not even exist (which may throw a

I assumed `document` would be tested for existence before performing
that test. Or if it wasn't, it should always be possible to "start" from
the global object:

// considering `this` refers to Global Object here:
isMethod(this, 'window', 'document', 'body', 'appendChild');

This actually gave me an idea for alternative `isMethod` signature:

isMethod('window.document.body.appendChild');

would split string by ".", then sequentially test properties starting
from the global object. Not sure how this would work with multiple
methods though (i.e. `areMethods`).

As far as type converting host objects (not methods!), didn't we just
have a conversation about it where you said that it should be safe to do so?

<cite>
Yes, but seriously, if an object reference provided by the
implementation of a standardized API does not type-convert to `true' ...
well, I don't care about implementations *this* borken unless I have to.
While, as you probably know, I am a strong promoter of
feature-testing, to care for every possible quirk or bug would mean that
no quirk will ever cease to exist and no bug will ever get fixed, and we
would be writing workarounds for borken implementations forever. That
is not the kind of world I want to live in. Do you?
</cite>

<http://groups.google.com/group/comp.lang.javascript/msg/4df3cf9b5a7bd60f>

Or am I missing something?


> TypeError). Therefore, I suggested allowing for the evaluation of primitive
> strings that match /Identifier/ or property accessor for the first argument,
> per flag so that methods of String objects could still be tested. What do
> you think about that?

What do you mean by "flag" and "per flag"?

--
kangax

Peter Michaux

unread,
Jul 2, 2009, 1:04:58 AM7/2/09
to
On Jun 29, 9:47 pm, RobG <robg...@gmail.com> wrote:

> > I think it is a great idea.  There are a couple of other variations as
> > well (e.g. isHostObjectProperty.)  Peter's article(s) on the subject
> > summarize the pros and cons and offers different versions of each,
> > IIRC.
>
> I guess you mean this one:
>
> Feature Detection: State of the Art Browser Scripting

> <URL:http://peter.michaux.ca/articles/feature-detection-state-of-the-art-b...

I don't know how easy it would be to summarize the isHostMethod,
isHostCollection, and isHostObject functions down to a reasonably
sized FAQ entry. It is worth a try if there is consensus about which
functions to include.

It is not trivially clear cut which of the three functions to use at
any particular time. Some host properties fall into all three
categories. For example, document.all is a collection, function and
object.

These three functions depend on non-standardized behavior of the
typeof operator. The typeof operator is being used as some sort of
magic try-catch but the ECMAScript standard doesn't say anything about
that behavior. From my reading of the standard if obj.prop blows up in
some browser than so could typeof(obj.prop). It just so happens that
the implementations don't blow up when using the typeof version.

It has been so long since I really thought about this topic. I
remember that there was one function that could replace all three
isHost* functions at increased risk of false positives but with no
known false positives in existence. I still wonder if the three
isHost* functions are overly paranoid and the riskier one function is
sufficient.

Peter

Garrett Smith

unread,
Jul 2, 2009, 2:13:57 AM7/2/09
to
Peter Michaux wrote:
> On Jun 29, 9:47 pm, RobG <robg...@gmail.com> wrote:
>

[-about isHost* methods-]

>
> These three functions depend on non-standardized behavior of the
> typeof operator. The typeof operator is being used as some sort of
> magic try-catch but the ECMAScript standard doesn't say anything about
> that behavior. From my reading of the standard if obj.prop blows up in
> some browser than so could typeof(obj.prop). It just so happens that
> the implementations don't blow up when using the typeof version.
>

In what way does |typeof| seems magic? If the answer to that has not
been explained clearly, it can be, and doing so would be worthwhile.

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 4:38:56 AM7/2/09
to
kangax wrote:
> Thomas 'PointedEars' Lahn wrote:
>> kangax wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> The local version of object.js (0.1.5a.2009062116) currently features
>>>> jsx.object.isMethod() which allows to pass an object reference plus an
>>>> arbitrary number of string arguments. This allows e.g. isMethod(Array,
>>>> "prototype", "slice", "call") and avoids repeated calls of isMethod().
>>> This sounds useful. Another common need is to test multiple methods on
>>> the same base object, so these two (i.e. your n-level `isMethod` and
>>> `areMethods`) might cover most of the use cases:
>>>
>>> [...]
>>> areMethods(document, 'body', ['appendChild', 'removeChild']);
>> Conceptionally, I like this approach best. Not much overloading and very
>> flexible. However, an Array object reference (which requires a reliable
>> Array test¹) should only be allowed as last argument to avoid expensive
>> backtracking; or do you have an idea for that as well?
>
> Yes, an array as last argument is what I had in mind. Allowing it as any
> argument seems impractical and unnecessarily expensive (i.e.
> backtracking cost which you mentioned).

ACK. Implemented and tested OK last night so:

for (var i = 1; i < len; i++)
{
var
p = arguments[i],
p_is_Array = (i === len - 1 && jsx.object.isArray(p)),
origP = p;

for (var j = (p_is_Array && origP.length || 1); j--;)
{
if (p_is_Array) p = origP[j];

t = typeof o[p];

// ...
}
}

Did I miss something?

>> ¹ Regarding the cross-frame issue: what about a property referring
>> to the current Array object to be set and reset before/after call
>> as needed?
>
> I suppose you're talking about so-called Miller device (i.e. comparing
> value of [[Class]] to "Array").

Yes, I don't like that for its many assumptions.

> From what I remember (per Richard's observations), it was
> *cross-window issue*, not cross-frame one.

But I thought the problem were different global objects, each with its own
Array property.

> In any case, I'm not sure I understand what you mean by resetting
> property and "current Array object". Would you please clarify?

/**
* Reference to the object used for {@link Array} detection;
* modify at runtime if you access this script from
* a different frame.
*/
jsx.Array = typeof Array != "undefined" ? Array : null;

/**
* NOTE: This method has previously been provided by
* {@link types.js}; optimizations in code reuse moved it here.
*
* @author
* (C) 2003, 2009 Thomas Lahn &lt;obje...@PointedEars.de&gt;
* @partof http://pointedears.de/scripts/object.js
* @requires jsx#object.isInstanceOf
* @param a : Object
* Expression to be determined an array.
* @return
* <code>true</code> if <code>a</code> is an object
* derived from Array, <code>false</code> otherwise.
* Returns also <code>false</code> if the language
* version does not support Array objects (JavaScript
* before 1.1).
*/
var isArray = jsx.object.isArray = function(a) {
return jsx.object.isInstanceOf(a, jsx.Array);
};

>>> // compare to something like:
>>>
>>> if (document &&
>>> document.body &&
>>> isMethod(document.body, 'appendChild') &&
>>> isMethod(document.body, 'removeChild')) { ... }
>> `if (foo)' (here: foo === document) is not very reliable in any case,
>> though: Implicit type conversion on a host object (which may throw any
>> exception) using a property that may not even exist (which may throw a
>
> I assumed `document` would be tested for existence before performing
> that test.

That is exactly what I want to avoid.

> Or if it wasn't, it should always be possible to "start" from
> the global object:
>
> // considering `this` refers to Global Object here:
> isMethod(this, 'window', 'document', 'body', 'appendChild');

Yes, I am using

jsx.object.isMethod(jsx.global, 'window', 'document', 'body', 'appendChild');

But a method to be tested is not necessarily anchored at the global object.

> This actually gave me an idea for alternative `isMethod` signature:
>
> isMethod('window.document.body.appendChild');
>
> would split string by ".", then sequentially test properties starting
> from the global object. Not sure how this would work with multiple
> methods though (i.e. `areMethods`).

I had considered and rejected this approach already because it would
preclude property names with dots in them from being considered.

> As far as type converting host objects (not methods!), didn't we just
> have a conversation about it where you said that it should be safe to do so?
>

> [...]

Yes, I was talking about return values of standardized methods there.

>> TypeError). Therefore, I suggested allowing for the evaluation of primitive
>> strings that match /Identifier/ or property accessor for the first argument,
>> per flag so that methods of String objects could still be tested. What do
>> you think about that?
>
> What do you mean by "flag" and "per flag"?

/**
* ...
*
* @param statements
* Value to be evaluated as a <i>StatementList</i>.
* Called if a <code>Function</code> object reference, converted
* to string if not a string, and used as-is otherwise.
* For compatibility, the <code>undefined</code> value
* is evaluated like the empty string.
* @param errorHandlers
* Value to be evaluated as a <i>StatementList</i> in case of an
* exception. Called if a <code>Function</code> object reference,
* converted to string if not a string, and used as-is otherwise.
* For compatibility, the <code>undefined</code> value
* is evaluated like the empty string.
* @return
* The result of <code>statements</code>, or the result
* of <code>errorHandlers</code> if an error occurred.
* @author
* Copyright (c) 2008
* Thomas 'PointedEars' Lahn &lt;j...@PointedEars.de&gt;
* Distributed under the GNU GPL v3 and later.
* @partof JSX:object.js
*/
var tryThis = jsx.tryThis = function(statements, errorHandlers) {
/**
* @param s Value to be stringified
* @param sIdent Identifier of the value to be stringified
* @return string Stringified version of <code>s</code>
*/
function stringify(s, sIdent)
{
if (typeof s == "function")
{
s = sIdent || "(" + s + ")()";
}
else if (typeof s == "undefined")
{
s = "";
}

return s;
}

var sStatements = stringify(statements, "statements();");
var sErrorHandlers = stringify(errorHandlers, "errorHandlers(e);");

var code = 'try {\n ' + sStatements + '\n}\n'
+ 'catch (e) {\n ' + sErrorHandlers + '\n}';

return eval(code);
};

/* ... */

var isMethod = jsx.object.isMethod = jsx.object.areMethods = function(o, p) {
var len = arguments.length;
if (len < 1) return false;

var
rxUnknown = /^\s*unknown\s*$/i,
rxMethod = /^\s*(function|object)\s*$/i,
t = typeof o;

/* ... */

/*
* Refined support for strings; evaluating them always would
* preclude String objects from being tested for methods.
* Try to warn if a primitive string value is passed and the
* required flag is not set (default).
*/
if (t === "string")
{
if (arguments.callee.evalStrings)
{
/*
* Only consider strings that could be property accessors (incl. E4X)
* TODO: Unicode identifiers
*/
if (/^\s*\w+(\s*\.\.?\s*\w+|\[[^]]+\])*\s*$/.test(o))
{
o = jsx.tryThis(o);
}
else
{
jsx.dmsg(
"jsx.object.isMethod: string does not look like"
+ " a property access; using it as-is",
"warn");
}
}
else
{
jsx.dmsg(
"jsx.object.isMethod: Evaluation of strings requires"
+ " .evalStrings == true",
"warn");
}
}

/* ... */
};

/**
* Set this flag to <code>true</code> to allow evaluation
* of primitive strings as first argument. Allows for
* isMethod("foo", "bar") without testing the type of `foo' first.
* The default is <code>false</code>.
*/
isMethod.evalStrings = false;


PointedEars

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 5:31:20 AM7/2/09
to
Peter Michaux wrote:
> On Jun 29, 9:47 pm, RobG <robg...@gmail.com> wrote:
>> [...]

>> Feature Detection: State of the Art Browser Scripting
>> <URL:http://peter.michaux.ca/articles/feature-detection-state-of-the-art-b...
>
> [isHostMethod, isHostCollection, and isHostObject functions]

> These three functions depend on non-standardized behavior of the
> typeof operator. The typeof operator is being used as some sort of
> magic try-catch but the ECMAScript standard doesn't say anything about
> that behavior. From my reading of the standard if obj.prop blows up in
> some browser than so could typeof(obj.prop). It just so happens that
> the implementations don't blow up when using the typeof version.

But not merely by chance.

,-[ECMAScript Language Specification, Edition 3 Final]
|
| 11.2.1 Property Accessors 11.4.3 The typeof Operator
|
| [...]
| The production The production
|
| MemberExpression : UnaryExpression :
| MemberExpression typeof UnaryExpression
| [ Expression ]
|
| is evaluated as follows: is evaluated as follows:
|
| 1. Evaluate MemberExpression. 1. Evaluate UnaryExpression.
| 2. If Type(Result(1)) is not
| Reference, go to step 4.

| 3. If GetBase(Result(1)) is null,
| return "undefined".
| 2. Call GetValue(Result(1)). 4. Call GetValue(Result(1)).
| 3. Evaluate Expression.
| 4. Call GetValue(Result(3)).
| 5. Call ToObject(Result(2)).
| 6. Call ToString(Result(4)).
| 7. Return a value of type 5. Return a string determined
| Reference whose base object by Type(Result(4)) according
| is Result(5) and whose to the following table:
| property name is Result(6).
| Type Result
| --------------------------------
| Undefined "undefined"
| Null "object"
| Boolean "boolean"
| Number "number"
| String "string"
|
| Object (native "object"
| and doesn’t
| implement
| [[Call]])
|
| Object (native "function"
| and implements
| [[Call]])
|
| Object (host) Implementation-
| dependent


PointedEars

Peter Michaux

unread,
Jul 2, 2009, 9:07:59 AM7/2/09
to
On Jul 2, 2:31 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> Peter Michaux wrote:
> > On Jun 29, 9:47 pm, RobG <robg...@gmail.com> wrote:
> >> [...]
> >> Feature Detection: State of the Art Browser Scripting
> >> <URL:http://peter.michaux.ca/articles/feature-detection-state-of-the-art-b...
>
> > [isHostMethod, isHostCollection, and isHostObject functions]
> > These three functions depend on non-standardized behavior of the
> > typeof operator. The typeof operator is being used as some sort of
> > magic try-catch but the ECMAScript standard doesn't say anything about
> > that behavior. From my reading of the standard if obj.prop blows up in
> > some browser than so could typeof(obj.prop).  It just so happens that
> > the implementations don't blow up when using the typeof version.
>
> But not merely by chance.

[Snip sections 11.2.1 and 11.4.3 of the ECMAScript standard quoted in
an awkward-to-reply-to, two-column format.]

Look more into the evaluation of step 4 of the typeof operator. It is

4. Call GetValue(Result(1))

GetValue depends on the behavior specified in section 8.7.1 which
contains

4. Call the [[Get]] method of Result(2), ...

where Result(2) is the host object being tested for a property.

Then look at section 8.6.2 just before 8.6.2.1 which discusses the
requirements on [[Get]] (and other internal properties) for host
objects.

Host objects may implement these methods in any manner unless
specified otherwise.

Since it is not specified otherwise, [[Get]] for a host object could
throw an error.

There is no way to know what step 4 of a typeof evaluation will do and
there is no provision in the specification of typeof to protect
against the situation where an error is thrown.

This means that typeof(hostobj.prop) could throw an error.

Peter

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 9:26:16 AM7/2/09
to
wilq wrote:

> Thomas 'PointedEars' Lahn wrote:
>> wilq wrote:
>>> I dont have access to mine profiling function so I create own one
>>> from scratches. Its not great because I do this in hurry, if you have
>>> time to test it - please do. If you have idea on what might
>>> interferee with test cases - i'm open to hear :) Cheers:
>>> [...]
>>> (function(){
>>> var times=[];
>>> function addTime()
>>> {
>>> times.push((new Date()).getTime());
>> Why, +new Date() suffices.
>
> If we use it every time when measuring - it is counted inside measurement
> time for both operation (regexp and string)... so what diffrence?

+new Date() is arguably more runtime-efficient than (new Date()).getTime(),
another explicit method call (untested). Historically, type-converting
operations have been more runtime-efficient than type-converting calls.

>>> }
>> var someTemp;
>> var iterationCount=500000;
>> Several script engines might consider a script with that many
>> iterations as blocking, depending on accumulated runtime.
>
> Yes of course - because of this is an argument that you can change.

The question raised by this is: Is it realistic for an app to perform that
many calls of isMethod() consecutively? If not, the number is too high.
And as it is too high (IMHO), differences in runtime efficiency between
these approaches are in fact not as important as you present them to be.
And, as I said, efficiency is not everything. To begin with, any approach
should balance efficiency against reliability.

>>> var a="function";
>>> var b="object";
>>> var regExp=/^function|object$/;
>> As written in e-mail, this will match either "function" at the start of
>> input, or "object" at the end of input (which I imagine to be slow),
>> and so is not equivalent to `either "function" or "object"'. You'll
>> need
>>
>> var regExp=/^(function|object)$/;
>>
>> but, again, that does not consider leading or trailing whitespace.
>
> You can add those bracers to mine profiling function. As you probably
> notice this does not change alot.

Yes, as written in e-mail, with realistic figures the difference is as
negligible as before (in the 50 ms range on a Pentium M 740).

>>> function reg(){ for (var i=0;i<iterationCount;i++) { someTemp =
>>> regExp.test(a); someTemp = regExp.test(b);
>> Cheater! :) Here both tests will be performed always (worst case), but
>> that is not necessary with /^\s*unknown\s*/i and
>> /^\s*(object|function)\s*/i as in `is(Host)Method'. Hence my reversing
>> the order of tests since; shortcut evaluation of boolean expressions
>> will do the rest.
>
> Cheater ? I dont think so - I compare here cases that will occur mostly -
> "function" and "object". But I do the same for string solution

No, you don't.

> so there is no cheat. In fact its very fair comparsion in mine opinion.

Hardly. Fair would be

someTemp = regExp.test(a) || regExp.test(b);

> I open to see a best + worst case as you said that is in string
> comparsion.

The problem is that you are picking the cases that are in your favor,
IOW you *are* cheating here.

>>> }
>>> }
>>> function str()
>>> for (var i=0;i<iterationCount;i++)
>>> {
>>> someTemp = (a==="function"||a==="object");
>> Cheater! :) With your input, the second operand will never be
>> evaluated, and type conversion does not take place (best case).
>
> Yes - this is a idea of this test.

This test is biased(, then).

> I propose this test as a answer to post from some time ago that
> You were involved in:
>
> Correct me if I'm wrong, you changed:
>
> basically you changed there
>
> (t=='function' || t=='object')
>
> to:
>
> /^(function|object)$/.test(t)

You are wrong. Both about the original and the change.

> So here I also did the test. And in post before I explained why this
> string comparsion would be better - exacly that if a first boolean
> structure will be true, second wont be computed at all. You can try
> diffrent cases (both worst, both good) with a="object", b="object" and
> a="function", b="function" to see that this is still faster than
> regexp...

*Maybe* so, on *your* computer, *without RegExp optimization*. But it is
on *all* computers (running non-obsolete implementations) *less reliable*.

>>> someTemp = (b==="function"||b==="object");
>> With this approach, type conversion does not take place but might be
>> necessary with a `typeof' result when a host object is the operand.
>> And with your input, both operands will always be evaluated here (worst

>> case)..


>
> If this is really so big diffrence for you ?

Yes, it is.

> Then please consider this for the code that I gave:
>
> var a=typeof (function(){});
> var b=typeof ({someObject:0});

I was talking about host objects.

>>> }}
>> When you have set up a test of roughly equivalent approaches we can
>> talk about the shortcomings of simple string comparison as compared to
>> RegExp matching. In particular when host objects and unknown input is
>> involved.
>

> Basically you pointed out some elements in code, but generally that has
> nothing to do with really results of test.

Yes, it does. We are not discussing in a theoretical vacuum here.
Efficiency considerations matter because practical issues arise from
following an inefficient approach.

> Also you did not provide anything that would show that this approach is
> completly wrong. Please then provide code that proves what you saying is
> true :) I really like seeing things working than only talking. Then I
> can judge your solution :)

I have posted and pointed to the current (abridged) isMethod()
implementation already; now you only need to notice that.


PointedEars
--
realism: HTML 4.01 Strict
evangelism: XHTML 1.0 Strict
madness: XHTML 1.1 as application/xhtml+xml
-- Bjoern Hoehrmann

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 9:51:49 AM7/2/09
to
Peter Michaux wrote:

> Thomas 'PointedEars' Lahn wrote:
>> Peter Michaux wrote:
>>> On Jun 29, 9:47 pm, RobG <robg...@gmail.com> wrote:
>>>> [...]
>>>> Feature Detection: State of the Art Browser Scripting
>>>> <URL:http://peter.michaux.ca/articles/feature-detection-state-of-the-art-b...
>>> [isHostMethod, isHostCollection, and isHostObject functions]
>>> These three functions depend on non-standardized behavior of the
>>> typeof operator. The typeof operator is being used as some sort of
>>> magic try-catch but the ECMAScript standard doesn't say anything about
>>> that behavior. From my reading of the standard if obj.prop blows up in
>>> some browser than so could typeof(obj.prop). It just so happens that
>>> the implementations don't blow up when using the typeof version.
>> But not merely by chance.
>
> [Snip sections 11.2.1 and 11.4.3 of the ECMAScript standard quoted in
> an awkward-to-reply-to, two-column format.]

It was posted like that (with considerable effort!) so that the differences
could be easily seen by the dedicated reader. Not awkward at all.

> Look more into the evaluation of step 4 of the typeof operator. It is
>
> 4. Call GetValue(Result(1))

(JFTR: I have not doubted that the observed behavior may be the result of
not standards-compliant parts in the respective implementation of ECMAScript
or the DOM's ECMAScript binding.)

FWIW, I don't think GetValue() matters here. While step 3 of the `typeof'
algorithm could matter (which would be not standards compliant as it MUST
NOT return "unknown"), I think it matters more what actually happens in
steps 3 to 6 of the property accessor algorithm. Also the ToBoolean() in
the `if' statement algorithm (12.5) deserves closer inspection.

> [...]


> This means that typeof(hostobj.prop) could throw an error.

JFTR: Yes, it could.


PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm>

David Mark

unread,
Jul 2, 2009, 5:53:48 PM7/2/09
to
On Jun 30, 5:59 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> RobG wrote:
> > <FAQENTRY>
>
> > There has been frequent mention of the legendary "isHostMethod"
> > function in this group over the last 18 months or so in conjunction
> > with statements that "boolean type conversion is out" for testing host
> > method availability.  While that may be so, trying to find the elusive
> > method in all the noise is pretty difficult.
>
> > I discovered this version posted by Thomas in February 2008[1]:
>
> My JSdoc™ says:
>
>  * @author
>  *   (C) 2003-2009  Thomas Lahn &lt;object...@PointedEars.de&gt;

Oh mercy. You wrote that comment. Looking at the posted code, I will
concede that it's slightly modified from the one found in My Library
(mine creates the RegExp once.)

>
> I presume Google Groups still has the first version, either here or in
> de.comp.lang.javascript.

Huh? The first version(s) were posted here during the CWR
discussions.

[snip]

David Mark

unread,
Jul 2, 2009, 6:00:26 PM7/2/09
to

No doubt about it. Can also be found in many newer libraries.

>
> > Arguments about isHostMethod function don't seem to be likely to
> > contribute suitable or appropriate material for the FAQ. It may very
> > lead to pedandtry, quibbling or even irrational zealotry and flames.
>
> It takes a draft FAQ item for that? ;-)

His "arguments" make no sense.

>
> The only minor quibble I see here is over whether a regular expression
> should be used or not - that is a relatively trivial matter related to
> performance, not the purpose or overall design. I know you have a
> personal opinion that the in operator should be used, but that is a
> minority view.

It's apples and oranges anyway.

>
> > The code in that misnamed method pretends to imply that the property
> > is a method. I can't recommend that.

LOL. It basically comes down to two points. Doesn't like the name
and can't bottle his solution.

>
> That is your opinion, and while you may be the FAQ maintainer, that
> does not make you sole arbiter of what it should or should not
> contain.
> The purpose and limitations of the function have been
> expressed (and summarised previously in this thread), they should be
> part of the entry.

Agreed on both points.

>
> > I am not incapable of writing, and do like help with the FAQ, but I am
> > busy with various things, including recent threads here (dynamic
> > loading), other things that are related to programming, and yet other
> > things in my life that are unrelated. Not sailboats, but good stuff
> > nonetheless.
>
> There is no need for you to participate in the discussion, there are
> half a dozen regulars who have already done so since the topic was
> first raised. It only requires someone to post a draft, discussion to
> occur, and suitable agreement be reached. It is then up to the FAQ
> maintainer to put it in the FAQ.

Or we'll get rid of him and get one who will. :) And I think a
change is long overdue anyway.

Dr J R Stockton

unread,
Jul 2, 2009, 4:40:35 PM7/2/09
to
In comp.lang.javascript message <4A4CB578...@PointedEars.de>, Thu,
2 Jul 2009 15:26:16, Thomas 'PointedEars' Lahn <Point...@web.de>
posted:

>+new Date() is arguably more runtime-efficient than (new Date()).getTime(),
>another explicit method call (untested). Historically, type-converting
>operations have been more runtime-efficient than type-converting calls.

An excellent demonstration of the relative powers of arguing and of
getting actual facts.

Time taken by D.getTime(), as percentage of time for +D, if I tested
correctly :

IE 7 85
FF 3.0.11 85
Op 9.64 43
Safari 4.0 65
Chrome 2.0 29

Testing with new Date() gives rather irregular results, presumably
because of the many OS calls; but supports the conclusion.

Using getTime calls explicitly for use of that Method; using unary +
calls implicitly for the use of method valueOf, presumably the same
code, and also does the "return a Number" operation, apparently not
optimising it out.

But I suggest that testing is not needed to see that unary + is faster
to type and to read.

Did that speed difference not get mentioned here before, not so long
ago?

--
(c) John Stockton, nr London, UK. ?@merlyn.demon.co.uk Turnpike v6.05.
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm estrdate.htm js-dates.htm pas-time.htm critdate.htm etc.

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 8:04:16 PM7/2/09
to
David Mark wrote:

> Thomas 'PointedEars' Lahn wrote:
>> RobG wrote:
>>> <FAQENTRY>
>>> There has been frequent mention of the legendary "isHostMethod"
>>> function in this group over the last 18 months or so in conjunction
>>> with statements that "boolean type conversion is out" for testing host
>>> method availability. While that may be so, trying to find the elusive
>>> method in all the noise is pretty difficult.
>>> I discovered this version posted by Thomas in February 2008[1]:
>> My JSdoc™ says:
>>
>> * @author
>> * (C) 2003-2009 Thomas Lahn &lt;object...@PointedEars.de&gt;
>
> Oh mercy. You wrote that comment.

Because it's true.

> Looking at the posted code, I will concede that it's slightly modified
> from the one found in My Library (mine creates the RegExp once.)

It is not surprising that different people, at different times, independent
from one another, can come to the same result. My isMethod() is not any
more modified from that in your "My Library" (confusing name, isn't it?)
than vice-versa (it is _not_). I will ask you only once to stop implying
otherwise.

>> I presume Google Groups still has the first version, either here or in
>> de.comp.lang.javascript.
>
> Huh? The first version(s) were posted here during the CWR
> discussions.

No, years before that. IIRC, even years before Peter and you found cljs (at
least before you were *posting* here).


PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16

kangax

unread,
Jul 2, 2009, 8:11:44 PM7/2/09
to

Looks good. You could take `len - 1` out of the loop as well as avoid
resolving `jsx.object.isArray` over and over, but that is an
insignificant quibble (considering that number of arguments are unlikely
to exceed 4-5).

>
>>> ¹ Regarding the cross-frame issue: what about a property referring
>>> to the current Array object to be set and reset before/after call
>>> as needed?
>> I suppose you're talking about so-called Miller device (i.e. comparing
>> value of [[Class]] to "Array").
>
> Yes, I don't like that for its many assumptions.

There are not so many assumptions. It works as designed with native
objects in compliant implementations. Host objects are of course allowed
to implement any [[Class]] value in ES3, but not so in ES5 (as per 8.6.2
in both ES3 and ES5-draft specs).

>
>> From what I remember (per Richard's observations), it was
>> *cross-window issue*, not cross-frame one.
>
> But I thought the problem were different global objects, each with its own
> Array property.

Yes, but AUIU only Array objects created in child windows have "Object"
[[Class]] values (rather than "Array" ones). This is what "confuses"
Miller device.

This seems awkward. If I have 2 arrays from different frames, I would
need to set proper `jsx.Array` reference before testing each one of
them. And what if I don't know which frame array was created in? What if
that frame was removed from the document and I don't have a reference to
its global `Array` property?

>
>>>> // compare to something like:
>>>>
>>>> if (document &&
>>>> document.body &&
>>>> isMethod(document.body, 'appendChild') &&
>>>> isMethod(document.body, 'removeChild')) { ... }
>>> `if (foo)' (here: foo === document) is not very reliable in any case,
>>> though: Implicit type conversion on a host object (which may throw any
>>> exception) using a property that may not even exist (which may throw a
>> I assumed `document` would be tested for existence before performing
>> that test.
>
> That is exactly what I want to avoid.

Ok.

>
>> Or if it wasn't, it should always be possible to "start" from
>> the global object:
>>
>> // considering `this` refers to Global Object here:
>> isMethod(this, 'window', 'document', 'body', 'appendChild');
>
> Yes, I am using
>
> jsx.object.isMethod(jsx.global, 'window', 'document', 'body', 'appendChild');
>
> But a method to be tested is not necessarily anchored at the global object.

Makes sense.

>
>> This actually gave me an idea for alternative `isMethod` signature:
>>
>> isMethod('window.document.body.appendChild');
>>
>> would split string by ".", then sequentially test properties starting
>> from the global object. Not sure how this would work with multiple
>> methods though (i.e. `areMethods`).
>
> I had considered and rejected this approach already because it would
> preclude property names with dots in them from being considered.

Ah, of course. I imagine this could come up when accessing methods on
elements via name values:

isMethod(myForm, 'elements', 'foo.bar', 'focus');

>
>> As far as type converting host objects (not methods!), didn't we just
>> have a conversation about it where you said that it should be safe to do so?
>>
>> [...]
>> <http://groups.google.com/group/comp.lang.javascript/msg/4df3cf9b5a7bd60f>
>>
>> Or am I missing something?
>
> Yes, I was talking about return values of standardized methods there.

I'm pretty sure we were talking about `lastChild`/`firstChild` as an
operand in `if`/`while` expression (when "emptying" element contents).
`lastChild` is specified to be of type Node (or should I say - its
return value is specified to implement Node interface, or `null`).
`document`, in its turn, is specified to be of type Document, which
inherits from Node. Therefore type conversion on `lastChild` and
`window.document` carries similar risk, from what I can see (unless
objects implementing exactly Document interface would be the ones to
throw, and not those that implement Node only; but that would be just
plain silly)

>
>>> TypeError). Therefore, I suggested allowing for the evaluation of primitive
>>> strings that match /Identifier/ or property accessor for the first argument,
>>> per flag so that methods of String objects could still be tested. What do
>>> you think about that?
>> What do you mean by "flag" and "per flag"?
>

[snip `tryThis`]

>
> /* ... */
>
> var isMethod = jsx.object.isMethod = jsx.object.areMethods = function(o, p) {
> var len = arguments.length;
> if (len < 1) return false;

Shouldn't return value be other than boolean, to indicate that something
went wrong and differentiate from cases when tested method isn't
recognized as "method"? (e.g. is "unknown").

>
> var
> rxUnknown = /^\s*unknown\s*$/i,
> rxMethod = /^\s*(function|object)\s*$/i,

Why initialize these on every method invocation?

> t = typeof o;
>
> /* ... */
>
> /*
> * Refined support for strings; evaluating them always would
> * preclude String objects from being tested for methods.
> * Try to warn if a primitive string value is passed and the
> * required flag is not set (default).
> */
> if (t === "string")
> {
> if (arguments.callee.evalStrings)

I wouldn't use `arguments.callee` if possible (to take advantage of
environments which optimize).

[...]

--
kangax

David Mark

unread,
Jul 2, 2009, 8:45:14 PM7/2/09
to
On Jul 2, 8:04 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> David Mark wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> RobG wrote:
> >>> <FAQENTRY>
> >>> There has been frequent mention of the legendary "isHostMethod"
> >>> function in this group over the last 18 months or so in conjunction
> >>> with statements that "boolean type conversion is out" for testing host
> >>> method availability.  While that may be so, trying to find the elusive
> >>> method in all the noise is pretty difficult.
> >>> I discovered this version posted by Thomas in February 2008[1]:
> >> My JSdoc™ says:
>
> >>  * @author
> >>  *   (C) 2003-2009  Thomas Lahn &lt;object...@PointedEars.de&gt;
>
> > Oh mercy.  You wrote that comment.
>
> Because it's true.

Sort of.

>
> > Looking at the posted code, I will concede that it's slightly modified
> > from the one found in My Library (mine creates the RegExp once.)
>
> It is not surprising that different people, at different times, independent
> from one another, can come to the same result.  My isMethod() is not any
> more modified from that in your "My Library" (confusing name, isn't it?)
> than vice-versa (it is _not_).  I will ask you only once to stop implying
> otherwise.
>
> >> I presume Google Groups still has the first version, either here or in
> >> de.comp.lang.javascript.
>
> > Huh?  The first version(s) were posted here during the CWR
> > discussions.
>
> No, years before that.  IIRC, even years before Peter and you found cljs (at
> least before you were *posting* here).

That was certainly not isHostMethod as that is what I named my
function. Yours did not have the bit about "unknown" types, which
were apparently my discovery (every time I bring them up it seems
nobody knows what I am talking about.)

It is based on isMethodType from years back. And I "found" CLJ in
1996. Posted many times in the 90's as well, though not regularly and
probably under some silly handle.

David Mark

unread,
Jul 2, 2009, 8:49:18 PM7/2/09
to

Host objects should not be passed to "isArray" functions of any
flavor. Most designs should not need a such a function anyway.

>
>
>
> >> From what I remember (per Richard's observations), it was
> >> *cross-window issue*, not cross-frame one.
>
> > But I thought the problem were different global objects, each with its own
> > Array property.
>
> Yes, but AUIU only Array objects created in child windows have "Object"
> [[Class]] values (rather than "Array" ones). This is what "confuses"
> Miller device.

I thought it was frames as well. Regardless, as it is not 100%, you
must fall back to "duck typing" for "Object" classes. This is why
such functions should be designed out of the system.

>
>
>
>
>
> >> In any case, I'm not sure I understand what you mean by resetting
> >> property and "current Array object". Would you please clarify?
>
> > /**
> >  * Reference to the object used for {@link Array} detection;
> >  * modify at runtime if you access this script from
> >  * a different frame.
> >  */
> > jsx.Array = typeof Array != "undefined" ? Array : null;
>
> > /**
> >  * NOTE: This method has previously been provided by
> >  * {@link types.js}; optimizations in code reuse moved it here.
> >  *
> >  * @author

> >  *   (C) 2003, 2009  Thomas Lahn &lt;object...@PointedEars.de&gt;
> >  * @partofhttp://pointedears.de/scripts/object.js


> >  * @requires jsx#object.isInstanceOf
> >  * @param a : Object
> >  *   Expression to be determined an array.
> >  * @return
> >  *   <code>true</code> if <code>a</code> is an object
> >  *   derived from Array, <code>false</code> otherwise.
> >  *   Returns also <code>false</code> if the language
> >  *   version does not support Array objects (JavaScript
> >  *   before 1.1).
> >  */
> > var isArray = jsx.object.isArray = function(a) {
> >   return jsx.object.isInstanceOf(a, jsx.Array);
> > };
>
> This seems awkward.

It's just as it seems.

[snip]

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 8:50:56 PM7/2/09
to

Yes, but I don't think subtraction by 1 justifies introducing another variable.

> as avoid resolving `jsx.object.isArray` over and over,

Will do (as done elsewhere). However, it would have to be v.isArray(...)
in any case, or extensive rewrites might be needed if I change how
jsx.object.isArray() gets to the jsx.object.isInstanceOf() that it calls.

> [...]


>>>> ¹ Regarding the cross-frame issue: what about a property referring
>>>> to the current Array object to be set and reset before/after call
>>>> as needed?
>>> I suppose you're talking about so-called Miller device (i.e. comparing
>>> value of [[Class]] to "Array").
>> Yes, I don't like that for its many assumptions.
>
> There are not so many assumptions. It works as designed with native
> objects in compliant implementations. Host objects are of course allowed
> to implement any [[Class]] value in ES3, but not so in ES5 (as per 8.6.2
> in both ES3 and ES5-draft specs).

> [...]

Hmmm. I will review that discussion.

How couldn't you know? You are accessing it.

> What if that frame was removed from the document and I don't have a
> reference to its global `Array` property?

That's a good argument. Question remains if such an Array object would even
continue working, though.

>>> As far as type converting host objects (not methods!), didn't we just
>>> have a conversation about it where you said that it should be safe to do so?
>>>
>>> [...]
>>> <http://groups.google.com/group/comp.lang.javascript/msg/4df3cf9b5a7bd60f>
>>>
>>> Or am I missing something?
>> Yes, I was talking about return values of standardized methods there.
>
> I'm pretty sure we were talking about `lastChild`/`firstChild` as an
> operand in `if`/`while` expression (when "emptying" element contents).

You're right. However, I would submit that there is still a difference
between a property of a host object that must strictly follow specification,
and a host-defined property of the global object or a property of a host
object, that does not strictly follows implementation (for historical reasons).

> `lastChild` is specified to be of type Node (or should I say - its
> return value is specified to implement Node interface, or `null`).
> `document`, in its turn, is specified to be of type Document, which
> inherits from Node. Therefore type conversion on `lastChild` and
> `window.document` carries similar risk,

That might seem awkward at first, but the untested standalone `document' is
indeed riskier than the untested `window.document' (given `window' doesn't
fail, of course). Failed identifier resolution throws an exception
everywhere and always. There is also the remote possibility of a `document'
property in the scope chain that does not refer to a document object.

> from what I can see (unless objects implementing exactly
> Document interface would be the ones to throw, and not
> those that implement Node only; but that would be just
> plain silly)

It is not the value but the existence of the property that matters here.

>>>> TypeError). Therefore, I suggested allowing for the evaluation of primitive
>>>> strings that match /Identifier/ or property accessor for the first argument,
>>>> per flag so that methods of String objects could still be tested. What do
>>>> you think about that?
>>> What do you mean by "flag" and "per flag"?
>
> [snip `tryThis`]
>
>> /* ... */
>>
>> var isMethod = jsx.object.isMethod = jsx.object.areMethods = function(o, p) {
>> var len = arguments.length;
>> if (len < 1) return false;
>
> Shouldn't return value be other than boolean, to indicate that something
> went wrong and differentiate from cases when tested method isn't
> recognized as "method"? (e.g. is "unknown").

A possibility; but what should it be? These days I would even consider
throwing exceptions instead (guarded with eval(), of course).

>> var
>> rxUnknown = /^\s*unknown\s*$/i,
>> rxMethod = /^\s*(function|object)\s*$/i,
>
> Why initialize these on every method invocation?

Pretty inefficient, I know. I'm working on it.

>> t = typeof o;
>>
>> /* ... */
>>
>> /*
>> * Refined support for strings; evaluating them always would
>> * preclude String objects from being tested for methods.
>> * Try to warn if a primitive string value is passed and the
>> * required flag is not set (default).
>> */
>> if (t === "string")
>> {
>> if (arguments.callee.evalStrings)
>
> I wouldn't use `arguments.callee` if possible (to take advantage of
> environments which optimize).

If the property should not be owned by another object, `arguments.callee' is
a necessity as long as there cannot be a unique identifier (for backwards
compatibility) and user-defined read-only properties everywhere are still on
the wish list. And I really like using function objects as containers for
function-related properties.

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 8:59:02 PM7/2/09
to
David Mark wrote:
> On Jul 2, 8:11 pm, kangax <kan...@gmail.com> wrote:
>> Thomas 'PointedEars' Lahn wrote:
>>> kangax wrote:
>
> [...]

> Host objects should not be passed to "isArray" functions of any
> flavor. Most designs should not need a such a function anyway.
>
>>>> From what I remember (per Richard's observations), it was
>>>> *cross-window issue*, not cross-frame one.
>>> But I thought the problem were different global objects, each with its own
>>> Array property.
>> Yes, but AUIU only Array objects created in child windows have "Object"
>> [[Class]] values (rather than "Array" ones). This is what "confuses"
>> Miller device.
>
> I thought it was frames as well. Regardless, as it is not 100%, you
> must fall back to "duck typing" for "Object" classes. This is why
> such functions should be designed out of the system.

How do you propose to do that here? It needs to be tested whether the
argument is an Array object reference or not.


BTW, please learn to quote properly *always*. Your continued/repeated
failure to comply with that simple FAQ-supported request sets a pretty
bad example for this group, given that you do post valuable advice.
Even you can't be that busy.


PointedEars
--
Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 9:18:42 PM7/2/09
to
David Mark wrote:
> Thomas 'PointedEars' Lahn wrote:
>> David Mark wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> RobG wrote:
>>>>> <FAQENTRY>
>>>>> There has been frequent mention of the legendary "isHostMethod"
>>>>> function in this group over the last 18 months or so in conjunction
>>>>> with statements that "boolean type conversion is out" for testing host
>>>>> method availability. While that may be so, trying to find the elusive
>>>>> method in all the noise is pretty difficult.
>>>>> I discovered this version posted by Thomas in February 2008[1]:
>>>> My JSdoc™ says:
>>>> * @author
>>>> * (C) 2003-2009 Thomas Lahn &lt;object...@PointedEars.de&gt;
>>> Oh mercy. You wrote that comment.
>> Because it's true.
>
> Sort of.

I won't debate that the version of 2003/2004 is less evolved than what I
have now (that would be pretty bad performance); but please, credit where
credit is due:

<http://bytes.com/groups/javascript/151754-when-window-location-url-executed>

(Google doesn't seem to have it anymore, or the search function is borken.)

>>>> I presume Google Groups still has the first version, either here or in
>>>> de.comp.lang.javascript.
>>> Huh? The first version(s) were posted here during the CWR
>>> discussions.
>> No, years before that. IIRC, even years before Peter and you found cljs (at
>> least before you were *posting* here).
>
> That was certainly not isHostMethod as that is what I named my
> function.

Yes, I have never seen the need to make a difference there and I still don't
see it. Apparently Peter started to doubt, too.

> Yours did not have the bit about "unknown" types, which
> were apparently my discovery (every time I bring them up it seems
> nobody knows what I am talking about.)

I don't know whose discovery that was, but apparently you were the first to
mention it on Usenet:

<http://groups.google.com/group/comp.lang.javascript/msg/b34757abe55aaea0?hl=en&dmode=source>

> It is based on isMethodType from years back.

How come that you missed isMethod() from years back although it has been
referred to at least in the JSdoc™ of isMethodType() ever since?

David Mark

unread,
Jul 2, 2009, 10:36:17 PM7/2/09
to
On Jul 2, 8:59 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> David Mark wrote:
> > On Jul 2, 8:11 pm, kangax <kan...@gmail.com> wrote:
> >> Thomas 'PointedEars' Lahn wrote:
> >>> kangax wrote:
>
> > [...]
> > Host objects should not be passed to "isArray" functions of any
> > flavor.  Most designs should not need a such a function anyway.
>
> >>>> From what I remember (per Richard's observations), it was
> >>>> *cross-window issue*, not cross-frame one.
> >>> But I thought the problem were different global objects, each with its own
> >>> Array property.
> >> Yes, but AUIU only Array objects created in child windows have "Object"
> >> [[Class]] values (rather than "Array" ones). This is what "confuses"
> >> Miller device.
>
> > I thought it was frames as well.  Regardless, as it is not 100%, you
> > must fall back to "duck typing" for "Object" classes.  This is why
> > such functions should be designed out of the system.
>
> How do you propose to do that here?  It needs to be tested whether the
> argument is an Array object reference or not.

Chuck the whole thing and redo anything that initially indicated a
need for it.

>
> BTW, please learn to quote properly *always*.  Your continued/repeated
> failure to comply with that simple FAQ-supported request sets a pretty
> bad example for this group, given that you do post valuable advice.
> Even you can't be that busy.

LOL. You have no idea.

David Mark

unread,
Jul 2, 2009, 10:40:53 PM7/2/09
to
On Jul 2, 9:18 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>

wrote:
> David Mark wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> David Mark wrote:
> >>> Thomas 'PointedEars' Lahn wrote:
> >>>> RobG wrote:
> >>>>> <FAQENTRY>
> >>>>> There has been frequent mention of the legendary "isHostMethod"
> >>>>> function in this group over the last 18 months or so in conjunction
> >>>>> with statements that "boolean type conversion is out" for testing host
> >>>>> method availability.  While that may be so, trying to find the elusive
> >>>>> method in all the noise is pretty difficult.
> >>>>> I discovered this version posted by Thomas in February 2008[1]:
> >>>> My JSdoc™ says:
> >>>>  * @author
> >>>>  *   (C) 2003-2009  Thomas Lahn &lt;object...@PointedEars.de&gt;
> >>> Oh mercy.  You wrote that comment.
> >> Because it's true.
>
> > Sort of.
>
> I won't debate that the version of 2003/2004 is less evolved than what I
> have now (that would be pretty bad performance); but please, credit where
> credit is due:
>
> <http://bytes.com/groups/javascript/151754-when-window-location-url-ex...>

>
> (Google doesn't seem to have it anymore, or the search function is borken.)

If you mean isMethodType, then yes. You fought tooth and nail when I
proposed isHostMethod, which is just a slight improvement.

>
> >>>> I presume Google Groups still has the first version, either here or in
> >>>> de.comp.lang.javascript.
> >>> Huh?  The first version(s) were posted here during the CWR
> >>> discussions.
> >> No, years before that.  IIRC, even years before Peter and you found cljs (at
> >> least before you were *posting* here).
>
> > That was certainly not isHostMethod as that is what I named my
> > function.
>
> Yes, I have never seen the need to make a difference there and I still don't
> see it.  Apparently Peter started to doubt, too.

What are you talking about? We debated this to death. Unless you
wish to exclude ActiveX methods, which can pop up anywhere in IE and
throw exceptions, isHostMethod is the way to go. Nobody ever said
what exactly MS was doing behind the scenes with that stuff (that's
all speculation.) The point is that cross-browser scripting is part
science and part history.

>
> > Yours did not have the bit about "unknown" types, which
> > were apparently my discovery (every time I bring them up it seems
> > nobody knows what I am talking about.)
>
> I don't know whose discovery that was, but apparently you were the first to
> mention it on Usenet:
>

> <http://groups.google.com/group/comp.lang.javascript/msg/b34757abe55aa...>

Okay, but how can you not know what the difference is?

>
> > It is based on isMethodType from years back.
>
> How come that you missed isMethod() from years back although it has been
> referred to at least in the JSdoc™ of isMethodType() ever since?

Seems odd, but I'll take your word for it. I seem to remember you
arguing about passing a reference to isHostMethod. I see you have
written a sequel too. Looks like a good idea, but please don't call
it areHostMethods as that one exists. I'm not saying you called it
that, but I've seen several proposals lately and one had that name.

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 10:45:14 PM7/2/09
to
David Mark wrote:
> Thomas 'PointedEars' Lahn wrote:
>> David Mark wrote:

>>> kangax wrote:
>>>> Thomas 'PointedEars' Lahn wrote:
>>>>> kangax wrote:
>>> [...]
>>> Host objects should not be passed to "isArray" functions of any
>>> flavor. Most designs should not need a such a function anyway.
>>>>>> From what I remember (per Richard's observations), it was
>>>>>> *cross-window issue*, not cross-frame one.
>>>>> But I thought the problem were different global objects, each with its own
>>>>> Array property.
>>>> Yes, but AUIU only Array objects created in child windows have "Object"
>>>> [[Class]] values (rather than "Array" ones). This is what "confuses"
>>>> Miller device.
>>> I thought it was frames as well. Regardless, as it is not 100%, you
>>> must fall back to "duck typing" for "Object" classes. This is why
>>> such functions should be designed out of the system.
>> How do you propose to do that here? It needs to be tested whether the
>> argument is an Array object reference or not.
>
> Chuck the whole thing and redo anything that initially indicated a
> need for it.

Now that's a pretty useless reply. You owe me at least 15 seconds of my time.

>> BTW, please learn to quote properly *always*. Your continued/repeated
>> failure to comply with that simple FAQ-supported request sets a pretty
>> bad example for this group, given that you do post valuable advice.
>> Even you can't be that busy.
>
> LOL. You have no idea.

Then post when you are not busy. The overall quality of your replies might
even increase, and rest assured the world isn't going to end because of that
delay. BTDT.

David Mark

unread,
Jul 2, 2009, 10:52:48 PM7/2/09
to
On Jul 2, 10:45 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

> David Mark wrote:
> > Thomas 'PointedEars' Lahn wrote:
> >> David Mark wrote:
> >>> kangax wrote:
> >>>> Thomas 'PointedEars' Lahn wrote:
> >>>>> kangax wrote:
> >>> [...]
> >>> Host objects should not be passed to "isArray" functions of any
> >>> flavor.  Most designs should not need a such a function anyway.
> >>>>>> From what I remember (per Richard's observations), it was
> >>>>>> *cross-window issue*, not cross-frame one.
> >>>>> But I thought the problem were different global objects, each with its own
> >>>>> Array property.
> >>>> Yes, but AUIU only Array objects created in child windows have "Object"
> >>>> [[Class]] values (rather than "Array" ones). This is what "confuses"
> >>>> Miller device.
> >>> I thought it was frames as well.  Regardless, as it is not 100%, you
> >>> must fall back to "duck typing" for "Object" classes.  This is why
> >>> such functions should be designed out of the system.
> >> How do you propose to do that here?  It needs to be tested whether the
> >> argument is an Array object reference or not.
>
> > Chuck the whole thing and redo anything that initially indicated a
> > need for it.
>
> Now that's a pretty useless reply.  You owe me at least 15 seconds of my time.

Look again. It's the only practical answer to your question.

[snip]

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 11:05:27 PM7/2/09
to
David Mark wrote:
> Thomas 'PointedEars' Lahn wrote:
>> David Mark wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> David Mark wrote:
>>>>> Thomas 'PointedEars' Lahn wrote:
>>>>>> RobG wrote:
>>>>>>> <FAQENTRY>
>>>>>>> There has been frequent mention of the legendary "isHostMethod"
>>>>>>> function in this group over the last 18 months or so in conjunction
>>>>>>> with statements that "boolean type conversion is out" for testing host
>>>>>>> method availability. While that may be so, trying to find the elusive
>>>>>>> method in all the noise is pretty difficult.
>>>>>>> I discovered this version posted by Thomas in February 2008[1]:
>>>>>> My JSdoc™ says:
>>>>>> * @author
>>>>>> * (C) 2003-2009 Thomas Lahn &lt;object...@PointedEars.de&gt;
>>>>> Oh mercy. You wrote that comment.
>>>> Because it's true.
>>> Sort of.
>> I won't debate that the version of 2003/2004 is less evolved than what I
>> have now (that would be pretty bad performance); but please, credit where
>> credit is due:
>>
>> <http://bytes.com/groups/javascript/151754-when-window-location-url-ex...>
>>
>> (Google doesn't seem to have it anymore, or the search function is borken..)

>
> If you mean isMethodType, then yes.

You really can search for "function isMethod" there if you want. Trust me.

> You fought tooth and nail when I proposed isHostMethod, which is just a
> slight improvement.

Come on! I debated whether it would be useful in general to have a method
that requires another test before it can be used. And in part I still do,
hence my considering to allow identifier/member expression string evaluation
back (if via flag) after all. (I have already allowed a single argument for
isMethod() so that e.g. arguments of other methods could be tested without
isMethodType() and the "unknown" expression [the base object of the
reference would be the context's Variable Object, which is unavailable per
reference except global]. Turned out that you can't pass "unknown"s anyway.)

>>>>>> I presume Google Groups still has the first version, either here or in
>>>>>> de.comp.lang.javascript.
>>>>> Huh? The first version(s) were posted here during the CWR
>>>>> discussions.
>>>> No, years before that. IIRC, even years before Peter and you found cljs (at
>>>> least before you were *posting* here).
>>> That was certainly not isHostMethod as that is what I named my
>>> function.
>> Yes, I have never seen the need to make a difference there and I still don't
>> see it. Apparently Peter started to doubt, too.
>

> What are you talking about? [snip irrelevance]

<news:bee08d6a-0f19-4da9...@h2g2000yqg.googlegroups.com>

>>> Yours did not have the bit about "unknown" types, which
>>> were apparently my discovery (every time I bring them up it seems
>>> nobody knows what I am talking about.)
>> I don't know whose discovery that was, but apparently you were the first to
>> mention it on Usenet:
>>
>> <http://groups.google.com/group/comp.lang.javascript/msg/b34757abe55aa...>
>
> Okay, but how can you not know what the difference is?

I don't follow.

>>> It is based on isMethodType from years back.
>> How come that you missed isMethod() from years back although it has been
>> referred to at least in the JSdoc™ of isMethodType() ever since?
>
> Seems odd, but I'll take your word for it. I seem to remember you
> arguing about passing a reference to isHostMethod. I see you have
> written a sequel too. Looks like a good idea, but please don't call
> it areHostMethods as that one exists.

It is going to be jsx.object.areMethods (and jsx.object.areHostMethods
should it prove to be needed), so there is only a remote possibility for
confusion.

Thomas 'PointedEars' Lahn

unread,
Jul 2, 2009, 11:10:16 PM7/2/09
to

It isn't even remotely practical! One needs to differentiate between
testing foo.bar.baz, or foo.bar and foo.baz etc. without much fuss about
objects and properties on call. AFAICS only Arrays can provide that in
these languages.

David Mark

unread,
Jul 2, 2009, 11:42:09 PM7/2/09
to
On Jul 2, 11:05 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>

I believe you, but if it accepts references to host objects for the
first argument, I'm confused by your prior position on isHostMethod.

>
> > You fought tooth and nail when I proposed isHostMethod, which is just a
> > slight improvement.
>
> Come on!  I debated whether it would be useful in general to have a method
> that requires another test before it can be used.  And in part I still do,
> hence my considering to allow identifier/member expression string evaluation
> back (if via flag) after all.  (I have already allowed a single argument for
> isMethod() so that e.g. arguments of other methods could be tested without
> isMethodType() and the "unknown" expression [the base object of the
> reference would be the context's Variable Object, which is unavailable per
> reference except global].  Turned out that you can't pass "unknown"s anyway.)

You can't do much of anything with unknown types (except call some of
them.)

>
> >>>>>> I presume Google Groups still has the first version, either here or in
> >>>>>> de.comp.lang.javascript.
> >>>>> Huh?  The first version(s) were posted here during the CWR
> >>>>> discussions.
> >>>> No, years before that.  IIRC, even years before Peter and you found cljs (at
> >>>> least before you were *posting* here).
> >>> That was certainly not isHostMethod as that is what I named my
> >>> function.
> >> Yes, I have never seen the need to make a difference there and I still don't
> >> see it.  Apparently Peter started to doubt, too.
>
> > What are you talking about?  [snip irrelevance]
>
> <news:bee08d6a-0f19-4da9...@h2g2000yqg.googlegroups.com>

If that's from today, I read it (and explained its relative relevance
a minute ago.)

>
> >>> Yours did not have the bit about "unknown" types, which
> >>> were apparently my discovery (every time I bring them up it seems
> >>> nobody knows what I am talking about.)
> >> I don't know whose discovery that was, but apparently you were the first to
> >> mention it on Usenet:
>
> >> <http://groups.google.com/group/comp.lang.javascript/msg/b34757abe55aa...>
>
> > Okay, but how can you not know what the difference is?
>
> I don't follow.

You snipped too hastily apparently. You said something about not
knowing the difference between testing for "unknown" or not. Big
difference there (safe vs. explosive.)

>
> >>> It is based on isMethodType from years back.
> >> How come that you missed isMethod() from years back although it has been
> >> referred to at least in the JSdoc™ of isMethodType() ever since?
>
> > Seems odd, but I'll take your word for it.  I seem to remember you
> > arguing about passing a reference to isHostMethod.  I see you have
> > written a sequel too.  Looks like a good idea, but please don't call
> > it areHostMethods as that one exists.
>
> It is going to be jsx.object.areMethods (and jsx.object.areHostMethods
> should it prove to be needed), so there is only a remote possibility for
> confusion.

Sounds good. My areHostMethods just allows for n string arguments
after the host object reference (e.g. gEBI, gEBTN, etc.) It's handy
when an app needs to check several methods of the same host object.

David Mark

unread,
Jul 2, 2009, 11:45:19 PM7/2/09
to
On Jul 2, 11:10 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>

Strange. I've never once needed an isArray method and I've written
damned near everything you can imagine for browsers.

> One needs to differentiate between
> testing foo.bar.baz, or foo.bar and foo.baz etc. without much fuss about
> objects and properties on call.  AFAICS only Arrays can provide that in
> these languages.

I didn't say there was anything wrong with arrays. Just design your
app so that you do not need to test for them explicitly. In other
words, if an "overloaded" function takes a string or an array
argument, test for the string (else assume an array.)

Thomas 'PointedEars' Lahn

unread,
Jul 3, 2009, 12:26:04 AM7/3/09
to
>>>> <http://bytes.com/groups/javascript/151754-when-window-location-url-ex....>

>>>> (Google doesn't seem to have it anymore, or the search function is borken..)
>>> If you mean isMethodType, then yes.
>> You really can search for "function isMethod" there if you want. Trust me.
>
> I believe you, but if it accepts references to host objects for the
> first argument, I'm confused by your prior position on isHostMethod.

4 years later in cljs ... and my code (style) had changed significantly;
much for the better, thanks to the discussions here.

>>>>>>>> I presume Google Groups still has the first version, either here or in
>>>>>>>> de.comp.lang.javascript.
>>>>>>> Huh? The first version(s) were posted here during the CWR
>>>>>>> discussions.
>>>>>> No, years before that. IIRC, even years before Peter and you found cljs (at
>>>>>> least before you were *posting* here).
>>>>> That was certainly not isHostMethod as that is what I named my
>>>>> function.
>>>> Yes, I have never seen the need to make a difference there and I still don't
>>>> see it. Apparently Peter started to doubt, too.
>>> What are you talking about? [snip irrelevance]
>> <news:bee08d6a-0f19-4da9...@h2g2000yqg.googlegroups.com>
>
> If that's from today, I read it (and explained its relative relevance
> a minute ago.)

That's just too cryptic for me to parse right now.

>>>>> Yours did not have the bit about "unknown" types, which
>>>>> were apparently my discovery (every time I bring them up it seems
>>>>> nobody knows what I am talking about.)
>>>> I don't know whose discovery that was, but apparently you were the first to
>>>> mention it on Usenet:

>>>> <http://groups.google.com/group/comp.lang.javascript/msg/b34757abe55aa....>


>>> Okay, but how can you not know what the difference is?
>> I don't follow.
>
> You snipped too hastily apparently. You said something about not
> knowing the difference between testing for "unknown" or not.

No, I didn't.

BTW, I just noticed that I searched for "typeof unknown" and ended up
referring to the wrong posting. That which I referred to does not contain
"unknown" at all.

First mention of "unknown" as typeof result here by Thor Larholm in 2000:

<http://groups.google.com/group/comp.lang.javascript/msg/13c5162bcbac2434?hl=en&dmode=source>

First mention of "unknown" on host objects here by James D. Rofkar in 2001:

<http://groups.google.com/group/comp.lang.javascript/msg/5e638bd2abc186d1?hl=en&dmode=source&output=gplain>

First mention of "unknown" objects throwing an exception on property access
by John Irish in 2001:

<http://groups.google.com/group/comp.lang.javascript/msg/2de58f52773542bc?hl=en&dmode=source&output=gplain>

Incidentally, that research (keywords: typeof unknown
group:comp.lang.javascript) has showed up a number of interesting postings
in the past about "unknown" objects and their history in MSHTML.

> Big difference there (safe vs. explosive.)

Of course.

>>>>> It is based on isMethodType from years back.
>>>> How come that you missed isMethod() from years back although it has been
>>>> referred to at least in the JSdoc™ of isMethodType() ever since?
>>> Seems odd, but I'll take your word for it. I seem to remember you
>>> arguing about passing a reference to isHostMethod. I see you have
>>> written a sequel too. Looks like a good idea, but please don't call
>>> it areHostMethods as that one exists.
>> It is going to be jsx.object.areMethods (and jsx.object.areHostMethods
>> should it prove to be needed), so there is only a remote possibility for
>> confusion.
>
> Sounds good. My areHostMethods just allows for n string arguments
> after the host object reference (e.g. gEBI, gEBTN, etc.) It's handy
> when an app needs to check several methods of the same host object.

As discussed, that approach has the drawback that the method needs
to be called repeatedly if "properties of properties" need to be tested.

David Mark

unread,
Jul 3, 2009, 12:52:57 AM7/3/09
to
On Jul 3, 12:26 am, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:

[smip]

>
> First mention of "unknown" as typeof result here by Thor Larholm in 2000:
>

> <http://groups.google.com/group/comp.lang.javascript/msg/13c5162bcbac2...>


>
> First mention of "unknown" on host objects here by James D. Rofkar in 2001:
>

> <http://groups.google.com/group/comp.lang.javascript/msg/5e638bd2abc18...>


>
> First mention of "unknown" objects throwing an exception on property access
> by John Irish in 2001:
>

> <http://groups.google.com/group/comp.lang.javascript/msg/2de58f5277354...>

Perhaps I never brought up the pre-2000 Mac IE object that lead me to
use typeof for feature detection. I think the first time I discussed
it here was in response to a query about a window.external method and
that would have been in 2007. I came up with the isMethod
augmentation (isHostMethod) shortly thereafter. I'm pretty sure I was
the first to mention that ActiveX was the culprit and "unknown" likely
referred to the IUnknown interface.

>
> Incidentally, that research (keywords: typeof unknown
> group:comp.lang.javascript) has showed up a number of interesting postings
> in the past about "unknown" objects and their history in MSHTML.

Probably wouldn't interest me at this point. :)

>
> > Big difference there (safe vs. explosive.)
>
> Of course.
>
> >>>>> It is based on isMethodType from years back.
> >>>> How come that you missed isMethod() from years back although it has been
> >>>> referred to at least in the JSdoc™ of isMethodType() ever since?
> >>> Seems odd, but I'll take your word for it.  I seem to remember you
> >>> arguing about passing a reference to isHostMethod.  I see you have
> >>> written a sequel too.  Looks like a good idea, but please don't call
> >>> it areHostMethods as that one exists.
> >> It is going to be jsx.object.areMethods (and jsx.object.areHostMethods
> >> should it prove to be needed), so there is only a remote possibility for
> >> confusion.
>
> > Sounds good.  My areHostMethods just allows for n string arguments
> > after the host object reference (e.g. gEBI, gEBTN, etc.)  It's handy
> > when an app needs to check several methods of the same host object.
>
> As discussed, that approach has the drawback that the method needs
> to be called repeatedly if "properties of properties" need to be tested.

That's another function (which I think you posted recently.)

wilq

unread,
Jul 3, 2009, 4:24:13 AM7/3/09
to
On Jul 2, 10:40 pm, Dr J R Stockton <reply0...@merlyn.demon.co.uk>
wrote:
> In comp.lang.javascript message <4A4CB578.9050...@PointedEars.de>, Thu,
> 2 Jul 2009 15:26:16, Thomas 'PointedEars' Lahn <PointedE...@web.de>

> posted:
>
> >+new Date() is arguably more runtime-efficient than (new Date()).getTime(),
> >another explicit method call (untested).  Historically, type-converting
> >operations have been more runtime-efficient than type-converting calls.
>
> An excellent demonstration of the relative powers of arguing and of
> getting actual facts.
>
> Time taken by D.getTime(), as percentage of time for +D, if I tested
> correctly :
>
>         IE 7            85
>         FF 3.0.11       85
>         Op 9.64         43
>         Safari 4.0      65
>         Chrome 2.0      29
>
> Testing with new Date() gives rather irregular results, presumably
> because of the many OS calls; but supports the conclusion.
>
> Using getTime calls explicitly for use of that Method; using unary +
> calls implicitly for the use of method valueOf, presumably the same
> code, and also does the "return a Number" operation, apparently not
> optimising it out.
>
> But I suggest that testing is not needed to see that unary + is faster
> to type and to read.
>
> Did that speed difference not get mentioned here before, not so long
> ago?
>
> --
>  (c) John Stockton, nr London, UK.    ?...@merlyn.demon.co.uk     Turnpike v6.05.

>  Web  <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
>  PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
>  Dates - miscdate.htm estrdate.htm js-dates.htm pas-time.htm critdate.htm etc.


Well basically as all of us knows (new Date()).getTime are not very
reliable on short timings. This is where iteration comes in. If the
time produced because of iteration will be really long (i.e. few
seconds), you will minimise all influence from (new Date()).getTime()
- that is an idea of doing any tests... So even moving to +(new Date)
will not change alot in tests right now... Please try...

wilq

unread,
Jul 3, 2009, 4:49:45 AM7/3/09
to
On Jul 2, 3:26 pm, Thomas 'PointedEars' Lahn <PointedE...@web.de>
wrote:
> >>> }

> >> var someTemp;
> >> var iterationCount=500000;
> >> Several script engines might consider a script with that many
> >> iterations as blocking, depending on accumulated runtime.
>
> > Yes of course - because of this is an argument that you can change.
>
> The question raised by this is: Is it realistic for an app to perform that
> many calls of isMethod() consecutively?  If not, the number is too high.
> And as it is too high (IMHO), differences in runtime efficiency between
> these approaches are in fact not as important as you present them to be.
> And, as I said, efficiency is not everything.  To begin with, any approach
> should balance efficiency against reliability.

For real working app ? Well probably you wont fire that function
500000 in real app, but results I get that it can be even to 3 times
slower is just something that might be important for me if I planning
to create wig app that uses alot of javascript code that I want to
make it runing as fast as possible. This reminds me a case when
someone want to follow standard in className for DOM elements, where
it says that you can use whitespaces to separate classes. This means
that you could put tab or enter there. Thats great but to put that
idea inside function instead of splitting className over space, you
need to split that using regexp. This function was fired many times in
project and removing regexp just makes it working alot faster. Those
small diffrences of performance DO matters if its beeing called many
times in project. 1ms or 3ms is no diffrence, count that * 1000, and
you have 1s vs 3s. 1000 of calling this method in really big app is -
you think - much or not ?

> >>> function reg(){ for (var i=0;i<iterationCount;i++) { someTemp =
> >>> regExp.test(a); someTemp = regExp.test(b);
> >> Cheater! :)  Here both tests will be performed always (worst case), but
> >> that is not necessary with /^\s*unknown\s*/i and
> >> /^\s*(object|function)\s*/i as in `is(Host)Method'.  Hence my reversing
> >> the order of tests since; shortcut evaluation of boolean expressions
> >> will do the rest.
>
> > Cheater ? I dont think so - I compare here cases that will occur mostly -
> > "function" and "object". But I do the same for string solution
>
> No, you don't.
>
> > so there is no cheat.  In fact its very fair comparsion in mine opinion.
>
> Hardly.  Fair would be
>
>   someTemp = regExp.test(a) || regExp.test(b);
>

Think, in every iteration I doing two tests. Like you would fire
function twice.


someTemp = regExp.test(a);
someTemp = regExp.test(b);

First part of this is best case, second is worst case (for string
comparsion). This cases almost does not matter for regexp, but this is
still behaves as a twice execution of the function that I profiling.

This concept:

someTemp = regExp.test(a) || regExp.test(b);

is wrong because it works more like a one iteration... first part
before || will always return true because I assume 'a' to be string
containing "function" or "object" (I remove stage of type conversion
assuming that I have a string in return). Second part will never be
fired in that circumstances..... Dont you see that ?

> > I open to see a best + worst case as you said that is in string
> > comparsion.
>
> The problem is that you are picking the cases that are in your favor,
> IOW you *are* cheating here.
>

I pick two cases - "function" and "object" what is wrong with those
cases ? Please propose then cases that will make your statements true.
But dont try to cheat like with this "someTemp = regexp || regexp"

> >>>   }
> >>> }
> >>> function str()
> >>>   for (var i=0;i<iterationCount;i++)
> >>>   {
> >>>     someTemp = (a==="function"||a==="object");
> >> Cheater! :)  With your input, the second operand will never be
> >> evaluated, and type conversion does not take place (best case).
>
> > Yes - this is a idea of this test.
>
> This test is biased(, then).

I think that you dont get whole idea..

> > So here I also did the test. And in post before I explained why this
> > string comparsion would be better - exacly that if a first boolean
> > structure will be true, second wont be computed at all. You can try
> > diffrent cases (both worst, both good) with a="object", b="object" and
> > a="function", b="function" to see that this is still faster than
> > regexp...
>
> *Maybe* so, on *your* computer, *without RegExp optimization*.  But it is
> on *all* computers (running non-obsolete implementations) *less reliable*.

So on other computers with regexp optimalization it will be __faster__
that simple string comparsion?

>
> I have posted and pointed to the current (abridged) isMethod()
> implementation already; now you only need to notice that.
>

Maybe I did not notice your test case and profiling testing.. Please
be so kind and point me directly where exacly are this test/profiling
function.

Dr J R Stockton

unread,
Jul 4, 2009, 2:08:58 PM7/4/09
to
In comp.lang.javascript message <b683c06c-1221-42c6-b91f-d40e09e23b1d@y9
g2000yqg.googlegroups.com>, Fri, 3 Jul 2009 01:24:13, wilq
<wil...@gmail.com> posted:

>On Jul 2, 10:40�pm, Dr J R Stockton <reply0...@merlyn.demon.co.uk>
>wrote:
>> In comp.lang.javascript message <4A4CB578.9050...@PointedEars.de>, Thu,
>> 2 Jul 2009 15:26:16, Thomas 'PointedEars' Lahn <PointedE...@web.de>
>> posted:
>>
>> >+new Date() is arguably more runtime-efficient than (new Date()).getTime(),
>> >another explicit method call (untested). �Historically, type-converting
>> >operations have been more runtime-efficient than type-converting calls.

>> But I suggest that testing is not needed to see that unary + is faster
>> to type and to read.
>>
>> Did that speed difference not get mentioned here before, not so long
>> ago?
>>
>> --
>> �(c)

>> ...

>Well basically as all of us knows (new Date()).getTime are not very
>reliable on short timings. This is where iteration comes in. If the
>time produced because of iteration will be really long (i.e. few
>seconds), you will minimise all influence from (new Date()).getTime()
>- that is an idea of doing any tests... So even moving to +(new Date)
>will not change alot in tests right now... Please try...


A well-written newsreader should have trimmed that sig from the quote;
but not using one is not adequate justification for leaving it in.

Firstly, who said that (new Date()).getTime() was used *to perform the
timings*? After all, there is at least one other way of doing it,
without using values of new Date() at all.

Secondly, who said that the durations measured were short? Those are
percentages, and you have no way of telling the overall number of
seconds measured.

Evidently you are not a metrologist.

I often advise people to read messages carefully before posting
"answers"; in this case that hardly seems worth-while.

YGCIB.

--
(c) John Stockton, nr London UK. ???@merlyn.demon.co.uk Turnpike v6.05 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQish topics, acronyms, & links.
Check boilerplate spelling -- error is a public sign of incompetence.
Never fully trust an article from a poster who gives no full real name.

Jorge

unread,
Jul 4, 2009, 3:20:03 PM7/4/09
to
On Jul 4, 8:08 pm, Dr J R Stockton <reply0...@merlyn.demon.co.uk>
wrote:
> (...)

> Firstly, who said that (new Date()).getTime() was used *to perform the
> timings*?  After all, there is at least one other way of doing it,
> without using values of new Date() at all.
> (...)

How, please ?

TIA,
--
Jorge.

kangax

unread,
Jul 6, 2009, 6:06:10 PM7/6/09
to
Thomas 'PointedEars' Lahn wrote:
> kangax wrote:
>> Thomas 'PointedEars' Lahn wrote:
[...]

>>> for (var i = 1; i < len; i++)
>>> {
>>> var
>>> p = arguments[i],
>>> p_is_Array = (i === len - 1 && jsx.object.isArray(p)),
>>> origP = p;
>>>
>>> for (var j = (p_is_Array && origP.length || 1); j--;)
>>> {
>>> if (p_is_Array) p = origP[j];
>>>
>>> t = typeof o[p];
>>>
>>> // ...
>>> }
>>> }
>>>
>>> Did I miss something?
>> Looks good. You could take `len - 1` out of the loop as well
>
> Yes, but I don't think subtraction by 1 justifies introducing another variable.

Fair enough.

>
>> as avoid resolving `jsx.object.isArray` over and over,
>
> Will do (as done elsewhere). However, it would have to be v.isArray(...)
> in any case, or extensive rewrites might be needed if I change how
> jsx.object.isArray() gets to the jsx.object.isInstanceOf() that it calls.

Hmm. I was thinking of something like `var isArray =
jsx.object.isArray`. So I take it that `isArray` is using `this` to
reference `jsx.object`? If so, then introducing extra variable to go
from double property access to single doesn't seem justified.

[...]

Theoretically speaking, I might get an object from a 3rd party script
and I might not know what that object is (if it happens to be an array,
then that array could very well be created in some frame used by a 3rd
party script).

>
>> What if that frame was removed from the document and I don't have a
>> reference to its global `Array` property?
>
> That's a good argument. Question remains if such an Array object would even
> continue working, though.

IIRC, an array object was fully functional after removing an iframe it
originated from (perhaps Global Object of that iframe was still in
memory, due to existent references). Can't be fully sure though, will
need to test later on.

>
>>>> As far as type converting host objects (not methods!), didn't we just
>>>> have a conversation about it where you said that it should be safe to do so?
>>>>
>>>> [...]
>>>> <http://groups.google.com/group/comp.lang.javascript/msg/4df3cf9b5a7bd60f>
>>>>
>>>> Or am I missing something?
>>> Yes, I was talking about return values of standardized methods there.
>> I'm pretty sure we were talking about `lastChild`/`firstChild` as an
>> operand in `if`/`while` expression (when "emptying" element contents).
>
> You're right. However, I would submit that there is still a difference
> between a property of a host object that must strictly follow specification,
> and a host-defined property of the global object or a property of a host
> object, that does not strictly follows implementation (for historical reasons).

So `Node::firstChild` is part of a DOM standard, but `Window::document`
is not (because global `window` is not part of a standard). Am I
understanding you correctly?

>
>> `lastChild` is specified to be of type Node (or should I say - its
>> return value is specified to implement Node interface, or `null`).
>> `document`, in its turn, is specified to be of type Document, which
>> inherits from Node. Therefore type conversion on `lastChild` and
>> `window.document` carries similar risk,
>
> That might seem awkward at first, but the untested standalone `document' is
> indeed riskier than the untested `window.document' (given `window' doesn't
> fail, of course). Failed identifier resolution throws an exception
> everywhere and always. There is also the remote possibility of a `document'
> property in the scope chain that does not refer to a document object.

This I agree with. I was actually comparing `<nodeRef>.firstChild` to
`window.document` (or rather - `<Global Object>.window.document`), not
just `document`.

>
>> from what I can see (unless objects implementing exactly
>> Document interface would be the ones to throw, and not
>> those that implement Node only; but that would be just
>> plain silly)
>
> It is not the value but the existence of the property that matters here.

Just to make things clear, I am interested in your opinion about
boolean- type conversion of host objects (not methods). You mentioned
that it is safe to type convert `<nodeRef>.firstChild/lastChild`. Now
I'm trying to figure out whether it is safe to type-convert other host
objects, such as `document`;

e.g. - `if (<global object>.window.document) { ... }`.

>
>>>>> TypeError). Therefore, I suggested allowing for the evaluation of primitive
>>>>> strings that match /Identifier/ or property accessor for the first argument,
>>>>> per flag so that methods of String objects could still be tested. What do
>>>>> you think about that?
>>>> What do you mean by "flag" and "per flag"?
>> [snip `tryThis`]
>>
>>> /* ... */
>>>
>>> var isMethod = jsx.object.isMethod = jsx.object.areMethods = function(o, p) {
>>> var len = arguments.length;
>>> if (len < 1) return false;
>> Shouldn't return value be other than boolean, to indicate that something
>> went wrong and differentiate from cases when tested method isn't
>> recognized as "method"? (e.g. is "unknown").
>
> A possibility; but what should it be? These days I would even consider
> throwing exceptions instead (guarded with eval(), of course).

I usually use `null`.

>
>>> var
>>> rxUnknown = /^\s*unknown\s*$/i,
>>> rxMethod = /^\s*(function|object)\s*$/i,
>> Why initialize these on every method invocation?
>
> Pretty inefficient, I know. I'm working on it.
>
>>> t = typeof o;
>>>
>>> /* ... */
>>>
>>> /*
>>> * Refined support for strings; evaluating them always would
>>> * preclude String objects from being tested for methods.
>>> * Try to warn if a primitive string value is passed and the
>>> * required flag is not set (default).
>>> */
>>> if (t === "string")
>>> {
>>> if (arguments.callee.evalStrings)
>> I wouldn't use `arguments.callee` if possible (to take advantage of
>> environments which optimize).
>
> If the property should not be owned by another object, `arguments.callee' is
> a necessity as long as there cannot be a unique identifier (for backwards
> compatibility) and user-defined read-only properties everywhere are still on
> the wish list. And I really like using function objects as containers for
> function-related properties.

I would use a closure (into which things like `rxUnknown` and `rxMethod`
can go), and if closure is out of the question, use function object
itself, but access it via identifier, not `arguments.callee`.

--
kangax

David Mark

unread,
Jul 8, 2009, 2:23:52 AM7/8/09
to
On Jul 6, 6:06 pm, kangax <kan...@gmail.com> wrote:

[snip]

>
> Just to make things clear, I am interested in your opinion about
> boolean- type conversion of host objects (not methods). You mentioned
> that it is safe to type convert `<nodeRef>.firstChild/lastChild`. Now
> I'm trying to figure out whether it is safe to type-convert other host
> objects, such as `document`;
>
> e.g. - `if (<global object>.window.document) { ... }`.
>
>

[snip]

Depends. Consult isHostObjectProperty. The "unknown" properties
known *not* to be implemented as methods are unusable.

An example has been demonstrated in the past where an element orphaned
by an innerHTML assignment will have an "unknown" offsetParent
property. Hard to say why, but it is certainly a useless property at
that point (even an access throws an exception.)

That reminds me, always use typeof to test string properties as well
(isHostStringProperty?) In at least some builds of IE7, news link
(NNTP protocol) href properties (normally strings) are "unknown." Go
figure.

And then there are the truly unknown problems that nobody has
discovered (or invented) yet. There may be host objects out there
that have "poison" types or "don't tread on me" types. Such surprises
are best avoided as well (at least until they can be studied.) The
isHost* functions (or methods in most cases) are very simple, but
quite calculated in what they allow. An easy rule for choosing
between the main two is to use isHostMethod for anything you plan to
call. Use isHostObjectProperty for virtually everything else. I
can't even remember what the third one was (host collections?) I know
I never use it.

kangax

unread,
Jul 8, 2009, 8:57:16 AM7/8/09
to
David Mark wrote:
> On Jul 6, 6:06 pm, kangax <kan...@gmail.com> wrote:
>
> [snip]
>
>> Just to make things clear, I am interested in your opinion about
>> boolean- type conversion of host objects (not methods). You mentioned
>> that it is safe to type convert `<nodeRef>.firstChild/lastChild`. Now
>> I'm trying to figure out whether it is safe to type-convert other host
>> objects, such as `document`;
>>
>> e.g. - `if (<global object>.window.document) { ... }`.
>>
>>
>
> [snip]
>
> Depends. Consult isHostObjectProperty. The "unknown" properties
> known *not* to be implemented as methods are unusable.
>
> An example has been demonstrated in the past where an element orphaned
> by an innerHTML assignment will have an "unknown" offsetParent
> property. Hard to say why, but it is certainly a useless property at
> that point (even an access throws an exception.)

Doesn't have to be orphaned by an `innerHTML`, if I'm not mistaken. I
remember writing a feature test for this particular bug in Prototype:

<http://github.com/kangax/prototype/blob/a223833c8b49ae55f03b1e1a3a5b7e9fb647c139/src/dom/dom.js#L2046>

(Don't mind all the mess around in that file.)

Also note that it is lack of "parentNode" that seems to be the root of
the issue, not the orphanness of an element per se.

>
> That reminds me, always use typeof to test string properties as well
> (isHostStringProperty?) In at least some builds of IE7, news link
> (NNTP protocol) href properties (normally strings) are "unknown." Go
> figure.
>
> And then there are the truly unknown problems that nobody has
> discovered (or invented) yet. There may be host objects out there
> that have "poison" types or "don't tread on me" types. Such surprises
> are best avoided as well (at least until they can be studied.) The
> isHost* functions (or methods in most cases) are very simple, but
> quite calculated in what they allow. An easy rule for choosing
> between the main two is to use isHostMethod for anything you plan to
> call. Use isHostObjectProperty for virtually everything else. I

Well, IE can return "unknown" for `lastChild` as well, so element's
contents would need to be emptied as:

while (isHostObjectProperty(element, "lastChild")) {
element.removeChild(element.lastChild);
}

Btw, looking at MyLib.js, I see that you do indeed use
`isHostObjectProperty` for testing `firstChild`, although it's being
used inconsistently and some of the checks seem to be missing (e.g.
`getElementText` has it, but `setElementText` doesn't).

I also see that you never test `firstChild` with `isHostObjectProperty`
at runtime (I assume for perf. reasons?). You test
`document.documentElement`'s `firstChild` upfront and assume that
`firstChild` of any other DOM element doesn't blow up. Is this really a
safe assumption to make?

On a side note, it would be nice if we could automate testing of
`isHostMethod` coverage. Maybe create an artificial environment where
host objects properties would be defined via error-throwing setters.
Then run test suite through all unit tests and ensure that nothing blows
up (i.e. that there's no plain host objects properties access, and that
everything is proxied through `isHostObjectProperty`)

--
kangax

Peter May

unread,
Jul 8, 2009, 10:50:16 AM7/8/09
to
kangax pisze:

> Well, IE can return "unknown" for `lastChild` as well, so element's
> contents would need to be emptied as:
>
> while (isHostObjectProperty(element, "lastChild")) {
> element.removeChild(element.lastChild);
> }

Btw, for clearing all nodes I'm using something like this:

// elm - this is element to be cleared
var e = elm.cloneNode(false);
elm.parentNode.replaceChild(e, elm);
elm = e;

In the past, I compared to the results of both speed and code that
indicated above was much faster. Even than innerHTML = "". However,
there may be what is proposed is not good. Maybe someone will react.

--
Peter

Peter May

unread,
Jul 8, 2009, 10:53:36 AM7/8/09
to
Peter May pisze:

And for remove element just add to the end:

elm.parentNode.removeChild(elm);

--
Peter

kangax

unread,
Jul 8, 2009, 12:11:39 PM7/8/09
to

Yes, this "method" is usually faster if you don't care about "lost"
event listeners of original element.

There are some problems with `cloneNode`, though. IIRC, cloning form
elements doesn't "copy" user-set values of containing input elements in
IE (not sure which versions, probably <=6).

I remember I first found this bug in Garrett's APE (should be fixed now).

--
kangax

Garrett Smith

unread,
Jul 8, 2009, 12:42:35 PM7/8/09
to
kangax wrote:
> Peter May wrote:
>> kangax pisze:
>>> Well, IE can return "unknown" for `lastChild` as well, so element's
>>> contents would need to be emptied as:
>>>

When does that happen?

>>> while (isHostObjectProperty(element, "lastChild")) {
>>> element.removeChild(element.lastChild);
>>> }
>>

All those extra function calls would slow the function down.

>> Btw, for clearing all nodes I'm using something like this:
>>
>> // elm - this is element to be cleared
>> var e = elm.cloneNode(false);
>> elm.parentNode.replaceChild(e, elm);
>> elm = e;
>>
>> In the past, I compared to the results of both speed and code that
>> indicated above was much faster. Even than innerHTML = "". However,
>> there may be what is proposed is not good. Maybe someone will react.
>>
>
> Yes, this "method" is usually faster if you don't care about "lost"
> event listeners of original element.

That is true for all properties that don't reflect.

>
> There are some problems with `cloneNode`, though. IIRC, cloning form
> elements doesn't "copy" user-set values of containing input elements in
> IE (not sure which versions, probably <=6).
>

Would be nice to have a DOM method for that and serialization.

e.g.
var formClone = form.cloneObject(); // Copy state.
var formHTML = form.toHTML(); // Serialize state.

> I remember I first found this bug in Garrett's APE (should be fixed now).
>

It should, but I'm not sure if it actually is.

Garrett
--
comp.lang.javascript FAQ: http://jibbering.com/faq/

kangax

unread,
Jul 8, 2009, 12:54:50 PM7/8/09
to
Garrett Smith wrote:
> kangax wrote:
>> Peter May wrote:
>>> kangax pisze:
>>>> Well, IE can return "unknown" for `lastChild` as well, so element's
>>>> contents would need to be emptied as:
>>>>
>
> When does that happen?

When `lastChild` references an element/object with "unknown" typeof in
IE, I suppose.

>
>>>> while (isHostObjectProperty(element, "lastChild")) {
>>>> element.removeChild(element.lastChild);
>>>> }
>>>
>
> All those extra function calls would slow the function down.

That much is obvious. I'm pretty sure that's the main reason MyLib.js is
performing such testing upfront and inferring certain support on other
elements. Whether this is a safe thing to do is a different topic. IIRC,
PointedEars was saying it's not.

>
>>> Btw, for clearing all nodes I'm using something like this:
>>>
>>> // elm - this is element to be cleared
>>> var e = elm.cloneNode(false);
>>> elm.parentNode.replaceChild(e, elm);
>>> elm = e;
>>>
>>> In the past, I compared to the results of both speed and code that
>>> indicated above was much faster. Even than innerHTML = "". However,
>>> there may be what is proposed is not good. Maybe someone will react.
>>>
>>
>> Yes, this "method" is usually faster if you don't care about "lost"
>> event listeners of original element.
>
> That is true for all properties that don't reflect.

What do you mean by "properties that don't reflect"?

[...]

--
kangax

Peter

unread,
Jul 8, 2009, 2:15:37 PM7/8/09
to
kangax pisze:

> Peter May wrote:
>> kangax pisze:
>>> Well, IE can return "unknown" for `lastChild` as well, so element's
>>> contents would need to be emptied as:
>>>
>>> while (isHostObjectProperty(element, "lastChild")) {
>>> element.removeChild(element.lastChild);
>>> }
>>
>> Btw, for clearing all nodes I'm using something like this:
>>
>> // elm - this is element to be cleared
>> var e = elm.cloneNode(false);
>> elm.parentNode.replaceChild(e, elm);
>> elm = e;
>>
>> In the past, I compared to the results of both speed and code that
>> indicated above was much faster. Even than innerHTML = "". However,
>> there may be what is proposed is not good. Maybe someone will react.
>>
>
> Yes, this "method" is usually faster if you don't care about "lost"
> event listeners of original element.

I found some information that "Only events added as attributes are
cloned. Not those added using AddEventListener."

http://tinyurl.com/m2tgyr

But I can't find some more information in Google. Maybe someone could
write something more about above sentence.

--
Peter

David Mark

unread,
Jul 8, 2009, 5:52:30 PM7/8/09
to
On Jul 8, 8:57 am, kangax <kan...@gmail.com> wrote:
> David Mark wrote:
> > On Jul 6, 6:06 pm, kangax <kan...@gmail.com> wrote:
>
> > [snip]
>
> >> Just to make things clear, I am interested in your opinion about
> >> boolean- type conversion of host objects (not methods). You mentioned
> >> that it is safe to type convert `<nodeRef>.firstChild/lastChild`. Now
> >> I'm trying to figure out whether it is safe to type-convert other host
> >> objects, such as `document`;
>
> >> e.g. - `if (<global object>.window.document) { ... }`.
>
> > [snip]
>
> > Depends.  Consult isHostObjectProperty.  The "unknown" properties
> > known *not* to be implemented as methods are unusable.
>
> > An example has been demonstrated in the past where an element orphaned
> > by an innerHTML assignment will have an "unknown" offsetParent
> > property.  Hard to say why, but it is certainly a useless property at
> > that point (even an access throws an exception.)
>
> Doesn't have to be orphaned by an `innerHTML`, if I'm not mistaken. I
> remember writing a feature test for this particular bug in Prototype:
>
> <http://github.com/kangax/prototype/blob/a223833c8b49ae55f03b1e1a3a5b7...>

It crashed my browser again (preceded by a large black box on the
document and my CPU fans going through the roof.) No thanks.

>
> (Don't mind all the mess around in that file.)

Never got to see it.

>
> Also note that it is lack of "parentNode" that seems to be the root of
> the issue, not the orphanness of an element per se.

I fail to see the difference (and can't pin down "orphanness" anyway.)

>
>
>
> > That reminds me, always use typeof to test string properties as well
> > (isHostStringProperty?)  In at least some builds of IE7, news link
> > (NNTP protocol) href properties (normally strings) are "unknown."  Go
> > figure.
>
> > And then there are the truly unknown problems that nobody has
> > discovered (or invented) yet.  There may be host objects out there
> > that have "poison" types or "don't tread on me" types.  Such surprises
> > are best avoided as well (at least until they can be studied.)  The
> > isHost* functions (or methods in most cases) are very simple, but
> > quite calculated in what they allow.  An easy rule for choosing
> > between the main two is to use isHostMethod for anything you plan to
> > call.  Use isHostObjectProperty for virtually everything else.  I
>
> Well, IE can return "unknown" for `lastChild` as well, so element's
> contents would need to be emptied as:
>
> while (isHostObjectProperty(element, "lastChild")) {
>    element.removeChild(element.lastChild);
>
> }

Not really. Your app should never present such a possibility.
Trouble comes when you try to write a library for every occasion (e.g.
Prototype.)

>
> Btw, looking at MyLib.js, I see that you do indeed use
> `isHostObjectProperty` for testing `firstChild`, although it's being

In one-off feature detection I am sure.

> used inconsistently and some of the checks seem to be missing (e.g.
> `getElementText` has it, but `setElementText` doesn't).

I assume you mean used inconsistently in that some of the checks are
missing. No doubt about it. Was slapped together in about two months
and I lost interest soon afterward. Turned out to be the magic
formula! ;)

>
> I also see that you never test `firstChild` with `isHostObjectProperty`
> at runtime (I assume for perf. reasons?).

Should fail immediately. The calling app blew it at that point.

> You test
> `document.documentElement`'s `firstChild` upfront and assume that
> `firstChild` of any other DOM element doesn't blow up. Is this really a
> safe assumption to make?

That's not testing for the IE explosion issue (just that the property
exists.)

>
> On a side note, it would be nice if we could automate testing of
> `isHostMethod` coverage. Maybe create an artificial environment where
> host objects properties would be defined via error-throwing setters.

Be my guest.

> Then run test suite through all unit tests and ensure that nothing blows
> up (i.e. that there's no plain host objects properties access, and that
> everything is proxied through `isHostObjectProperty`)

Well, you don't normally need to be so thorough with the testing.
Often it is good to let things fail immediately. I laugh when I see
that "unspecified error" on a job site. The fix is never to add a
call to isHostObjectProperty (it's to fix whatever made the mistake of
passing an "orphaned" element.)

David Mark

unread,
Jul 8, 2009, 5:55:38 PM7/8/09
to
On Jul 8, 12:42 pm, Garrett Smith <dhtmlkitc...@gmail.com> wrote:
> kangax wrote:
> > Peter May wrote:
> >> kangax pisze:
> >>> Well, IE can return "unknown" for `lastChild` as well, so element's
> >>> contents would need to be emptied as:
>
> When does that happen?

Again? IE can return "unknown" for any host object property at any
given time. It's particularly true of elements, as has been discussed
here many times. I told you the keywords to search last time you
asked (so search for your query.)

[snip]

kangax

unread,
Jul 8, 2009, 7:00:35 PM7/8/09
to
David Mark wrote:
> On Jul 8, 8:57 am, kangax <kan...@gmail.com> wrote:
>> David Mark wrote:
>>> On Jul 6, 6:06 pm, kangax <kan...@gmail.com> wrote:
>>> [snip]
>>>> Just to make things clear, I am interested in your opinion about
>>>> boolean- type conversion of host objects (not methods). You mentioned
>>>> that it is safe to type convert `<nodeRef>.firstChild/lastChild`. Now
>>>> I'm trying to figure out whether it is safe to type-convert other host
>>>> objects, such as `document`;
>>>> e.g. - `if (<global object>.window.document) { ... }`.
>>> [snip]
>>> Depends. Consult isHostObjectProperty. The "unknown" properties
>>> known *not* to be implemented as methods are unusable.
>>> An example has been demonstrated in the past where an element orphaned
>>> by an innerHTML assignment will have an "unknown" offsetParent
>>> property. Hard to say why, but it is certainly a useless property at
>>> that point (even an access throws an exception.)
>> Doesn't have to be orphaned by an `innerHTML`, if I'm not mistaken. I
>> remember writing a feature test for this particular bug in Prototype:
>>
>> <http://github.com/kangax/prototype/blob/a223833c8b49ae55f03b1e1a3a5b7...>
>
> It crashed my browser again (preceded by a large black box on the
> document and my CPU fans going through the roof.) No thanks.

Jeez. It never crashed on me. Which browser/OS are you using?

Here's a plain "js" file. Search for "var
OFFSET_PARENT_THROWS_ON_ORPHANED_ELEMENT"

http://github.com/kangax/prototype/raw/a223833c8b49ae55f03b1e1a3a5b7e9fb647c139/src/dom/dom.js

Not that there's something extraordinary there.

>
>> (Don't mind all the mess around in that file.)
>
> Never got to see it.
>
>> Also note that it is lack of "parentNode" that seems to be the root of
>> the issue, not the orphanness of an element per se.
>
> I fail to see the difference (and can't pin down "orphanness" anyway.)

Orphaned element is the one that is not in a document at a given time.
In other words, you won't get to its `ownerDocument` by following its
`parentNode` chain.

var divEl = document.createElement('div');
var spanEl = document.createElement('span');
divEl.appendChild(spanEl);

At this point `divEl` has no `parentNode` and is orphaned from the
document. At the same time, `spanEl` *has `parentNode`* but is still
orphaned from the document.

If I'm correct, IE won't throw on `spanEl.offsetParent`, but will throw
on `divEl.offsetParent`, even though both elements are orphaned ones. I
assume this missing `parentNode` is what causes IE to throw (maybe
`offsetParent` tries to call one of its members internally or smth.)

Does this make things clearer?

>
>>
>>
>>> That reminds me, always use typeof to test string properties as well
>>> (isHostStringProperty?) In at least some builds of IE7, news link
>>> (NNTP protocol) href properties (normally strings) are "unknown." Go
>>> figure.
>>> And then there are the truly unknown problems that nobody has
>>> discovered (or invented) yet. There may be host objects out there
>>> that have "poison" types or "don't tread on me" types. Such surprises
>>> are best avoided as well (at least until they can be studied.) The
>>> isHost* functions (or methods in most cases) are very simple, but
>>> quite calculated in what they allow. An easy rule for choosing
>>> between the main two is to use isHostMethod for anything you plan to
>>> call. Use isHostObjectProperty for virtually everything else. I
>> Well, IE can return "unknown" for `lastChild` as well, so element's
>> contents would need to be emptied as:
>>
>> while (isHostObjectProperty(element, "lastChild")) {
>> element.removeChild(element.lastChild);
>>
>> }
>
> Not really. Your app should never present such a possibility.
> Trouble comes when you try to write a library for every occasion (e.g.
> Prototype.)

Not sure what you mean. How else will my helper clear element's
contents? You either use `isHostObjectProperty` at runtime when
accessing `firstChild`, or you use boolean type conversion and face a
chance of blow up.

>
>> Btw, looking at MyLib.js, I see that you do indeed use
>> `isHostObjectProperty` for testing `firstChild`, although it's being
>
> In one-off feature detection I am sure.
>
>> used inconsistently and some of the checks seem to be missing (e.g.
>> `getElementText` has it, but `setElementText` doesn't).
>
> I assume you mean used inconsistently in that some of the checks are
> missing. No doubt about it. Was slapped together in about two months

That's what I meant.

> and I lost interest soon afterward. Turned out to be the magic
> formula! ;)
>
>> I also see that you never test `firstChild` with `isHostObjectProperty`
>> at runtime (I assume for perf. reasons?).
>
> Should fail immediately. The calling app blew it at that point.
>
>> You test
>> `document.documentElement`'s `firstChild` upfront and assume that
>> `firstChild` of any other DOM element doesn't blow up. Is this really a
>> safe assumption to make?
>
> That's not testing for the IE explosion issue (just that the property
> exists.)

That's what I thought. Why are you stuffing `firstChild` in a plain
type-conversion at run time then? What if `firstChild` references
"unknown" object/element at some point?

>
>> On a side note, it would be nice if we could automate testing of
>> `isHostMethod` coverage. Maybe create an artificial environment where
>> host objects properties would be defined via error-throwing setters.
>
> Be my guest.

I'll think about this whole idea and how to implement it better.
Perhaps, using Rhino with specifically crafted environment simulating
hostile, error-throwing DOM.

>
>> Then run test suite through all unit tests and ensure that nothing blows
>> up (i.e. that there's no plain host objects properties access, and that
>> everything is proxied through `isHostObjectProperty`)
>
> Well, you don't normally need to be so thorough with the testing.
> Often it is good to let things fail immediately. I laugh when I see

Of course. But if doesn't fail upfront, there's no guarantee it won't
fail at load time. Obviously, that's the main danger in that kind of
inference (object inference type II, is it?)

[...]

--
kangax

Roger

unread,
Jul 8, 2009, 8:11:18 PM7/8/09
to

XP Pro with FF3.x. Last time it was just a black box at the bottom
(no crash.) IIRC, the site uses jQuery, so anything is possible.

>
> Here's a plain "js" file. Search for "var
> OFFSET_PARENT_THROWS_ON_ORPHANED_ELEMENT"
>

> http://github.com/kangax/prototype/raw/a223833c8b49ae55f03b1e1a3a5b7e...


>
> Not that there's something extraordinary there.

I'll take your word for it (and I think I've seen it.)

>
>
>
> >> (Don't mind all the mess around in that file.)
>
> > Never got to see it.
>
> >> Also note that it is lack of "parentNode" that seems to be the root of
> >> the issue, not the orphanness of an element per se.
>
> > I fail to see the difference (and can't pin down "orphanness" anyway.)
>
> Orphaned element is the one that is not in a document at a given time.
> In other words, you won't get to its `ownerDocument` by following its
> `parentNode` chain.
>
> var divEl = document.createElement('div');
> var spanEl = document.createElement('span');
> divEl.appendChild(spanEl);
>
> At this point `divEl` has no `parentNode` and is orphaned from the
> document. At the same time, `spanEl` *has `parentNode`* but is still
> orphaned from the document.
>
> If I'm correct, IE won't throw on `spanEl.offsetParent`, but will throw
> on `divEl.offsetParent`, even though both elements are orphaned ones. I
> assume this missing `parentNode` is what causes IE to throw (maybe
> `offsetParent` tries to call one of its members internally or smth.)
>
> Does this make things clearer?

Yes, but I think your recollections are off regarding IE, orphans and
the "unspecified error." I don't think a newly created element has an
"unknown" offsetParent property. I'm pretty sure I had to do
something odd to make that happen (e.g. user innerHTML.) Hard to say
though as IE varies according to Windows update. These rules have
been known to change overnight.

>
>
>
>
>
> >>> That reminds me, always use typeof to test string properties as well
> >>> (isHostStringProperty?) In at least some builds of IE7, news link
> >>> (NNTP protocol) href properties (normally strings) are "unknown." Go
> >>> figure.
> >>> And then there are the truly unknown problems that nobody has
> >>> discovered (or invented) yet. There may be host objects out there
> >>> that have "poison" types or "don't tread on me" types. Such surprises
> >>> are best avoided as well (at least until they can be studied.) The
> >>> isHost* functions (or methods in most cases) are very simple, but
> >>> quite calculated in what they allow. An easy rule for choosing
> >>> between the main two is to use isHostMethod for anything you plan to
> >>> call. Use isHostObjectProperty for virtually everything else. I
> >> Well, IE can return "unknown" for `lastChild` as well, so element's
> >> contents would need to be emptied as:
>
> >> while (isHostObjectProperty(element, "lastChild")) {
> >> element.removeChild(element.lastChild);
>
> >> }
>
> > Not really. Your app should never present such a possibility.
> > Trouble comes when you try to write a library for every occasion (e.g.
> > Prototype.)
>
> Not sure what you mean. How else will my helper clear element's
> contents? You either use `isHostObjectProperty` at runtime when
> accessing `firstChild`, or you use boolean type conversion and face a
> chance of blow up.

(I really hate Google. The "posting limit" for my real account has
been exceeded.)

It won't blow up unless the caller did something it shouldn't have
(and in that case you want it to blow up.) These isHost* methods are
primarily for feature testing things once at the outset. For
instance, if you have an absolute position function (not recommended
of course), you will need to check offsetParent. You wouldn't want to
treat an "unknown" offsetParent like one that is missing. The former
clearly indicates a mistake by the caller, the latter does not. Best
to let obvious mistakes blow up (else they can sneak into production.)

>
>
>
> >> Btw, looking at MyLib.js, I see that you do indeed use
> >> `isHostObjectProperty` for testing `firstChild`, although it's being
>
> > In one-off feature detection I am sure.
>
> >> used inconsistently and some of the checks seem to be missing (e.g.
> >> `getElementText` has it, but `setElementText` doesn't).
>
> > I assume you mean used inconsistently in that some of the checks are
> > missing. No doubt about it. Was slapped together in about two months
>
> That's what I meant.
>
> > and I lost interest soon afterward. Turned out to be the magic
> > formula! ;)
>
> >> I also see that you never test `firstChild` with `isHostObjectProperty`
> >> at runtime (I assume for perf. reasons?).
>
> > Should fail immediately. The calling app blew it at that point.
>
> >> You test
> >> `document.documentElement`'s `firstChild` upfront and assume that
> >> `firstChild` of any other DOM element doesn't blow up. Is this really a
> >> safe assumption to make?
>
> > That's not testing for the IE explosion issue (just that the property
> > exists.)
>
> That's what I thought. Why are you stuffing `firstChild` in a plain
> type-conversion at run time then? What if `firstChild` references
> "unknown" object/element at some point?

That would be a highly unexpected turn of events (unlike offsetParent
above.) You can't prevent every conceivable problem, else your code
would go on forever. In this case, I'd want to see it blow up so I
could investigate the cause.

>
>
>
> >> On a side note, it would be nice if we could automate testing of
> >> `isHostMethod` coverage. Maybe create an artificial environment where
> >> host objects properties would be defined via error-throwing setters.
>
> > Be my guest.
>
> I'll think about this whole idea and how to implement it better.
> Perhaps, using Rhino with specifically crafted environment simulating
> hostile, error-throwing DOM.

I don't know much about Rhino.

>
>
>
> >> Then run test suite through all unit tests and ensure that nothing blows
> >> up (i.e. that there's no plain host objects properties access, and that
> >> everything is proxied through `isHostObjectProperty`)
>
> > Well, you don't normally need to be so thorough with the testing.
> > Often it is good to let things fail immediately. I laugh when I see
>
> Of course. But if doesn't fail upfront, there's no guarantee it won't
> fail at load time. Obviously, that's the main danger in that kind of
> inference (object inference type II, is it?)

No. You are confusing feature detection with the perceived need to
defend against all cases of the "unspecified error" in IE. They are
somewhat related by the use of common methods, but not at all the same
thing.

David Mark

unread,
Jul 8, 2009, 9:24:16 PM7/8/09
to

It's a clumsy way of saying that (in FF) intrinsic event handler
attributes are copied to the clone, but attached listeners are not
(which seems reasonable.) I wouldn't count on anything to do with
cloning (or importing) elements with intrinsic event handlers (or
inline styles) though. If you must do such things, you will have to
feature test each case.

RobG

unread,
Jul 8, 2009, 11:43:56 PM7/8/09
to
On Jul 9, 4:15 am, Peter <peter....@poczta.fm> wrote:
> kangax pisze:
>
>
>
> > Peter May wrote:
> >> kangax pisze:
> >>> Well, IE can return "unknown" for `lastChild` as well, so element's
> >>> contents would need to be emptied as:
>
> >>> while (isHostObjectProperty(element, "lastChild")) {
> >>> element.removeChild(element.lastChild);
> >>> }
>
> >> Btw, for clearing all nodes I'm using something like this:
>
> >> // elm - this is element to be cleared
> >> var e = elm.cloneNode(false);
> >> elm.parentNode.replaceChild(e, elm);
> >> elm = e;
>
> >> In the past, I compared to the results of both speed and code that
> >> indicated above was much faster. Even than innerHTML = "". However,
> >> there may be what is proposed is not good. Maybe someone will react.
>
> > Yes, this "method" is usually faster if you don't care about "lost"
> > event listeners of original element.

It also goes belly-up in some earlier versions of Safar or Opera or
maybe both, I can't remember. The clone was created OK, but an error
was thrown during the replace. Anyone who cares about such ancient
artifacts should test thoroughly.


> I found some information that "Only events added as attributes are
> cloned. Not those added using AddEventListener."
>
> http://tinyurl.com/m2tgyr

Per the DOM 2 Events spec for interface EventListener:

"When a Node is copied using the cloneNode method the
EventListeners attached to the source Node are not attached
to the copied Node. If the user wishes the same EventListeners
to be added to the newly created copy the user must add them
manually."

<URL: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
>

The story in IE, Fx and Safari at least is:

1. If added as attributes, they're clonded too

2. If added as properties, they're dropped

3. If added using addEventListener they're dropped (W3C compliant)

4. If added using attachEvent, they're cloned too (in IE at least).


--
Rob

Peter May

unread,
Jul 9, 2009, 3:43:46 AM7/9/09
to
RobG pisze:

Thank you. That explains a lot.

--
Peter

Garrett Smith

unread,
Jul 9, 2009, 4:15:33 AM7/9/09
to
kangax wrote:
> Garrett Smith wrote:
>> kangax wrote:
>>> Peter May wrote:
>>>> kangax pisze:
>>>>> Well, IE can return "unknown" for `lastChild` as well, so element's
>>>>> contents would need to be emptied as:
>>>>>
>>
>> When does that happen?
>
> When `lastChild` references an element/object with "unknown" typeof in
> IE, I suppose.
>

The providing of such an example would be good, helpful, and informative.


>>
>> That is true for all properties that don't reflect.
>
> What do you mean by "properties that don't reflect"?
>
> [...]
>

Using HTML 5 term to describe the phenomenon:
| Some DOM attributes are defined to reflect a particular content
| attribute. This means that on getting, the DOM attribute returns the
| current value of the content attribute, and on setting, the DOM
| attribute changes the value of the content attribute to the given
| value.

From:
http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#reflect

(I am using a term to describe a phenomenon. The HTML 5 draft, again, is
a draft, not a TR.)

Implementations vary a lot on actual behavior. To make IE's behavior
allowable, HTML 5 could create properties I mentioned earlier, and then
IE could implement those and recommend those. That makes it easier for
IE to change behavior of attributes and serialization (innerHTML) to
match the other browsers (which copied IE halfway) and allow developers
a way to still get the IE attributes/serialization behavior AND have it
work in more browsers (should they implement such strategies).

kangax

unread,
Jul 9, 2009, 3:41:41 PM7/9/09
to
RobG wrote:

[...]

> Per the DOM 2 Events spec for interface EventListener:
>
> "When a Node is copied using the cloneNode method the
> EventListeners attached to the source Node are not attached
> to the copied Node. If the user wishes the same EventListeners
> to be added to the newly created copy the user must add them
> manually."
>
> <URL: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
>
> The story in IE, Fx and Safari at least is:
>
> 1. If added as attributes, they're clonded too
>
> 2. If added as properties, they're dropped

Note that properties (and so attributes) that don't correspond to any of
intrinsic event handler names are cloned too. (in IE)

In other words, `onclick` property/attribute will not be cloned, but
`onfoobar` will.

[...]

--
kangax

kangax

unread,
Jul 9, 2009, 3:56:10 PM7/9/09
to
Garrett Smith wrote:
> kangax wrote:
>> Garrett Smith wrote:
>>> kangax wrote:
>>>> Peter May wrote:
>>>>> kangax pisze:
>>>>>> Well, IE can return "unknown" for `lastChild` as well, so
>>>>>> element's contents would need to be emptied as:
>>>>>>
>>>
>>> When does that happen?
>>
>> When `lastChild` references an element/object with "unknown" typeof in
>> IE, I suppose.
>>
>
> The providing of such an example would be good, helpful, and informative.

You know that if I had one, I would have already provided it :)

I'm speaking theoretically, of course; based on previous observations of
host objects. I personally have never seen `lastChild`/`firstChild`
reference `unknown`. Whether these properties should be tested for it is
a rather subjective topic.

One approach is to test every access of every host property via
relatively safe wrapper such as isHostMethod/isHostObjectProperty. The
downside to this is performance hit. The benefit is protection against
any existent and future throwable properties.

Another - perhaps more pragmatic - approach is to only use wrapper on
elements which are known (or likely) to blow up. Performance would be
higher then, but so would the chance of stumbling upon unknown/future
throwable property.

>
>
>>>
>>> That is true for all properties that don't reflect.
>>
>> What do you mean by "properties that don't reflect"?
>>
>> [...]
>>
>
> Using HTML 5 term to describe the phenomenon:
> | Some DOM attributes are defined to reflect a particular content
> | attribute. This means that on getting, the DOM attribute returns the
> | current value of the content attribute, and on setting, the DOM
> | attribute changes the value of the content attribute to the given
> | value.
>
> From:
> http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastructure.html#reflect

That makes sense. Thanks.

[...]

--
kangax

kangax

unread,
Jul 9, 2009, 4:38:49 PM7/9/09
to
Roger wrote:
> On Jul 8, 7:00 pm, kangax <kan...@gmail.com> wrote:
>> David Mark wrote:
[...]

>>> It crashed my browser again (preceded by a large black box on the
>>> document and my CPU fans going through the roof.) No thanks.
>> Jeez. It never crashed on me. Which browser/OS are you using?
>
> XP Pro with FF3.x. Last time it was just a black box at the bottom
> (no crash.) IIRC, the site uses jQuery, so anything is possible.

Weird. Never happened to me on FF3.x (MacOSX)

[...]

>>> I fail to see the difference (and can't pin down "orphanness" anyway.)
>> Orphaned element is the one that is not in a document at a given time.
>> In other words, you won't get to its `ownerDocument` by following its
>> `parentNode` chain.
>>
>> var divEl = document.createElement('div');
>> var spanEl = document.createElement('span');
>> divEl.appendChild(spanEl);
>>
>> At this point `divEl` has no `parentNode` and is orphaned from the
>> document. At the same time, `spanEl` *has `parentNode`* but is still
>> orphaned from the document.
>>
>> If I'm correct, IE won't throw on `spanEl.offsetParent`, but will throw
>> on `divEl.offsetParent`, even though both elements are orphaned ones. I
>> assume this missing `parentNode` is what causes IE to throw (maybe
>> `offsetParent` tries to call one of its members internally or smth.)
>>
>> Does this make things clearer?
>
> Yes, but I think your recollections are off regarding IE, orphans and
> the "unspecified error." I don't think a newly created element has an
> "unknown" offsetParent property. I'm pretty sure I had to do
> something odd to make that happen (e.g. user innerHTML.) Hard to say
> though as IE varies according to Windows update. These rules have
> been known to change overnight.

It doesn't take long to test it. What does this return in your IE?

`typeof document.createElement('div').offsetParent;`

I see "unknown", as expected. Now try plain type conversion on it and
unspecified error should be thrown.

[...]

>>> Not really. Your app should never present such a possibility.
>>> Trouble comes when you try to write a library for every occasion (e.g.
>>> Prototype.)
>> Not sure what you mean. How else will my helper clear element's
>> contents? You either use `isHostObjectProperty` at runtime when
>> accessing `firstChild`, or you use boolean type conversion and face a
>> chance of blow up.
>
> (I really hate Google. The "posting limit" for my real account has
> been exceeded.)

So get Thunderbird. I only use groups for searching.

>
> It won't blow up unless the caller did something it shouldn't have
> (and in that case you want it to blow up.) These isHost* methods are

I was mainly talking about `lastChild`, which you answered below.

> primarily for feature testing things once at the outset. For
> instance, if you have an absolute position function (not recommended
> of course), you will need to check offsetParent. You wouldn't want to
> treat an "unknown" offsetParent like one that is missing. The former
> clearly indicates a mistake by the caller, the latter does not. Best
> to let obvious mistakes blow up (else they can sneak into production.)

So positioning function would bail out early when typeof `offsetParent`
is tested as "unknown", since we would known that an element is orphaned
(probably returning whatever offset parent of orphaned element should
be), right?

Fair enough.

[...]

--
kangax

David Mark

unread,
Jul 9, 2009, 4:45:47 PM7/9/09
to
On Jul 9, 3:56 pm, kangax <kan...@gmail.com> wrote:
> Garrett Smith wrote:
> > kangax wrote:
> >> Garrett Smith wrote:
> >>> kangax wrote:
> >>>> Peter May wrote:
> >>>>> kangax pisze:
> >>>>>> Well, IE can return "unknown" for `lastChild` as well, so
> >>>>>> element's contents would need to be emptied as:
>
> >>> When does that happen?
>
> >> When `lastChild` references an element/object with "unknown" typeof in
> >> IE, I suppose.
>
> > The providing of such an example would be good, helpful, and informative.
>
> You know that if I had one, I would have already provided it :)
>
> I'm speaking theoretically, of course; based on previous observations of
> host objects. I personally have never seen `lastChild`/`firstChild`
> reference `unknown`. Whether these properties should be tested for it is
> a rather subjective topic.
>
> One approach is to test every access of every host property via
> relatively safe wrapper such as isHostMethod/isHostObjectProperty.

As mentioned, that is definitely the wrong approach. Those methods
are virtually always used for feature testing (and once per load.)

Instead of firstChild/lastChild (which can be "unknown" as I've seen
elements in the debugger with every property inaccessible and the
value as "[unknown]"), take offsetParent, which we all know can be
unknown (and the cause seems to be predictable.)

If you have a function to calculate position offsets, one of the first
few lines is likely to read:

if (el.offsetParent) { ... }

Likely the rest of the logic is contained in this branch, else you
would check the computed style (e.g. some browsers set offsetParent to
null for elements with fixed position.) Clearly this is an important
test and perhaps it looks like it would be dangerous and you might
jump to the conclusion that using this would be more safe:

if (isHostObjectProperty(el, 'offsetParent')) { ... }

As mentioned, this much slower and additional baggage for nothing (you
should have already tested the property is available on elements.)
But that's not the real issue. The logic is flat-out wrong. Look at
the two cases where this would fail:

1. Fixed position in some browsers
2. Orphaned element in IE (under some circumstances)

These are completely incompatible cases, each requiring its own logic.

The first one is something you need to check. The second should
*never* come up as the rest of your app should know better than to try
to compute offsets for orphaned elements. In this second case, you
want the exception to be thrown, then you can easily find the bug by
examining the call stack.

Obviously, this is the only correct solution:

if (el.offsetParent) { ... }

These patterns repeat themselves endlessly in DOM scripting. If you
find yourself hiding from "unknown" types after the gateway is cleared
(i.e. feature detection is complete), you are likely shielding
yourself from critical debugging information.

And think about what you would do if the second pattern failed.
Trying to get the computed style (actually cascaded in IE) will not
yield anything related to an offset for an orphaned element. It may
fail silently with an odd result (in which case, you've got a very
obscure bug to track down) or it may throw further exceptions.
Obviously, the last thing you would do is add more calls to isHost* to
prevent further exceptions.

Does that make it clear?

> The
> downside to this is performance hit. The benefit is protection against
> any existent and future throwable properties.

Absolutely not. See above.

>
> Another - perhaps more pragmatic - approach is to only use wrapper on
> elements which are known (or likely) to blow up. Performance would be
> higher then, but so would the chance of stumbling upon unknown/future
> throwable property.

No. You use these isHost* functions during feature detection and for
every host method and property. You cannot pick and choose. You
virtually never use them afterward.

>
>
>
>
>
> >>> That is true for all properties that don't reflect.
>
> >> What do you mean by "properties that don't reflect"?
>
> >> [...]
>
> > Using HTML 5 term to describe the phenomenon:

WTF. Who is trying too hard to be clever? Don't use terms from that
draft here.

> > | Some DOM attributes are defined to reflect a particular content

Especially not *that* one. Whoever came up with "DOM attributes" to
describe properties should be locked up (or at least barred from such
discussions.)

> > | attribute. This means that on getting, the DOM attribute returns the
> > | current value of the content attribute, and on setting, the DOM

Same for "content attribute." Twits shouldn't be allowed to write
these documents. Nobody is going to understand them.

> > | attribute changes the value of the content attribute to the given
> > | value.

Just read it aloud and it becomes crystal clear.

>
> > From:
> >http://www.whatwg.org/specs/web-apps/current-work/multipage/infrastru...

Lets stop posting that link as well. From what I've heard, the score
is two crashed browsers plus one successful load that took six
minutes.

>
> That makes sense. Thanks.

Doh!

RobG

unread,
Jul 9, 2009, 7:56:10 PM7/9/09
to
On Jul 10, 5:41 am, kangax <kan...@gmail.com> wrote:
> RobG wrote:
>
> [...]
>
> > Per the DOM 2 Events spec for interface EventListener:
>
> >   "When a Node is copied using the cloneNode method the
> >    EventListeners attached to the source Node are not attached
> >    to the copied Node. If the user wishes the same EventListeners
> >    to be added to the newly created copy the user must add them
> >    manually."
>
> > <URL:http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventListener
>
> > The story in IE, Fx and Safari at least is:
>
> > 1. If added as attributes, they're clonded too
>
> > 2. If added as properties, they're dropped
>
> Note that properties (and so attributes) that don't correspond to any of
> intrinsic event handler names are cloned too. (in IE)

And Firefox. To add to the mix, non-standard properties are clonded in
IE but not in Firefox, non-standard attributes are cloned in both. I
lost interest in documenting it in more detail after discovering how
random it is, so there are likely many more inconsistancies.

>
> In other words,

... it's a complete mess. :-(

cloneNode(false) can't be used as a general method to empty content,
though it is OK for specific cases where the pitfalls are avoided.


--
Rob

Thomas 'PointedEars' Lahn

unread,
Jul 10, 2009, 4:59:26 AM7/10/09
to
kangax wrote:
> Thomas 'PointedEars' Lahn wrote:
>> kangax wrote:
>>> Thomas 'PointedEars' Lahn wrote:
>>>> for (var i = 1; i < len; i++)
>>>> {
>>>> var
>>>> p = arguments[i],
>>>> p_is_Array = (i === len - 1 && jsx.object.isArray(p)),
>>>> origP = p;
>>>> [...]
>>>> }
>>>>
>>>> Did I miss something?
>>> [...] avoid resolving `jsx.object.isArray` over and over,

>> Will do (as done elsewhere). However, it would have to be v.isArray(...)
>> in any case, or extensive rewrites might be needed if I change how
>> jsx.object.isArray() gets to the jsx.object.isInstanceOf() that it calls.
>
> Hmm. I was thinking of something like `var isArray =
> jsx.object.isArray`. So I take it that `isArray` is using `this` to
> reference `jsx.object`?

It might, in the future, when the global `isArray' variable (not that here)
were no longer needed.

> If so, then introducing extra variable to go
> from double property access to single doesn't seem justified.

It is not just the property access but also the identifier resolution along
the scope chain. The additional steps, and unreliability avoided, by using

function ...(...)
{
var foo = bar.baz;

for (...)
{
foo.bla
}
}

instead of

function ...(...)
{
for (...)
{
bar.baz.bla
}
}

are worth closer inspection.

>>>>> As far as type converting host objects (not methods!), didn't we just
>>>>> have a conversation about it where you said that it should be safe to do so?
>>>>>
>>>>> [...]
>>>>> <http://groups.google.com/group/comp.lang.javascript/msg/4df3cf9b5a7bd60f>
>>>>>
>>>>> Or am I missing something?
>>>> Yes, I was talking about return values of standardized methods there.
>>> I'm pretty sure we were talking about `lastChild`/`firstChild` as an
>>> operand in `if`/`while` expression (when "emptying" element contents).
>> You're right. However, I would submit that there is still a difference
>> between a property of a host object that must strictly follow specification,
>> and a host-defined property of the global object or a property of a host
>> object, that does not strictly follows implementation (for historical reasons).
>
> So `Node::firstChild` is part of a DOM standard, but `Window::document`
> is not (because global `window` is not part of a standard). Am I
> understanding you correctly?

Partially.

>>> from what I can see (unless objects implementing exactly
>>> Document interface would be the ones to throw, and not
>>> those that implement Node only; but that would be just
>>> plain silly)
>> It is not the value but the existence of the property that matters here.
>
> Just to make things clear, I am interested in your opinion about
> boolean- type conversion of host objects (not methods). You mentioned
> that it is safe to type convert `<nodeRef>.firstChild/lastChild`.

No, I said that I could not see a good reason why it should be unsafe.

> Now I'm trying to figure out whether it is safe to type-convert other host
> objects, such as `document`;
>
> e.g. - `if (<global object>.window.document) { ... }`.

The specified arbitrariness of host object's [[Get]] implementations
suggests that it is probably is not safe.

>>>> var isMethod = jsx.object.isMethod = jsx.object.areMethods = function(o, p) {
>>>> var len = arguments.length;
>>>> if (len < 1) return false;
>>> Shouldn't return value be other than boolean, to indicate that something
>>> went wrong and differentiate from cases when tested method isn't
>>> recognized as "method"? (e.g. is "unknown").
>> A possibility; but what should it be? These days I would even consider
>> throwing exceptions instead (guarded with eval(), of course).
>
> I usually use `null`.

I would rather throw an exception instead. `is*' methods are not supposed
to return non-booleans; and if you replied that types would not matter, my
reply would be why `false' would not suffice then.

>>>> var
>>>> rxUnknown = /^\s*unknown\s*$/i,
>>>> rxMethod = /^\s*(function|object)\s*$/i,
>>> Why initialize these on every method invocation?
>> Pretty inefficient, I know. I'm working on it.

Actually, in a conforming implementation of ECMAScript, Edition 3, it is not
that inefficient. While the initialization of the variable happens on each
call indeed, the creation of the RegExp object would not (section 7.8.5).

ECMAScript Edition 3.5 Final Draft, section 7.8.5, suggests that this
behavior might change. But as for now, only if the runtime of the
initialization turned out to be significant, then another closure might be
in order.

>>>> t = typeof o;
>>>>
>>>> /* ... */
>>>>
>>>> /*
>>>> * Refined support for strings; evaluating them always would
>>>> * preclude String objects from being tested for methods.
>>>> * Try to warn if a primitive string value is passed and the
>>>> * required flag is not set (default).
>>>> */
>>>> if (t === "string")
>>>> {
>>>> if (arguments.callee.evalStrings)
>>> I wouldn't use `arguments.callee` if possible (to take advantage of
>>> environments which optimize).
>> If the property should not be owned by another object, `arguments.callee' is
>> a necessity as long as there cannot be a unique identifier (for backwards

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


>> compatibility) and user-defined read-only properties everywhere are still on

^^^^^^^^^^^^^^


>> the wish list. And I really like using function objects as containers for
>> function-related properties.
>
> I would use a closure (into which things like `rxUnknown` and `rxMethod`
> can go), and if closure is out of the question, use function object
> itself, but access it via identifier, not `arguments.callee`.

^^^^^^^^^^^^^^^^^^^^^^^^
Read again.


PointedEars
--
Anyone who slaps a 'this page is best viewed with Browser X' label on
a Web page appears to be yearning for the bad old days, before the Web,
when you had very little chance of reading a document written on another
computer, another word processor, or another network. -- Tim Berners-Lee

kangax

unread,
Jul 10, 2009, 1:03:21 PM7/10/09
to
Thomas 'PointedEars' Lahn wrote:
> kangax wrote:
[...]

>> Now I'm trying to figure out whether it is safe to type-convert other host
>> objects, such as `document`;
>>
>> e.g. - `if (<global object>.window.document) { ... }`.
>
> The specified arbitrariness of host object's [[Get]] implementations
> suggests that it is probably is not safe.

That's exactly why I couldn't understand why `document` should be
guarded against [[Get]] but `firstChld`/`lastChild` not. Both elements
can implement it as implementation desires (including throw).

>
>>>>> var isMethod = jsx.object.isMethod = jsx.object.areMethods = function(o, p) {
>>>>> var len = arguments.length;
>>>>> if (len < 1) return false;
>>>> Shouldn't return value be other than boolean, to indicate that something
>>>> went wrong and differentiate from cases when tested method isn't
>>>> recognized as "method"? (e.g. is "unknown").
>>> A possibility; but what should it be? These days I would even consider
>>> throwing exceptions instead (guarded with eval(), of course).
>> I usually use `null`.
>
> I would rather throw an exception instead. `is*' methods are not supposed
> to return non-booleans; and if you replied that types would not matter, my
> reply would be why `false' would not suffice then.

Because `false` indicates something else - that certain object didn't
pass a test. The fact that something went wrong during test itself (e.g.
not enough arguments) seems like a good candidate for a different return
value or (as you mentioned) a thrown exception.

>
>>>>> var
>>>>> rxUnknown = /^\s*unknown\s*$/i,
>>>>> rxMethod = /^\s*(function|object)\s*$/i,
>>>> Why initialize these on every method invocation?
>>> Pretty inefficient, I know. I'm working on it.
>
> Actually, in a conforming implementation of ECMAScript, Edition 3, it is not
> that inefficient. While the initialization of the variable happens on each
> call indeed, the creation of the RegExp object would not (section 7.8.5).

Yes, of course. What I meant was variable initialization, evaluation of
regex literal to get a reference to regex object and assignment of that
reference to a corresponding variable. And all of that twice, for each
variable :)

Not much work, but can be avoided (especially if it's used in a method
that will be frequently called)

[...]

--
kangax

Thomas 'PointedEars' Lahn

unread,
Jul 10, 2009, 1:47:07 PM7/10/09
to
kangax wrote:
> Thomas 'PointedEars' Lahn wrote:
>> kangax wrote:
>>> Now I'm trying to figure out whether it is safe to type-convert other host
>>> objects, such as `document`;
>>>
>>> e.g. - `if (<global object>.window.document) { ... }`.
>> The specified arbitrariness of host object's [[Get]] implementations
>> suggests that it is probably is not safe.
>
> That's exactly why I couldn't understand why `document` should be
> guarded against [[Get]] but `firstChld`/`lastChild` not. Both elements
> can implement it as implementation desires (including throw).

But isn't ToBoolean(...document) more likely to do that than
ToBoolean(...first/lastChild)?

>>>>>> var isMethod = jsx.object.isMethod = jsx.object.areMethods = function(o, p) {
>>>>>> var len = arguments.length;
>>>>>> if (len < 1) return false;
>>>>> Shouldn't return value be other than boolean, to indicate that something
>>>>> went wrong and differentiate from cases when tested method isn't
>>>>> recognized as "method"? (e.g. is "unknown").
>>>> A possibility; but what should it be? These days I would even consider
>>>> throwing exceptions instead (guarded with eval(), of course).
>>> I usually use `null`.
>> I would rather throw an exception instead. `is*' methods are not supposed
>> to return non-booleans; and if you replied that types would not matter, my
>> reply would be why `false' would not suffice then.
>
> Because `false` indicates something else - that certain object didn't
> pass a test. The fact that something went wrong during test itself (e.g.
> not enough arguments) seems like a good candidate for a different return
> value or (as you mentioned) a thrown exception.

if (isMethod() == null)

and the like is a self-fulfilling prophecy, isn't it?

>>>>>> var
>>>>>> rxUnknown = /^\s*unknown\s*$/i,
>>>>>> rxMethod = /^\s*(function|object)\s*$/i,
>>>>> Why initialize these on every method invocation?
>>>> Pretty inefficient, I know. I'm working on it.
>> Actually, in a conforming implementation of ECMAScript, Edition 3, it is not
>> that inefficient. While the initialization of the variable happens on each
>> call indeed, the creation of the RegExp object would not (section 7.8.5).
>
> Yes, of course. What I meant was variable initialization, evaluation of
> regex literal to get a reference to regex object and assignment of that
> reference to a corresponding variable. And all of that twice, for each
> variable :)
>
> Not much work, but can be avoided (especially if it's used in a method
> that will be frequently called)

As I indicated, tests pending.


PointedEars
--
var bugRiddenCrashPronePieceOfJunk = (
navigator.userAgent.indexOf('MSIE 5') != -1
&& navigator.userAgent.indexOf('Mac') != -1
) // Plone, register_function.js:16

Peter Michaux

unread,
Jul 11, 2009, 1:33:32 AM7/11/09
to
On Jun 30, 4:08 am, Jorge <jo...@jorgechamorro.com> wrote:

> See "The MegaHertz Myth" :http://www.youtube.com/watch?v=PKF9GOE2q38

Thanks for posting that. Interesting.

Peter

0 new messages