When is a function not a function?

J

John G Harris

Thomas 'PointedEars' Lahn said the following on 9/26/2007 5:40 PM:

But there is no reason why it *can not* other than people's pedantic
desires to whine about it. Had it been S that was used instead, people
would shut up about it and move on. Except that if it had been S
instead of $ then people would be whining about how the name wasn't an
indication of what it did.


But it's already happened :

Thou shalt not start a global name with "MM_".

Because otherwise there will come a day when you get an obscure bug that
will drive you crazy.

There's a similar rule in C++ about names starting with leading
underlines. The difference is that the rule has been biting people for
years, so competent programmers don't dismiss it as pedantic standards
mania.

John
 
R

Richard Cornford

Peter said:
Shouldn't a standard just say what the language can and
cannot do?

Failing to state that would result in a poor standard. It would be
unrealistic to expect a standard to never do any more.
Imagine the C or Scheme specification suggesting use of
indenting and parens/braces. "Herding cats" comes to mind.

If such a convention was proposed in their respective specification you
may well find programmers of those languages indenting their code.
Suggesting conventions in a standard is likely to fail
with at least some developers.

Everything is likely to fail with at least some 'developers', but that
may say more about those 'developers' than anything else.
Those developers haven't left the standard and so should
not be derided.

In our case those developers have 'left the standard' and should be
derided. There is no question about what the standard says.
I think conventions are for the community to develop and
adopt if they suit a particular development project.

You are not understanding that there are things that cannot be expressed
in the grammar or syntax of a language but may still be seen as
important to the creators of those languages. The way you deal with that
is to include a clear statement of intent in the language's
specification, so that programmers can avoid taking actions that would
undermine that intention. That was a completely successful strategy with
Java, but unfortunately in javascript too many individuals who don't
have a clue about what they are doing are allowed to have too much
influence.

Richard.
 
R

Richard Cornford

Randy said:
Richard Cornford said the following on 9/26/2007 8:39 PM:

The "Same professional attitude", according to who?

Apparently according to professionals using every other language with a
similar specification defined convention.
And, why did the argument change from "Because some
ECMA.. says so" to a "professional attitude"?

That is not a change. It remains the case that Java programmers do not
break the similar convention that appears in their language
specification, and do not even see a reason for debating that choice.
And, your statement implies that anybody that doesn't
follow ECMA - to the letter - isn't a "professional" and
that is total hogwash.

In the sense that ECMA 262 can be 'followed to the letter' by a
programmer then not doing so would be unprofessional. For any individual
programming javascript there is not a great deal in that document that
can be taken as constituting instructions to do, or not do, anything.
Mostly the document just states how javascript can be expected to
behave.

An example of where ECMA 262 may be taken as providing instructions for
the programmer might be where it states that any attempt to call the -
eval - function indirectly may result in an EvalError, at the discretion
of the implementation. The implication of that statement is that unless
someone is writing for a know set of implementations/versions (where
EvalErrors have been observed not to be thrown) or an implementation
that makes an explicit statement that no such error ever will be thrown,
then authoring with the assumption that no EvalError will ever be thrown
when calling - eval - indirectly (now or in future implementation
versions) would be an obvious mistake and so unprofessional.
Then why have I never seen the argument "You shouldn't use $
because it doesn't indicate what the function does" but you
see hundreds - if not thousands - of posts about "You shouldn't
do that because some obscure paragraph in a theoretical document
says you shouldn't"?

If you haven't seen that argument it is because you have not been paying
attention. I have made that point on numerous occasions, and if you go
back to the very first time we discussed this subject you will find that
it was Lasse Reichstein Nielsen's primary reson for rejecting the use of
the - $ - symbol in javascript.

Richard.
 
D

dhtmlkitchen

Richard Cornford said the following on 9/30/2007 4:36 PM:





Does that convention extend to function names beginning with uppercase
letters? You should know where that is headed.

<snip>

I snipped the rest of it because I don't care to have this drawn out
conversation again. It has been had in the past and people can search it
out and make up there own minds.

Either way, with regards to $. The only place in ECMAScript that I can
find that it refers to $ is this:

Section 7.6 Identifiers:
<quote>
This standard specifies one departure from the grammar given in the
Unicode standard: The dollar sign ($) and the underscore (_) are
permitted anywhere in an identifier. The dollar sign is intended for use
only in mechanically generated code.
</quote>

It doesn't say "limited" or "required". It simply says "This is what it
is *intended* for". I doubt very seriously that 99% of what is done with
scripting was it's "intended use".

Either way, it doesn't matter what ECMA had to say about it, people are
still going to use it until some UA comes out that breaks it. And no
amount of discussing it in comp.lang.javascript will ever change that.

Things that might seem not to matter:
{OOA&D, Testing, Variable names, comments, code formatting
conventions, process}

These things are just not that appealing to people, generally. This is
especially true for presentation layer development. Why not look at
what toolkit vendors do? They're the rock stars, right?

Yahoo still employs code freezes, status reports, and last time I was
there, my manager would not let me check ANY tests into CVS (they
still don't use SVN). They were calling this Scrum.

Little things like "don't use post-increment operator" are easy for
people to grasp. Free advice that comes with cookies and refreshments.
Serotonin levels go up with the increased blood sugar, jokes are told,
examples are shown (with much hand waving), and people are happy while
not working.

I do wonder though: Why $? I would like to know, out of curiosity, why
did jQuery use $? There is a reason the variable was used; I just
don't know what it is.
 
T

The Natural Philosopher

Things that might seem not to matter:
{OOA&D, Testing, Variable names, comments, code formatting
conventions, process}

These things are just not that appealing to people, generally. This is
especially true for presentation layer development. Why not look at
what toolkit vendors do? They're the rock stars, right?

Yahoo still employs code freezes, status reports, and last time I was
there, my manager would not let me check ANY tests into CVS (they
still don't use SVN). They were calling this Scrum.

Little things like "don't use post-increment operator" are easy for
people to grasp. Free advice that comes with cookies and refreshments.
Serotonin levels go up with the increased blood sugar, jokes are told,
examples are shown (with much hand waving), and people are happy while
not working.

I do wonder though: Why $? I would like to know, out of curiosity, why
did jQuery use $? There is a reason the variable was used; I just
don't know what it is.

I would say ha about 90% of "standards" s not so much 'best practice' as
just plain simple 'do it this ways so that people coming upon you
unexpectedly will know what's going on'

E.g. we all drive on one side of the road, but which side is open to debate.

Standards are there mostly for people working together, to enforce a
common style, so everybody knows how things should be done.

Its a mark of the petty jobsworth to elect such standards into moral Laws.
 
T

Thomas 'PointedEars' Lahn

I do wonder though: Why $? I would like to know, out of curiosity, why
did jQuery use $? There is a reason the variable was used; I just
don't know what it is.

Cluelessness. (That was easy.)


PointedEars
 
T

Thomas 'PointedEars' Lahn

Randy said:
Thomas 'PointedEars' Lahn said the following on 10/5/2007 7:37 PM:

Try enabling the spell checker in Thunderbird. It might shed some light
on it.

It merely shows that you don't know the word and that it isn't in the
default dictionary of Thunderbird's spell checker.
Sure I can.

You can *not*, you are not the author.
It was chosen because of the uniqueness of it and the lack
of use of it on the web.

Logical fallacy: wishful thinking. You can know neither whether or not it
was used on the Web at the time the library was conceived, nor can you know
that supposed uniqueness or supposed no-use at the time was the reason for
choosing it.
What better way to pick a simple single character identifier than one
that wasn't in use?

Logical fallacy: non sequitur.


PointedEars
 
D

dhtmlkitchen

The typeof operator is consistent when its subjects are not host
objects, and has been around since JavaScript 1.1, so well pre-dating
the 4th generation browsers.



Yes, the a Function constructor exists for each frame and each has
unique identity. That is also true of the Array constructor.




That would depend on what you considered correct. It looks like the
subject of the test is expected to be any of a javascript function
(unwisely tested), a siring primitive, a DOM element and Array or a
value with falseness. Getting into a position where it is necessary to
make such a test betrays very poor code design.
I think you meant "portrays" not "betrays". Am I right?

That analysis would be right if they'd used ||, but they used &&.

I provided analysis of the problem on my site. The problem is that
this function returns true for objects (of any type) that contain
"function" in the toString result.
(!!fn )....................falses are out.
(typeof fn != "string")....string values are out
(!fn.nodeName).............things with a truthy nodeName are out.
(fn.constructor != Array)..Arrays in same frame are out.
(/function/i.test( fn + "" ).anything else left can get through, it
just has to say "function".


It's not safe, but it's indicative of the problem of typechecking in
js.

Dojo has similar stuff. They claim that some built-in functions don't
return "function" for typeof. I have been unable to prove that
statement true.

http://dhtmlkitchen.com/?category=/...&entry=How-to-Tell-if-an-Object-is-a-Function
There are no circumstances under which a function object would result
in - typeof fn != 'string' - being true

No. typeof fn != 'string' should *always* be true.

or its having a - nodeName -
property or a constructor property that was a reference to the frame's
Array constructor (unless they had been explicitly added).
You're confused by thinking ||. The function uses &&

Anyway, typechecking is an issue and this post made me think about
that, which led to the blog entry.
What makes you think that jQuery, or any of its like, was written with
any interest in, or knowledge of, 'older browsers'?


If that was a valid argument we would not have seen the virtual
disappearance of people using - eval - to reference object properties
with constructed dot notation property accessors. There was a time when
"everybody" was doing that, but most have now learnt better.
You know, it might not be very good code, but I think John might be
creative. He's interested in these things, so improvement is
inevitable.

The code above speaks of poor design, but at least it is ECMA 262
conforming, so that is one up on Prototype.js.
What is not conforming in Prototype? I haven't done a thorough
analysis on it.
 
T

Thomas 'PointedEars' Lahn

I think you meant "portrays" not "betrays". Am I right?

That analysis would be right if they'd used ||, but they used &&.

I provided analysis of the problem on my site. The problem is that
this function returns true for objects (of any type) that contain
"function" in the toString result.
(!!fn )....................falses are out.

(fn) is equivalent there.
(typeof fn != "string")....string values are out
(!fn.nodeName).............things with a truthy nodeName are out.
(fn.constructor != Array)..Arrays in same frame are out.
(/function/i.test( fn + "" ).anything else left can get through, it
just has to say "function".

It's not safe, but it's indicative of the problem of typechecking in
js.

No, it is indicative of the bad quality of the calling script, and
ultimately of the bad quality of the called script. As Richard said,
one should never get into a position where a test of that form would
be necessary.

The code comes from jQuery (1.2.1):

// This may seem like some crazy code, but trust me when I say that this
// is the only cross-browser way to do this. --John
isFunction: function( fn ) {
return !!fn && typeof fn != "string" && !fn.nodeName &&
fn.constructor != Array && /function/i.test( fn + "" );
}

jQuery claims to support IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+ (and
calls that "cross-browser" -- OMG). But, if

/function/i.test(fn + "")

would return `true', it is highly unlikely that

typeof fn

would yield "string", so the test

typeof fn != "string"

is unnecessary. Unless, of course, someone who lacks the minimum clue
assumes that strings could be called and so could ever be subject to
isFunction().

Furthermore, if

/function/i.test(fn + "")

would return `true', how could it be that

fn.constructor != Array

could not yield `true' and therefore that test would be unnecessary as well?
There is yet a script engine to be named that does not type-convert an array
object to string in the form "element1,element2,element3". Unless, of
course, someone who lacks a minimum clue assumes that Array objects having
references to callable objects as elements could be called as well and so
could ever be subject to isFunction() in which case the former test would
return `true' (as the string representation of such an Array object could be
"...,function ...() {....},...").

Needless to say that RegExp.prototype.test() already type-converts its
argument to string (see ECMAScript Ed. 3, 15.10.6.3) and so the forced
conversion by concatenation is unnecessary.

And a Function object, being a native object, certainly could have a
user-defined property `nodeName' and still could be called. So that test
makes no sense as well.

So far methods of built-in objects have always yielded typeof "function",
only methods of host objects in the MSHTML DOM have yielded typeof "object".

Therefore,

if (/\b(function|object)\b/i.test(typeof fn) && fn)
{
// ...
}

should satisfy all the reasonable cases in which isFunction() could be called:

- False-values could only yield `object', as `null' does, but they would not
type-convert to `true';

- typeof fn == "string" is already excluded (unless one assumes the
improbable case that `typeof' would yield "string function" and the like);

- fn.constructor != Array could only yield `true' because typeof "function"
would apply;

- /function/i.test( fn + "" ) could only yield `true' because typeof
"function" or "object" would apply.

And none of the obscure testing in jQuery is explained as to why it was done
(i.e. for what script engine and DOM); we have only the word of "John" that
it would be "the only cross-browser way to do this."

BTW: jQuery-1.2.1.js is served for download from Google Code with
Content-Type: text/x-c. OMG.


PointedEars
 
D

dhtmlkitchen

(fn) is equivalent there.



No, it is indicative of the bad quality of the calling script, and
ultimately of the bad quality of the called script. As Richard said,
one should never get into a position where a test of that form would
be necessary.
how can you know if it's a function?

typeof fn? nope, not in safari.

document.links, document.getElementsByTagName("blah")

Safari thinks they implement call, which is what typeof checks for.
The code comes from jQuery (1.2.1):

// This may seem like some crazy code, but trust me when I say that this
// is the only cross-browser way to do this. --John
isFunction:function( fn ) {
return !!fn && typeof fn != "string" && !fn.nodeName &&
fn.constructor != Array && /function/i.test( fn + "" );
}

jQuery claims to support IE 6.0+, FF 1.5+, Safari 2.0+, Opera 9.0+ (and
calls that "cross-browser" -- OMG). But, if

/function/i.test(fn + "")

would return `true', it is highly unlikely that

typeof fn

would yield "string", so the test

typeof fn != "string"

is unnecessary. Unless, of course, someone who lacks the minimum clue
assumes that strings could be called and so could ever be subject to
isFunction().
No, it excludes strings.

"function" + "" would return true. This clause prevents that.

Furthermore, if

/function/i.test(fn + "")

would return `true', how could it be that

fn.constructor != Array
var a = Array{function bork(){});

couldnotyield `true' and therefore that test would be unnecessary as well? No.


There is yet a script engine to be named that doesnottype-convert an array
object to string in the form "element1,element2,element3". Unless, of
course, someone who lacks a minimum clue assumes that Array objects having
references to callable objects as elements could be called as well and so
could ever be subject to isFunction() in which case the former test would
return `true' (as the string representation of such an Array object could be
"...,function...() {....},...").
Yes.

Needless to say that RegExp.prototype.test() already type-converts its
argument to string (see ECMAScript Ed. 3, 15.10.6.3) and so the forced
conversion by concatenation is unnecessary.
That's true, but being explicit is a good thing.
And aFunctionobject, being a native object, certainly could have a
user-defined property `nodeName' and still could be called. So that test
makes no sense as well.
Right, so could any of the four examples on my site.
So far methods of built-in objects have always yielded typeof "function",
only methods of host objects in the MSHTML DOM have yielded typeof "object".

Therefore,

if (/\b(function|object)\b/i.test(typeof fn) && fn)
{
// ...
}

should satisfy all the reasonable cases in which isFunction() could be called:
Relying on toString is bad duck typing. It quacks but dosn't walk.
It's the same thinking that went into the jQuery and Dojo code.
- False-values could only yield `object', as `null' does, but they wouldnot
type-convert to `true';

- typeof fn == "string" is already excluded (unless one assumes the
improbable case that `typeof' would yield "stringfunction" and the like);
new String()
{toString:function(){return 'function';}}

a = Function();
a.toString = "widget";
- fn.constructor != Array could only yield `true' because typeof "function"
would apply;
frames.

- /function/i.test( fn + "" ) could only yield `true' because typeof
"function" or "object" would apply.

And none of the obscure testing in jQuery is explained as to why it was done
(i.e. for what script engine and DOM); we have only the word of "John" that
it would be "the only cross-browser way to do this."
RIght. No detail, no tests.

Dojo and YUI at least has comments. Unfortunately, a lot of the the
time, the comments are contradictory.

The Dojo example I posted on my site. isAlien is weird. I think
they're trying to test Host objects, but the comment says built-in,
and the code tests the input for a string value of [native code]/i,
which could be anything.

String values do not imply an object's type. Relying on toString is
not safe.

Garrett
 
R

Richard Cornford

On Sep 26, 1:29 am, Richard Cornford wrote:
I think you meant "portrays" not "betrays". Am I right?

No, "betrays" says exactly what I intended to say.
That analysis would be right if they'd used ||, but they
used &&.

No, that analysis is correct because it uses &&.
I provided analysis of the problem on my site.

That is not what I would call it. It is a pity that you choose to
publish such things without first having them checked by someone who
knows this subject.
The problem is that this function returns true for
objects (of any type) that contain
"function" in the toString result.

It also may return false for object that are functions. The author is
clearly unsure about what it is that is being tested for, and so has no
criteria for identifying an effective test for that (if one exists).
(!!fn )....................falses are out.

A pointless test if the subject is not expected to potentially be a
value that has falseness.
(typeof fn != "string")....string values are out

A pointless test if the subject is not expected to potentially be a
string primitive.
(!fn.nodeName).............things with a truthy nodeName are out.

A pointless test if the subject is not expected to potentially be an
object with a true nodeName property. An expected characteristic of DOM
elements.
(fn.constructor != Array)..Arrays in same frame are out.

A pointless test if the subject is not expected to potentially be an
Array.
(/function/i.test( fn + "" ).anything else left can get
through, it just has to say "function".

So in what sense is my "analysis" not correct? "It looks like the
subject of the test is expected to be any of a javascript function
(unwisely tested), a siring primitive, a DOM element and Array or a
value with falseness".
It's not safe, but it's indicative of the problem of
typechecking in js.

Dojo has similar stuff.

The dojo version of isFunction is nearly as bad as it will also return
true for non-callable objects. Again the authors appear to be uncertain
of what it is they are testing for.
They claim that some built-in functions don't
return "function" for typeof.

They can claim anything they like, but if it were a true statement they
could state the environment in which this was the case and show a test
case that proves the point (or shows where their misconceptions lie).
Without that, and judging their competence by the code in dojo, I would
not trust them to have made an accurate analysis.
I have been unable to prove that
statement true.
<snip>

You should not need to. The person making the claim is the one
responsible for demonstrating it.
No. typeof fn != 'string' should *always* be true.

Yes, it looks like I omitted a "not" between "being" and "true". One of
the consequences of rushing to get it posted before going to work on a
week day.
or its having a - nodeName -
You're confused by thinking ||. The function uses &&

No I am not. To get a true result with the logical AND operation test
every individual sub-expression needs to evaluate to true.
Anyway, typechecking is an issue

Not really. Once you get used to properly employing a loosely typed
language it rapidly becomes a non-issue, and such testing is relegated
to the feature testing role alone. Hence my assertion that the test
betrays poor design. Before someone has the experience to cope with
loose typing they will be struggling to identify the types of things
from a position of being totally in the dark. This results in such
testing functions being passed almost anything at all, and so having to
jump through hoops applying tests that really should never be necessary.

You know, it might not be very good code, but I think John
might be creative.

Being "creative", of itself, is of little significance. Masses of
dubiously code and all of those half-ass hacks were 'created' by
someone.

To be usefully creative it is necessary to first formulate a clear
notion of what it is that is to be achieved. It is evidence of this
clarity of comprehension that is absent from the testing code. Hence my
assertion that the test betrays poor design. Before someone has the
experience to cope with loose typing they will be struggling to identify
the types of things from a position of being totally in the dark. This
results in such testing functions being passed almost anything at all,
and so having to jump through hoops applying tests that really should
never be necessary.
He's interested in these things, so improvement is
inevitable.

That may be likely, but not inevitable. It appears that becoming
satisfied with what you have done can seriously inhibit an ability to
improve.
What is not conforming in Prototype?
<snip>

ECMS 262 provides an EvalError that is to be thrown when the - eval -
function is called indirectly (in any way other than as - eval(
seomthing ); - ). It then gives implementations the option of not
throwing that exception. ECMAScript conforming code has no choice but
assume the worst case (that the exception will be thrown), while
Prototype.js makes the assumption that no implications will (ever) throw
that exception. Thus it sacrifices ECMAScript compatibility (and so all
hope of its ever being cross-browser) and ends up being dependent upon a
limited set of known (current) implications where the exception can be
observed not to be thrown.

Richard.
 
R

Richard Cornford

Randy said:
Richard Cornford said the following on 9/30/2007 4:36 PM:


Does that convention extend to function names beginning with
uppercase letters?

The specification has nothing to say on the subject of the
capitalisation of Identifiers. Conventions relating to that subject are
left to the individual programmer (or their employers) to choose. The
convention of capitalising 'class' names is adopted from Java, and can
be very helpful if you are writing anything OO, but other capitalisation
conventions have been proposed (even if they haven't really caught on).
You should know where that is headed.

No, but I can guess.
<snip>
I snipped the rest of it because I don't care to have this drawn
out conversation again. It has been had in the past and people can
search it out and make up there own minds.

Either way, with regards to $. The only place in ECMAScript that
I can find that it refers to $ is this:

Section 7.6 Identifiers:
<quote>
This standard specifies one departure from the grammar given in
the Unicode standard: The dollar sign ($) and the underscore (_)
are permitted anywhere in an identifier. The dollar sign is
intended for use only in mechanically generated code.
</quote>

It doesn't say "limited" or "required".

It is not possible for it to say limited or required. The syntax for an
Identifier has to be correct regardless of whether the code was machine
generated or not.
It simply says "This is what it is *intended* for".

Yes, and that answers the question of why a character has been included
in the set of characters permissible in an Identifier when that
character contributes nothing to the task of identifying.
I doubt very seriously that 99% of
what is done with scripting was it's "intended use".

If computer programming languages have an intended use then it should be
to be used to program computers.
Either way, it doesn't matter what ECMA had to say about it,

It does matter.
people are still going to use it

You mean use it incorrectly. Using $ symbols in machine generated
identifiers could not be subject to any criticism.
until some UA comes out that breaks it.

A UA could not break it without the end result not being ECMAScript
compatible. The browsers have no way of knowing whether the code they
get is machine generated or not and have no reason to care. This is
entirely a question for programmers, like most conventions. It just
happens to be a convention proposed at the point of defining the
language rather than something arising in the use of the language (such
as indenting styles and capitalisation conventions).
And no amount of discussing it in comp.lang.javascript
will ever change that.

I wouldn't necessarily bet on that. A good few years of heavily
criticising the use of - eval - for evaluating dot notation property
accessors (and explaining/discussing the alternatives) has seen that
practice almost disappear (and certainly disappear from anything
professionally authored). It may be that a sufficiently robust attitude
taken towards this bad practice for sufficiently long will see it go the
same way as the worst examples of - eval - abuse. Things in the wider
world do change under the influence of our discussions, albeit slowly.

Richard.
 
R

Richard Cornford

how can you know if it's a function?

First define what you mean by "a function".
typeof fn? nope, not in safari.

Are you certain? Is it really the case that objects that return
'function' from a typeof operation cannot be called? Or are you just not
expecting them to be callable? Have you actually tried calling the
objects that safari asserts are functions?
document.links, document.getElementsByTagName("blah")

Safari thinks they implement call, which is what typeof
checks for.
<snip>

One of the consequences of using imprecise terminology is that when you
say "call" nobody knows whether you mean [[Call]] or
Function,.prototype.call. It is the implementing of the internal
[[Call]] method that typeof should be interested in, though not
necessarily for host objects. NodeLists and HTMLCollection interface
implementing objects would be host obejcts.

Richard.
 
D

dhtmlkitchen

No, "betrays" says exactly what I intended to say.


No, that analysis is correct because it uses &&.


That is not what I would call it. It is a pity that you choose to
publish such things without first having them checked by someone who
knows this subject.

There you go again.

It also may return false for object that are functions. The author is
clearly unsure about what it is that is being tested for, and so has no
criteria for identifying an effective test for that (if one exists).


A pointless test if the subject is not expected to potentially be a
value that has falseness.


A pointless test if the subject is not expected to potentially be a
string primitive.


A pointless test if the subject is not expected to potentially be an
object with a true nodeName property. An expected characteristic of DOM
elements.


A pointless test if the subject is not expected to potentially be an
Array.


So in what sense is my "analysis" not correct? "It looks like the
subject of the test is expected to be any of a javascript function
(unwisely tested), a siring primitive, a DOM element and Array or a
value with falseness".
The subject is expected NOT to be any of those things.

The point of each test is to exclude these things. Just maybe, there's
some type of node that says it's a "function" to typeof. It's actually
likely in Safari; Safari thinks document.images is a function, which
it is Not!

Now I should clear up a bit of confusion you posted on the webkit bug:

Take an object that is an instance of an NodeList.

That object's constructor implements NodeList. The object itself is an
object. The fact that it is callable is a bug, copied from MSIE, who
made document.all, et c. a function, e.g. document.all(0). Mozilla
copied this. It is retarded, IMO.

javascript:alert(Function.prototype.call.call(document.links,document,
1))

Not really useful. OR good design.

An instance of a NodeList is NOT the object that implements NodeList.
The object that implement's NodeList is the instance's constructor.


The dojo version of isFunction is nearly as bad as it will also return
true for non-callable objects.
What objects are those? Only ones that incorrectly report "function"
for typeof, I hope.

What I prefer about the dojo function is at least it is less
inclusive. It filters out with the typeof operator.

document.links instanceof Function; // false in Safari.


Again the authors appear to be uncertain
of what it is they are testing for.



They can claim anything they like, but if it were a true statement they
could state the environment in which this was the case and show a test
case that proves the point (or shows where their misconceptions lie).
Without that, and judging their competence by the code in dojo, I would
not trust them to have made an accurate analysis.


<snip>

You should not need to. The person making the claim is the one
responsible for demonstrating it.



Yes, it looks like I omitted a "not" between "being" and "true". One of
the consequences of rushing to get it posted before going to work on a
week day.



No I am not. To get a true result with the logical AND operation test
every individual sub-expression needs to evaluate to true.
That's what I'm saying. If jQuery's isFunction gets a falsish value, a
string value, et c, that value is excluded. It's "none of", not "any
of". You're wrong.

Not really. Once you get used to properly employing a loosely typed
language it rapidly becomes a non-issue, and such testing is relegated
to the feature testing role alone. Hence my assertion that the test
betrays poor design. Before someone has the experience to cope with
loose typing they will be struggling to identify the types of things
from a position of being totally in the dark. This results in such
testing functions being passed almost anything at all, and so having to
jump through hoops applying tests that really should never be necessary.
http://www.m-w.com/dictionary/betray

I'm pretty sure you meant "betrays good design," as that's the gist of
what you're saying.
Being "creative", of itself, is of little significance. Masses of
dubiously code and all of those half-ass hacks were 'created' by
someone.

To be usefully creative it is necessary to first formulate a clear
notion of what it is that is to be achieved. It is evidence of this
clarity of comprehension that is absent from the testing code. Hence my
assertion that the test betrays poor design. Before someone has the
experience to cope with loose typing they will be struggling to identify
the types of things from a position of being totally in the dark. This
results in such testing functions being passed almost anything at all,
and so having to jump through hoops applying tests that really should
never be necessary.
When I use others' code, I want it to fail right away if I use it
wrong. Now it might have been my fault for passing in an undefined,
but hey, I'm human and I lose my keys, I've put shit in the washer
that shouldn't go there, (phone, et c).

When others use my code it should fail fast and report the error
properly.

Now if some library had a function that takes a callback, that would
be when you want to know "is the callback a function?"

function doStuff( errorHandler ) {

}

When will errorHandler be invoked? Maybe never, right? Or maybe it
will be invoked some time after deployment, maybe even after I'm gone
from the job. Wow, that would suck.

Wouldn't it make sense to check the errorHandler 'thing' and make sure
it's actually a function first?


function doStuff( errorHandler ) {
if(typeof errorHandler != "function") "
var err = new Error("hey stoopid...");
log(err);
throw err;
....
}
 
D

David Mark

On Oct 13, 10:28 pm, "Richard Cornford" <[email protected]>
wrote:
[snip]
Are you certain? Is it really the case that objects that return
'function' from a typeof operation cannot be called? Or are you just not
expecting them to be callable? Have you actually tried calling the
objects that safari asserts are functions?

The objects that Safari claims are functions are indeed callable.
They have the internal [[Call]] method, but do not implement
Function.prototype.call.

Here are two test functions that are similar to the function I
referred to in the original post. One is ambiguous in what it expects
and one is not.

// Ambiguous version
// cb parameter can be a Function or other type of Object (explicitly
excluding a null object)
// method must be a string and is required if cb is not a Function

function executeCB1(cb, arg, method) {
if (typeof cb == 'function') { // disambiguation
return cb(arg);
}
else {
if (typeof cb[method] == 'function') { // validation
return cb[method](arg);
}
}
}

// Unambiguous version
// cb must be a Function
// context is optional

function executeCB2(cb, arg, context) {
if (typeof cb == 'function') { // validation
if (typeof context == 'undefined') {
return cb(arg);
}
else {
if (typeof cb.call == 'function') { // validation
return cb.call(context, arg);
}
}
}
}

function callbackFunction(a) {
return a;
}

function CallbackObject(b) {
this.callback = function(b) { return b; };
}

var co = new CallbackObject;

alert(executeCB1(callbackFunction, 'test function'));
alert(executeCB1(co, 'test object', 'callback'));

alert(executeCB2(callbackFunction, 'test function'));
alert(executeCB2(co.callback, 'test object', co));

alert(executeCB1(document.images, 'testimg'));
alert(executeCB2(document.images, 'testimg'));
alert(executeCB2(document.images, 'testimg', co));

The expected results were returned by all but Windows Safari Beta:

test function
test object
test function
test object
undefined
undefined
undefined

Safari returns:

test function
test object
test function
test object
[Object HTMLImageElement]
[Object HTMLImageElement]
undefined

So the validation is enough to prevent errors, but not enough to
maintain consistent results for the test cases. The pattern is clear
though.

function isFunction(f) {
return (typeof f == 'function' && typeof f.call == 'function');
}

function executeCB1(cb, arg, method) {
if (isFunction(cb)) { // disambiguation
return cb(arg);
}
else {
if (isFunction(cb[method])) { // validation
return cb[method](arg);
}
}
}

function executeCB2(cb, arg, context) {
if (isFunction(cb)) { // validation
if (typeof context == 'undefined') {
return cb(arg);
}
else {
if (isFunction(cb.call)) { // validation
return cb.call(context, arg);
}
}
}
}

The revised versions bring Windows Safari (and the like) into line.
 
D

David Mark

The subject is expected NOT to be any of those things.

The point of each test is to exclude these things. Just maybe, there's
some type of node that says it's a "function" to typeof. It's actually
likely in Safari; Safari thinks document.images is a function, which
it is Not!

Technically, it is not a Function, but it does implement an internal
[[Call]] method, so it is a function.
Now I should clear up a bit of confusion you posted on the webkit bug:

Take an object that is an instance of an NodeList.

That object's constructor implements NodeList. The object itself is an
object. The fact that it is callable is a bug, copied from MSIE, who
made document.all, et c. a function, e.g. document.all(0). Mozilla
copied this. It is retarded, IMO.

Microsoft? Retarded? Who knew? Of course, Mozilla (and Opera)
didn't need to copy this behavior.
javascript:alert(Function.prototype.call.call(document.links,document,
1))

Not really useful. OR good design.
Agreed.

[snip]

That's what I'm saying. If jQuery's isFunction gets a falsish value, a
string value, et c, that value is excluded. It's "none of", not "any
of". You're wrong.

I think Richard was saying that the confused logic in this low-level
function is indicative of higher-level problems in the design. For
example, a higher-level function designed to receive an array of DOM
elements and/or functions, which in turn passes them to the isFunction
function to determine which are which.

[snip]
When I use others' code, I want it to fail right away if I use it
wrong. Now it might have been my fault for passing in an undefined,
but hey, I'm human and I lose my keys, I've put shit in the washer
that shouldn't go there, (phone, et c).

That is a matter of exception handling. Whether it fails silently or
loudly, the logic in the isFunction function is confused, the author's
"trust me" comment is of little comfort and the two combined would
seem to indicate a design flaw in the library. Even if that is not
the case, the library is trash as it requires useragent sniffing just
to support a handful of modern browsers.
 
T

Thomas 'PointedEars' Lahn

No, it excludes strings.

Which is unnecessary, as strings could never be called, and so should never
be subject to the isFunction() test method.
"function" + "" would return true. This clause prevents that.

But can you name a case where a callable object would evaluate as a string
containing "function" without type conversion?
var a = Array{function bork(){});

But that assumes that `a' could be called which it cannot be. Hence it
should not be subject to an isFunction() test. An array is not a function.

Again, I did not write it that way. Please stop using broken software.
Yes.


That's true, but being explicit is a good thing.

Being explicit would be

/.../.test(String(...))

But that would be nonsense as well, as it would decrease efficiency.
Because if the specification algorithm is followed, type conversion
to String would happen *twice* in both cases: first due to the source
code and the second time as step 1 of RegExp.prototype.exec().
Right, so could any of the four examples on my site.

I didn't care about your (Web?) site and I have no intention to do so. If
you have arguments to present, please do it here.
new String()
{toString:function(){return 'function';}}

This is assuming that a String object could be called and so should/could
ever be subject to isFunction().
a = Function();
a.toString = "widget";

What should this accomplish? Overwriting the toString() method with a
string value renders type conversion to string non-functional. And even
if you meant

a = Function();
a.toString = function() { return "widget"; };

`typeof a' still would yield "function". The flaw in the described
algorithm is that it does not use `typeof' first. Because if it did,
many tests would not be necessary and the algorithm as a whole would
be less obscure and less error-prone.

I don't see any argument here.
String values do not imply an object's type. Relying on toString is
not safe.

Exactly.


PointedEars
 
T

Thomas 'PointedEars' Lahn

Randy said:
So document.images should be a Host Object?

A host object, yes. It has always referred to one.
Safari3/Win reports typeof(document.images) as 'function'. All other
Windows based browsers I have report it as 'object'.

And have you tested whether or not it can be called?

But again, you have been testing with a *beta version* (and, even more, the
beta version of *the first version for that platform and operating system
ever*), so any test results you got do not qualify for a argument regarding
software design.

It can be taken under serious consideration from the moment on the release
version shows the same result.


PointedEars
 
R

Richard Cornford

Randy said:
Richard Cornford said the following on 10/13/2007 10:28 PM:

Can I ask you to first define what you mean by "called"
or "callable"?

No more than sticking an ArgumentsList after a reference to the object
(the 'call operator', with or without arguments). That is what I would
consider calling an object, and to be callable that abject should not
throw an exception as a direct result of its being called (though it may
still throw an exception in response to its arguments'' values, as that
would be behaviour passed the point of calling it and so unrelated to
its callability).
document.links, document.getElementsByTagName("blah")

Safari thinks they implement call, which is what typeof
checks for.
<snip>

One of the consequences of using imprecise terminology is that
when you say "call" nobody knows whether you mean [[Call]] or
Function,.prototype.call. It is the implementing of the internal
[[Call]] method that typeof should be interested in, though not
necessarily for host objects. NodeLists and HTMLCollection
interface implementing objects would be host obejcts.

So document.images should be a Host Object?

It must be a host object, as it is provided by the host's object model.
Safari3/Win reports typeof(document.images) as 'function'.
Apparently.

All other Windows based browsers I have report it as 'object'.

Maybe, but that is neither necessarily true of windows based browsers
nor historically common on Mac browsers. Even Mac IE 5 would report
'function' in this context, and on Windows you only have to go back a
few Opera versions to see the same there.

(Incidentally, I will be replying to your e-mail soonish, but I will
have to do some research first so probably not for a day or two.)

Richard.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,522
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top