Test for null or undefined?

T

Thomas 'PointedEars' Lahn

Thomas said:
Matt said:
Thomas said:
Nonsense. The Specification says the argument object MUST be created
when control enters an execution context for function code
The only requirement is that the calling code should always be able to
act is if it had been created. [...]

That is _not_ what the ECMAScript Language Specification, Edition 3 Final
says. It describes what conforming implementations MUST implement, and
what they also MAY implement. What that means is made very clear,
starting with its Conformance section.

It is (like any other specification) an *implementation* specification,
_not_ a behavioral implementation; believe it or not.
^^^^^^^^^^^^^^
s/implementation/specification/

And here's the proof for those who think they know better:

,-[ECMAScript Language Specification, Edition 3 Final]
|
| 1 Scope
|
| This Standard defines the ECMAScript scripting language.
|
| 2 Conformance
|
| A conforming implementation of ECMAScript must provide and
^^^^^^^^^^^^^^^^
| support all the types, values, objects, properties, functions, and
^^^^^^^^^^^^^^^ ^^^^^^^ ^^^
| program syntax and semantics described in this specification.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| A conforming implementation of this International standard shall interpret
| characters in conformance with the Unicode Standard, Version 2.1 or
| later, and ISO/IEC 10646-1 with either UCS-2 or UTF-16 as the adopted
| encoding form, implementation level 3. If the adopted ISO/IEC 10646-1
| subset is not otherwise specified, it is presumed to be the BMP subset,
| collection 300. If the adopted encoding form is not otherwise specified,
| it presumed to be the UTF-16 encoding form.
|
| A conforming implementation of ECMAScript is permitted to provide
| additional types, values, objects, properties, and functions beyond
| those described in this specification. In particular, a conforming
| implementation of ECMAScript is permitted to provide properties
| not described in this specification, and values for those properties,
| for objects that are described in this specification.
|
| A conforming implementation of ECMAScript is permitted to support program
| and regular expression syntax not described in this specification. In
| particular, a conforming implementation of ECMAScript is permitted to
| support program syntax that makes use of the “future reserved wordsâ€
| listed in section 7.5.3 of this specification.

and

| 10.1.6 Activation Object
|
| When control enters an execution context for function code, an object
| called the activation object is created and associated with the execution
| context. The activation object is initialised with a property with name
| arguments and attributes { DontDelete }. The initial value of this
| property is the arguments object described below.

| 10.1.8 Arguments Object
|
| When control enters an execution context for function code, an arguments
| object is created and initialised as follows:
| [description of the features of the arguments object]

Nothing more, nothing less.


PointedEars
 
M

Matt Kruse

The only requirement is that the calling code should always be able to
act is if it had been created. [...]
That is _not_ what the ECMAScript Language Specification, Edition 3 Final
says.  It describes what conforming implementations MUST implement, andwhat
they also MAY implement.  What that means is made very clear, starting with
its Conformance section.

If the code has no way to determine if it has been created, and it
always behaves as if it has been created, then what's the difference?
I'm not sure why you think it would matter, especially if the
optimization results in a faster browser experience. Nothing lost,
something gained.

If you aren't sure whether an implementation creates arguments every
time or not, and yet every test or observation you can possibly make
says it's there, then it _is_ created as far as you are concerned. We
can diverge into philosophy and the nature of reality if you'd like -
the same concepts apply ;)

Matt Kruse
 
T

Thomas 'PointedEars' Lahn

Matt said:
Typical. You can only think in terms of your environment and your
situation, and you assume that everyone else's is the same.

If that means I am assuming competence, then you are correct.
I'm a reasonably intelligent guy.

But apparently you are not competent enough to set that intelligence to
work. How many *more* examples like the recent one (jQuery doesn't run
properly in IE 8) will it take for you to see that jQuery is junk, and
that its "team" consists of wannabes of the worst sort, lead by a "Ninja"
who cannot even get his star-throwing right?
I know how to balance conflicting needs to arrive at the best possible
solution, even if it's not ideal. If there was an easier, more obvious
solution, don't you think I would go for it? Or do you really think I'm
so in love with jQuery that I'll stick to it no matter what?

It sure looks that way.
On the contrary, I've chosen NOT to use it in some projects because it
wasn't the best choice, and I've actually REMOVED it from projects
(replaced with POJS) because it was a performance problem. It all depends.

Good that you removed it, and you get a star for effort. But again, how
many more *failures* (not: performance problems) do you need before you dump it?
Oh, of course. I'll just tell it to the suits! Easy! Genius! (Do you
think we all work in a Dilbert office? heh)

I don't know what a Dilbert office is, but what I describe is what I
consider competent behavior for a software developer. YMMV.
Okay, those are alternative programming tactics. And obvious. But none of
them are _jQuery_ alternatives.

But you are unable to set them in code?
Nobody chooses jQuery because of its
internal technical genius (I hope). They choose it because it offers a
convenient API

Marketing babble. A convenient API where you have one function that does
all? A convenient API is where you do not have to guess the meaning or the
outcome of a call, much unlike jQuery's.
and a layer of abstraction over things they don't want to spend hours
figuring out

There're trusting the people who don't have a clue about it either instead.
and creating - and does so in a finished, documented, tested, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
YMMD.

and supported package. That matters. An "alternative" to jQuery must
address those needs.

In order to determine what an "alternative" to jQuery must address it must
be determined first what the strong points of jQuery really are, beyond
marketing babble, and after that if those strong points are good points
after all.

Because, for example, querying elements per CSS selector, which was
apparently Resig's incentive to write jQuery is in fact not a top priority
when it comes to DOM scripting. It is instead that Resig didn't get the
ideas of, first, modifying stylesheet selectors or adding new stylesheets;
that is why with jQuery elements are selected by CSS selector in order to
modify their style. And then b) well-documented event delegation (and event
bubbling in particular) which makes the whole expensive, unreliable, and
error-prone "add a listener to a static set of similar element objects"
routine that jQuery is able to do rather superfluous.

So, can you list the strong (technical) points of jQuery without resorting
to marketing babble? Then you will be in a position to suggest a jQuery
"alternative".


PointedEars
 
G

Garrett Smith

Lasse said:
[...]


Try it! Add the following to a page and try it in different browsers:

<script type="text/javascript">
function testArgs() {
function f1(a) {
if (true) { return; } else { return arguments.a; }
}
function f2(a) {
if (true) { return; } else { return a.a; }
}

var t0 = new Date();
for (var i = 0; i < 100000; i++) {
f1();
}
var t1 = new Date();
for (var i = 0; i < 100000; i++) {
f2();
}
var t2 = new Date();
return (t1 - t0) / (t2 - t1);
}
window.onload = function(){ alert(testArgs()); };
</script>

My results (approx):
Opera 9.6 : 8
Firefox 3.0.8 : 1
Chrome 2.0.171.0 : 5.5
Safari 4 beta : 8
IE 7 : 1

So three out of five browsers do indeed get slower calling a function that
mentions the arguments object, even if it isn't accessed at all.

Would it be possible for an implementation to optimize those function
calls to omit the unreachable code?

Could function f1 be optimized to:-

function f1(a) {
return;
}

?
So much for being right :)

/L

Garrett
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:
Lasse Reichstein Nielsen wrote:

Your argument is inconclusive,

It's not an argument. It's a statement of fact.
of course, because if the arguments object is referred to in a
non-obvious fashion (i.e., not simply `arguments') it would need to
be created during execution and thus cost during execution.

The only non-obvious fashion for accessing the arguments object is using eval.
If you use eval, all bets are off, and the arguments object will be created
in all cases, just as many other optimizations are disabled.

Not creating the arguments object is an optimization.
If the function doesn't contain the identifier "arguments", and it doesn't
contain a call to "eval", then there is no way to access the arguments object
(unless the engine supports the non-standard arguments property on function
objects, in which case it probably won't be created until it's requested).
And to determine before execution whether it is referred to in a
non-obvious fashion is even more expensive.

Nope. Cheap and easy. When reading an identifier expression, check
whether it's "arguments". If so, mark the function as using "arguments".
If it doesn't use "arguments" and it doesn't use "eval" (which you are
checking for anyway), don't create the arguments objet.
Nonsense. The Specification says the argument object MUST be created when
control enters an execution context for function code, and then it goes on
to describe the features this object is to provide. Period. It makes no
statement about how this object can be referred to or when it can be
garbage-collected.

That might actually be true. If so, it's a flaw in the specification.

I.e., everybody else understands that a semantics specification is
not an implementation mandate, and if the same visible semantics can
be implemented more efficiently (like it says in section 5.2), then
that's great.

Or, to use your own words: It makes no statement about how the object
must be represented in memory. Or that there is a memory at all.
So it is perfectly legal to implement the "arguments" property of
the function's variables object virtually - i.e., with no physical
representation, and only manifest it if/when it is actually needed.
And there are good reasons why it does this:

function foo()
{
var s = "a"
+ /%72%67%75%6d%65%6e%74/.source.replace(
/%([\da-f]+)/g,
function(m, p1) {
return String.fromCharCode(parseInt(p1, 16)));
})
+ "s";

/* ReferenceError? */
eval('try { window.external[foo[0]]; }'
+ 'catch (e) { throw new Error("Inaccessible first argument"); }');
}

foo("addFavorite");


Uses a direct call to eval, so optimizations are disabled.
That's another good reason for not using eval.
It is a deliberately extreme example, of course, because those help to see
the bigger picture.

Nothing new to see there.
That they do it is no indication that what they do is the correct approach
or even standards-compliant.

Ah, but I say it is, and it appears that ECMAScript implementors from
Apple, Google and Opera think so too. And the only way you can prove
me, or them, wrong is to find a program that gives the wrong result in
one of those implementations due to that optimization.

So, put your coding skills where your mouth is. I dare you.
/L
 
L

Lasse Reichstein Nielsen

Garrett Smith said:
Lasse Reichstein Nielsen wrote: .... ....
Would it be possible for an implementation to optimize those function
calls to omit the unreachable code?

Could function f1 be optimized to:-

function f1(a) {
return;
}

I see no reason why they shouldn't be able to.

There are some non-standard features that prevents you from always
removing a branch completely (in particular function declarations that
are not at top-level, but are still evaluated when the function is
first entered).

/L
 
G

Garrett Smith

Lasse said:
I see no reason why they shouldn't be able to.

There are some non-standard features that prevents you from always
removing a branch completely (in particular function declarations that
are not at top-level, but are still evaluated when the function is
first entered).

I'm not sure what you mean by not "top-level". Do you mean a
FunctionStatement?

function y() {}

function a() {
if(true) {
function x(){};
x();
} else {
y();
}
}

?

The FunctionStatement is a non-standard extension. If that block were
removed, the containing function would have the same result in
implementations with that non-standard feature.

Or do you mean something else?

Garrett
 
L

Lasse Reichstein Nielsen

Garrett Smith said:
I'm not sure what you mean by not "top-level". Do you mean a
FunctionStatement?

Maybe, I'm not sure exactly what a FunctionStatement is, since
it's not standard, but it's probably what I'm thinking of.

As for "top-level", I mean "not as a SourceElement". SourceElement's
can only occur at the "top level" of a FunctionBody and a Program, but
not inside a statement Block.
function y() {}

function a() {
if(true) {
function x(){};
x();
} else {
y();
}
}

?

The FunctionStatement is a non-standard extension. If that block were
removed, the containing function would have the same result in
implementations with that non-standard feature.

Yes, but if you moved the function statement to the other branch, what
would then happen?

In IE, there is no "function statement", instead it allows function
declarations inside block statements.

I.e.,
(function(){
if (true) { return f(); }
else { function f() { return 42; } }
})()
evaluates to 42. Dropping the second branch would change the behavior.

Another case where it matters is:

var x = 42;
(function () {
if (true) {
x = 37;
} else {
var x;
}
})();
alert(x); // should alert 42.

If you remove the dead branch from this at the syntax level, the local
variable declaration will be removed and the scope of "x" changed.

/L
 
G

Garrett Smith

Lasse said:
[...]


I.e.,
(function(){
if (true) { return f(); }
else { function f() { return 42; } }
})()
evaluates to 42. Dropping the second branch would change the behavior.

An implementation that does not support the non-standard extension of
functionStatement (IE, Opera) would evaluate, on first-pass, function
f() { return 42; }, as a FunctionDeclaration.

That is demonstrated by the fact that the call of said function occurs
prior to its declaration.

I do not see a problem here, though. Implementations of
FunctionStatement can, without harm, remove the second branch to have
the same result (ReferenceError).

Another case where it matters is:

var x = 42;
(function () {
if (true) {
x = 37;
} else {
var x;
}
})();
alert(x); // should alert 42.

If you remove the dead branch from this at the syntax level, the local
variable declaration will be removed and the scope of "x" changed.

That is true. The same would be a problem for FunctionStatement, which
is evaluated on second-pass.

<script type="text/javascript">
function x() {
return "global x";
}
function callX() {
return x();
if(true) {
} else {
function x(){ return "local x"; }
}
}
document.write("callX() " + callX());
</script>

Firefox:
"global x"

Opera, IE, Webkit, Chrome:
"local x"

Garrett
 
T

Thomas 'PointedEars' Lahn

I'm only online on iPhone for the time being, so I'll keep my answers
short (and sorry in advance for bad quoting, selection and copy-paste
has been promised for summer.)

Lasse Reichstein Nielsen said:
It's not an argument. It's a statement of fact.

An assumption (about other implementations that is based on mere
observation) is never a statement of fact.
The only non-obvious fashion for accessing the arguments object is
using eval.

No. Remove the eval() wrapping from my example and the problem remains.
If you use eval, all bets are off, and the arguments object will be
created
in all cases, just as many other optimizations are disabled.

Not creating the arguments object is an optimization.
If the function doesn't contain the identifier "arguments", and it
doesn't
contain a call to "eval", then there is no way to access the arguments
object
(unless the engine supports the non-standard arguments property on
function
objects, in which case it probably won't be created until it's
requested).


Nope. Cheap and easy.

You're not making sense. If it was cheap and easy, why the need for
optimization?
When reading an identifier expression, check
whether it's "arguments". [...]

I have showed that considering Identifiers does not suffice at all.
That might actually be true. If so, it's a flaw in the specification.
YMMD.

I.e., everybody else understands that a semantics specification is
not an implementation mandate, and if the same visible semantics can
be implemented more efficiently (like it says in section 5.2), then
that's great.

Or, to use your own words: It makes no statement about how the object
must be represented in memory. Or that there is a memory at all.

I have never said that.
So it is perfectly legal to implement the "arguments" property of
the function's variables object virtually - i.e., with no physical
representation, and only manifest it if/when it is actually needed.

Not if "legal" means "standards-compliant."
And there are good reasons why it does this:

function foo()
{
var s = "a"
+ /%72%67%75%6d%65%6e%74/.source.replace(
/%([\da-f]+)/g,
function(m, p1) {
return String.fromCharCode(parseInt(p1, 16)));
})
+ "s";

/* ReferenceError? */
eval('try { window.external[foo[0]]; }'
+ 'catch (e) { throw new Error("Inaccessible first
argument"); }');
}

foo("addFavorite");


Uses a direct call to eval, so optimizations are disabled.
That's another good reason for not using eval.
It is a deliberately extreme example, of course, because those help
to see
the bigger picture.

Nothing new to see there.


Look closer.
Ah, but I say it is, and it appears that ECMAScript implementors from
Apple, Google and Opera think so too. And the only way you can prove
me, or them, wrong is to find a program that gives the wrong result in
one of those implementations due to that optimization.

So, put your coding skills where your mouth is. I dare you.

I think I did already.


PointedEars
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:
I'm only online on iPhone for the time being, so I'll keep my answers
short (and sorry in advance for bad quoting, selection and copy-paste
has been promised for summer.)



No. Remove the eval() wrapping from my example and the problem remains.

Have you tried to remove eval? It won't work.

You can't access the arguments object without either using the identifier
"arguments" (because it's not available as a property of an accessible
object, so you can't use square-bracket notation to access it), or using
eval.

You're not making sense. If it was cheap and easy, why the need for
optimization?

We are talking about determining whether the optimization is safe.
That is cheap and easy.

Ok, it's not easy to determine whether it is definitly referred to in
a non-obvious fashion. If the function contains a direct call to eval,
it's actually impossible (Halting-equivalent).

But it's a safe and cheap approximation that the arguments object
*definitly* isn't accessed if the function body contains neither
the identifier "arguments" or a direct call to eval.
When reading an identifier expression, check
whether it's "arguments". [...]

I have showed that considering Identifiers does not suffice at all.

Yes, but not that considering identifiers *and* eval does not suffice.
I have never said that.

Your words were "It makes no statement about", as if that makes any
difference. It's the things it does make a statement about that matter.
Not if "legal" means "standards-compliant."

Yes, I mean standards-compliant. And how is it not standards
compliant? Do tell, where does the standard mandate that "creating an
object" must be implemented using bits in memory?

You mentioned that it didn't say anything about when an arguments
object can be garbage collected. In fact, the specification makes no
mention of garbage collection at all. Does that mean that you can't
destroy objects again? After all, it often says "create an object",
but never "destroy an object".

Is an implementation that removes objects (e.g., using garbage
collection) not standards compliant?

Is an implementation that creates an arguments object, and immediately
after remove it again if it isn't used by the program, not standards
compliant? If so, why not?

Is an implementation that optimizes the above to never manifest the
creation of the arguments object not standards compliant? If so, why
not?
I think I did already.

You might think so, but you are wrong.

You have *not* exhibited a program that would work differently in an
ECMAScript implementation that optimizes away the creation of unused
arguments objects (using the described algorithm to determine whether
it's safe to omit it). And especially not one that works differently
in any of the three browsers that do optimize arguments object
creation.

/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
Have you tried to remove eval?

Yes, I have (in a manner of speaking).
It won't work.

Yes, it does in Firefox/Iceweasel 3.0.6, JavaScript 1.8.

You can't access the arguments object without either using the
identifier
"arguments" (because it's not available as a property of an accessible
object, so you can't use square-bracket notation to access it), or
using
eval.

In JavaScript, Function objects have an ‘arguments’ property to refer to
the arguments object of the execution context entered when they are
[[Call]]ed or [[Construct]]ed. That property is marked as deprecated,
but it is still there in JavaScript 1.8.

If using the bracket property accessor did not work in the
implementation(s) you tested, then it would seem as if their
implementors had forgone both standards compliance (even and especially
if we assumed you were right about a behavioral specification, see
below) *and*, more important, compatibility.
We are talking about determining whether the optimization is safe.
That is cheap and easy.

Yes, I misread.
Ok, it's not easy to determine whether it is definitly referred to in
a non-obvious fashion. If the function contains a direct call to eval,
it's actually impossible (Halting-equivalent).

But it's a safe and cheap approximation that the arguments object
*definitly* isn't accessed if the function body contains neither
the identifier "arguments" or a direct call to eval.

Apparently, it is not.
When reading an identifier expression, check
whether it's "arguments". [...]

I have showed that considering Identifiers does not suffice at all.

Yes, but not that considering identifiers *and* eval does not suffice.

Parse error.

Your words were "It makes no statement about", as if that makes any
difference.

It makes a difference because the Specification allows implementations'
objects to have more properties than specified. We can readily observe
that this allowance has practical implications with JavaScript and its
capability of referring to arguments objects by a property of Function
objects.
It's the things it does make a statement about that matter.

In essence, It says the arguments object MUST be created then, no matter
what.
Yes, I mean standards-compliant. And how is it not standards
compliant?

Do tell, where does the standard mandate that "creating an
object" must be implemented using bits in memory?

Creation of the arguments object MUST happen "when control enters an
execution context for function code." Your argument about how creation
is to be facilitated is irrelevant to that requirement.
You mentioned that it didn't say anything about when an arguments
object can be garbage collected.

Yes, but I can see that this was quite confusing for you. Since it's not
really relevant here, let's just forget that I said it even though it is
true.
I think I did already.

You might think so, but you are wrong.

You have *not* exhibited a program that would work differently [...]

Your own statement about what happens when you remove the eval() wrapper
apparently contradicts that assessment.


PointedEars
 
M

Matt Kruse

Creation of the arguments object MUST happen "when control enters an
execution context for function code." Your argument about how creation
is to be facilitated is irrelevant to that requirement.

You kind of ignored my previous statements about how you would ever
know if it's created, as long as it behaves as if it was.

This is the nature of "truth" and "reality". As long as something fits
fully within your held model, and all observations and tests that can
perform result in predictable behavior, then it can be said that this
something does indeed exist to you.

If an implementation consistently behaves in a predictable way as if
an 'arguments' object was created, and no test you can perform would
show evidence to the contrary, then how can you say it was not
created? And why would you possibly care?

Matt Kruse
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:
Yes, I have (in a manner of speaking).

Aha. Do tell.
Yes, it does in Firefox/Iceweasel 3.0.6, JavaScript 1.8.

I wasn't talking about JavaScript, but about ECMAScript.
You can't access the arguments object without either using the
identifier
"arguments" (because it's not available as a property of an accessible
object, so you can't use square-bracket notation to access it), or
using
eval.

In JavaScript, Function objects have an ‘arguments’ property to refer to
the arguments object of the execution context entered when they are
[[Call]]ed or [[Construct]]ed. That property is marked as deprecated,
but it is still there in JavaScript 1.8.

Yes, I mentioned it a few messages ago, as a different problem.

But it's true that there has to be some magic behind the the arguments
property on function objects that manifest the arguments object when
necessary. Luckily, that's rarely necessary.
If using the bracket property accessor did not work in the
implementation(s) you tested, then it would seem as if their
implementors had forgone both standards compliance (even and especially
if we assumed you were right about a behavioral specification, see
below) *and*, more important, compatibility.

I specifically was not talking about accessing the arguments object
through the function object (a non-standard feature).

....
In essence, It says the arguments object MUST be created then, no matter
what.

But it doesn't say what "creating an object" entails, only what
properties it must have when interacted with through the language.
Nothing requires an object to be represented by physical bits, unless
they are necessary to satisfy the semantics of a program. I.e., they
can be, effectively, be omitted.
Creation of the arguments object MUST happen "when control enters an
execution context for function code."

You didn't answer the question. Where does it say that creating an object
must be represented using bits in memory?
I.e., how can you say that an object isn't created, just because it has
no physical representation at that time?
Your argument about how creation is to be facilitated is irrelevant
to that requirement.

No. I claim that an object can be "created" without any physical
representation, while still being standards compliant - because
the standard doesn't say anything about how an object is created,
or how it must be represented.
Yes, but I can see that this was quite confusing for you. Since it's not
really relevant here, let's just forget that I said it even though it is
true.

How conventient, since it is actually at the crux of the discussion.
I would still like you to try and answer the three questions you
snipped:

1. Is an implementation that removes objects (e.g., using garbage
collection) not standards compliant?

2. Is an implementation that creates an arguments object, and
immediately after remove it again if it isn't used by the program, not
standards compliant? If so, why not?

3. Is an implementation that optimizes the above to never manifest the
creation of the arguments object not standards compliant? If so, why
not?


You have *not* exhibited a program that would work differently [...]

Your own statement about what happens when you remove the eval() wrapper
apparently contradicts that assessment.

If you remove the eval wrapper, you have either
- is just a string (just removing the call to eval),
- something that doesn't compile (just retaining the contents of the string
as code), or
- code that contains the identifier "arguments".


I agree that accessing the arguments object through the function
object is another way to access it (and even from another function
scope). It is possible to delay creation of the arguments object
until such an access (whcih is probably also done by the
implementations that optimize the arguments object creation - since it
works).

/L
 

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,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top