Guidlines for Avoiding ASI-related errors

G

Garrett Smith

ASI - Automatic Semicolon Insertions

Semicolon is inserted in various places where a statement could be
terminated, but is not. General advice, taken from the specification,
with my own addition.

Semicolons
* A postfix ++ or -- operator should appear on the same line as its
operand.
* An Expression in a return or throw statement should start on the
same line as the return or throw token.
* An Identifier in a break or continue statement should be on the same
line as the break or continue token.
* Semicolons should appear explicitly where they are required.

The last one is my addition. It is debatable but generally true. What
follows a newline-ending expression determines whether the semicolon is
inserted or not.

The advice semicolons should appear explicitly where they are required
provides a general guideline that makes a program more resilient to
errors that could be introduced by minification or inadvertent changes
in source code whitespace, including whitespace in comments, and order
of expressions.

A FunctionExpression that is followed by a newline, then followed by
grouping operator, will be interpreted as a CallExpression, implicating
the FunctionExpression in the call. For example, if the developer wanted
to declare a MyWidget constructor, and then do some initializations in a
closure following it, he might use:

var MyWidget = function a(){
this.name = "mike";
}
/**
* Initialize Widget
*/
(function() {
/*...*/
});

- but the problem with that is that the FunctionExpression would be
called because the parentheses, which were intended to be a grouping
operator, were interpreted as a part of CallExpression, resulting in
MyWidget having the value undefined window.name getting the value
"mike", just as:

var MyWidget = function(){
this.name = "mike";
}(function(){});

- would have the same effect, more obviously.

Line terminators in comments may also affect ASI. If comment begins at
the end of an expression and it contains a line terminator, a semicolon
should be automatically inserted. Not all implementations will do that,
however.

For example:

var MyWidget = function a(){
return {toString: function(){return"widget"}};
}/*
*/g = 2;

Conforming implementations consider whitespace in comments and so the
program can run. JScript, however, does not run the program.

Consistent failure can be expected from:

var MyWidget = function(){
this.name = "mike";
}/** Initialize Widget */g = 2;

- because the comment following the FunctionExpression does not contain
a line terminator. If a line terminator is added, then the program
should be interpreted with a semicolon being automatically inserted
immediately following the FunctionExpression. As stated, not all
implementations do that.

From ES5, 5.1.2:
| A MultiLineComment (that is, a comment of the form /*...*/
| regardless of whether it spans more than one line) is likewise simply
| discarded if it contains no line terminator; but if a MultiLineComment
| contains one or more line terminators, then it is replaced by a single
| line terminator, which becomes part of the stream of input elements
| for the syntactic grammar.

Question: How does a MultiLineComment can span more than one line and
not contain a line terminator?

Regardless, the complexities of automatic semicolon insertion are
undesirable and should be avoided. The advice provided aims to help
avoid those problems.

Comments or suggestions?
 
J

John G Harris

ASI - Automatic Semicolon Insertions

'Insertion', singular, would read better.
Semicolon

'A semicolon' would make it easier to read.
is inserted in various places where a statement could be
terminated, but is not. General advice, taken from the specification,
with my own addition.

Semicolons
* A postfix ++ or -- operator should appear on the same line as its
operand.
* An Expression in a return or throw statement should start on the
same line as the return or throw token.
* An Identifier in a break or continue statement should be on the same
line as the break or continue token.

'should' ought to be 'must' as it's not optional, not even slightly.
(Never mind what the standard says).
* Semicolons should appear explicitly where they are required.

The last one is my addition. It is debatable but generally true.

Maybe 'should' is a little too strong. Remember that some people are
violently opposed to using semicolons in a 'scripting' language. They
might be less annoyed if you said 'It is recommended, for the following
reasons, that' ...
What follows a newline-ending expression determines whether the
semicolon is inserted or not.

The advice semicolons

'The advice that semicolons'
should appear explicitly where they are required provides a general
guideline that makes a program more resilient to errors that could be
introduced by minification or inadvertent changes in source code
whitespace, including whitespace in comments, and order of expressions.

A FunctionExpression that is followed by a newline, then followed by
grouping operator, will be interpreted as a CallExpression, implicating
the FunctionExpression in the call. For example, if the developer
wanted to declare a MyWidget constructor, and then do some
initializations in a closure following it, he might use:

var MyWidget = function a(){
this.name = "mike";
}
/**
* Initialize Widget
*/
(function() {
/*...*/
});

- but the problem with that is that the FunctionExpression would be
called because the parentheses, which were intended to be a grouping
operator, were interpreted as a part of CallExpression, resulting in
MyWidget having the value undefined window.name getting the value
"mike", just as:

var MyWidget = function(){
this.name = "mike";
}(function(){});

- would have the same effect, more obviously.

Line terminators in comments may also affect ASI. If comment begins at

'If a comment'
the end of an expression and it contains a line terminator, a semicolon
should

'ought to'
be automatically inserted. Not all implementations will do that,
however.

For example:

var MyWidget = function a(){
return {toString: function(){return"widget"}};
}/*
*/g = 2;

Conforming implementations consider whitespace in comments and so the
program can run.

Not really whitespace; they need only test for line terminators.
JScript, however, does not run the program.
Shame!

Consistent failure can be expected from:

var MyWidget = function(){
this.name = "mike";
}/** Initialize Widget */g = 2;

- because the comment following the FunctionExpression does not contain
a line terminator. If a line terminator is added, then the program
should be interpreted with a semicolon being automatically inserted
immediately following the FunctionExpression. As stated, not all
implementations do that.

From ES5, 5.1.2:
| A MultiLineComment (that is, a comment of the form /*...*/
| regardless of whether it spans more than one line) is likewise simply
| discarded if it contains no line terminator; but if a MultiLineComment
| contains one or more line terminators, then it is replaced by a single
| line terminator, which becomes part of the stream of input elements
| for the syntactic grammar.

Question: How does a MultiLineComment can span more than one line and
not contain a line terminator?

Vertical tab and form feed can, on a glass teletype, make the text
multiline without there being a LineTerminator character.
Regardless, the complexities of automatic semicolon insertion are
undesirable and should be avoided. The advice provided aims to help
avoid those problems.

Comments or suggestions?

John
 
G

Garrett Smith

John said:
'Insertion', singular, would read better.


'A semicolon' would make it easier to read.

Yes it would.
'should' ought to be 'must' as it's not optional, not even slightly.
(Never mind what the standard says).

You're right.
Maybe 'should' is a little too strong. Remember that some people are
violently opposed to using semicolons in a 'scripting' language. They
might be less annoyed if you said 'It is recommended, for the following
reasons, that' ...


'The advice that semicolons'

Right. (I actually meant that as a quote; The advice "semicolons should
appear explicitly where they are required").
'If a comment'


'ought to'

'is'.

If a comment begins at the end of an expression and it contains a line
terminator, a semicolon is automatically inserted after the expression.
Not really whitespace; they need only test for line terminators.

Right.


Shame!

If ASI is avoided, it doesn't matter. The lineTerminator in comment is a
complicated aspect of ASI. ASI seems best avoided. The code using a
semicolon explicitly, where that is needed, costs only one character.

The specification does not mention non-restricted productions, such as
Grouping Operator, which can match Arguments, if preceded by a Token.

For example, in the first line, we have a CallExpression, and then
following that, an ArrayLiteral.

Here, we can see an example that "works":

var a = 0
var x = [].slice(document.childNodes)
var y = a--
[].splice.call(x);

- and when y is changed to pre-increment, the character '[' looks like
property Accessor, and so it is interpreted as that, and when ']' is
reached instead of an expression, a SyntaxError results.

var a = 0
var x = [].slice(document.childNodes)
var y = --a
[].splice.call(x);


And grouping operator accidentally becoming Arguments in CallExpression,
as shown earlier. Another example of that:

a.
var c = 19, b = 10;
var a = b + c
(a + b).toString()

b.
var c = 19, b = 10;
var a = b + c
(a + b).toString()


A program that uses semicolons explicitly is more resilient to changes
that could be introduced by minification, inadvertent changes in line
terminators, changes in order of expressions, and changes in comments.

I've included some of this in the Code Guidelines doc:

http://jibbering.com/faq/notes/code-guidelines/#asi

I wanted to include some examples where relying on ASI causes problems
but it ended up getting a little longer than I wanted.
Vertical tab and form feed can, on a glass teletype, make the text
multiline without there being a LineTerminator character.
OK.
 
G

Garrett Smith

Garrett said:
[...]

If a comment begins at the end of an expression and it contains a line
terminator, a semicolon is automatically inserted after the expression.

Reread: That explanation is wrong.

A a MultiLineComment that contains a LineTerminator is replaced by a
LineTerminator. If that LineTerminator would result in a place where a
semicolon could be inserted, then a semicolon is inserted.

Fixed.
 
J

John G Harris

<snip>
Here is an additional comment.

It would be useful to add a remark that some statements do *not* end
with a semicolon. If you add a semicolon after one of these you are
adding an Empty statement, which can cause trouble in some
circumstances.

The statements that don't end in semicolon all end in close curly
bracket instead. They are :

Block -
{ ... }

Switch Statement -
switch ( ... ) { ... }

Try Statement -
try ... catch ( ... ) { ... }
try ... finally { ... }

And also there is something that isn't a statement but resembles one :

Function Declaration -
function ... { ... }


John
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]
september.org>, Sun, 16 May 2010 16:01:06, Garrett Smith
ASI - Automatic Semicolon Insertions

Semicolon is inserted in various places where a statement could be
terminated, but is not. General advice, taken from the specification,
with my own addition.

Semicolons
* A postfix ++ or -- operator should appear on the same line as its
operand.

Advising against something which browsers etc. do not accept is hardly
necessary; and, if done, then use 'must' rather than 'should'.
* Semicolons should appear explicitly where they are required.

If they are required, clearly they must appear. You have a meaning, but
your words do not express it.


One should disregard those who write and deploy code without any
testing; therefore there need be no concern about what browsers detect
as errors, or what the simplest test must discover. and locate easily.

I suggest listing all of the cases where, in ordinary code, semicolon
insertion might be mis-predicted without necessarily causing an
immediately-located error. A prime case there seems to be insertion
between a return and its expression.
 
G

Garrett Smith

John said:
<snip>
Here is an additional comment.

It would be useful to add a remark that some statements do *not* end
with a semicolon. If you add a semicolon after one of these you are
adding an Empty statement, which can cause trouble in some
circumstances.

I thought of that, but realized that the case was not about formatting,
but about statements. The Statements section states:

"Do not use useless statements"

Is that too terse? Where is the right place for advice on
EmptyStatement? Should it go in "Statements" or does it belong under
"Formatting > Semicolons"?

The section "Formatting > "Semicolons", as it is written now, is focused
on how ASI affects a program and how to avoid that. A useless
EmptyStatement won't trigger an ASI related problem so advice on
EmptyStatement doesn't quite seem to fit there.

Should the section "Formatting > "Semicolons" include advice about when
not to include semicolon following the section on ASI? Should the
section on Statements mention that blocks don't need Semicolons? Or is
the section on Statements enough?
 
J

John G Harris

I thought of that, but realized that the case was not about formatting,
but about statements. The Statements section states:

"Do not use useless statements"

Is that too terse? Where is the right place for advice on
EmptyStatement? Should it go in "Statements" or does it belong under
"Formatting > Semicolons"?

The section "Formatting > "Semicolons", as it is written now, is
focused on how ASI affects a program and how to avoid that. A useless
EmptyStatement won't trigger an ASI related problem so advice on
EmptyStatement doesn't quite seem to fit there.

Should the section "Formatting > "Semicolons" include advice about when
not to include semicolon following the section on ASI? Should the
section on Statements mention that blocks don't need Semicolons? Or is
the section on Statements enough?

The trouble is that many people, not just beginners, are hazy about
statements and more so about where the implied semicolons go. They are
likely to insert semicolons almost at random without really knowing why.

If an error message says that an else is a syntax error then experienced
programmers will know to track backwards to see where the parser got
confused. Beginners tend to think that it's the else that's wrong and
waste a lot of time messing about, especially if they don't realise that
a semicolon can be causing the trouble.

That's why I think something should be said in the ASI part, even if
it's only a short sentence.

John
 
J

John G Harris

In comp.lang.javascript message <[email protected]
september.org>, Sun, 16 May 2010 16:01:06, Garrett Smith


Advising against something which browsers etc. do not accept is hardly
necessary; and, if done, then use 'must' rather than 'should'.

Which browsers don't accept this :
a
++
b
and how many beginners know for sure how it ought to be parsed ?


One should disregard those who write and deploy code without any
testing; therefore there need be no concern about what browsers detect
as errors, or what the simplest test must discover. and locate easily.
<snip>

Provided you remember to test with browsers that do detect it as an
error.

John
 
G

Garrett Smith

Dr said:
In comp.lang.javascript message <[email protected]
september.org>, Sun, 16 May 2010 16:01:06, Garrett Smith
ASI - Automatic Semicolon Insertions
[...]
* Semicolons should appear explicitly where they are required.

If they are required, clearly they must appear. You have a meaning, but
your words do not express it.

Certain statements are required to be terminated by a semicolon.

When a required semicolon is not explicitly supplied, one is
automatically inserted in certain situations.

Explicit use of required semicolons can help to avoid some problems with
ASI. Those problems are explained.

The current wording in the code guidelines document, in context:

| ASI Guidelines for Semicolons in Source Code:
|
| * Don't rely on ASI. Use semicolons explicitly.
|
| Productions that are not restricted can be created accidentally where
| ASI has been used. This is often the result of where the developer
| forgot to use a semicolon. Regardless, the problems it creates can
| occur when the order of Statements changes or when line terminators
| are added or removed, including those that appear in comments. Where
| semicolons are needed, it is recommended that they appear explicitly.
|

That paragraph is followed by explanation and examples.
One should disregard those who write and deploy code without any
testing; therefore there need be no concern about what browsers detect
as errors, or what the simplest test must discover. and locate easily.

I suggest listing all of the cases where, in ordinary code, semicolon
insertion might be mis-predicted without necessarily causing an
immediately-located error. A prime case there seems to be insertion
between a return and its expression.
That is only one of the three on the list.

ASI Guidelines for restricted productions:

| * A postfix ++ or -- operator must appear on the same line as its
| operand.
| * An Expression in a return or throw statement must start on the same
| line as the return or throw token.
| * An Identifier in a break or continue statement must be on the same
| line as the break or continue token.

John G Harris addressed postfix operators with an example. Are the cases
with `throw` and `break` confusing? If can provide an example if that is
necessary.
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]
8924D9443D28E23ED5CD>, Wed, 19 May 2010 17:14:05, John G Harris
Which browsers don't accept this :
a
++
b
and how many beginners know for sure how it ought to be parsed ?

No reasonable beginner would put either a pre- or a post- fix operator
in a different line to its operand. The language standard ought to
disallow it, as being unnecessary. In fact, I cannot actually recall
seeing ++ or -- with whitespace between itself and its operand.
 
D

dhtml

  <snip>








The trouble is that many people, not just beginners, are hazy about
statements and more so about where the implied semicolons go. They are
likely to insert semicolons almost at random without really knowing why.

If an error message says that an else is a syntax error then experienced
programmers will know to track backwards to see where the parser got
confused. Beginners tend to think that it's the else that's wrong and
waste a lot of time messing about, especially if they don't realise that
a semicolon can be causing the trouble.

That's why I think something should be said in the ASI part, even if
it's only a short sentence.

I have been thinking about this -- I have not forgotten. I will come
back to this. If it turns out that the section is too long, as it
already seems long, I might just extract it to its own document. The
Code Guidelines document should be scannable, so a reviewer can go
over it quickly and thoroughly. A preflight checklist should not delve
into turgid details about the physics of oil viscosity, thermodynamics
and cowl flaps work, etc. No; only mentioning those things briefly, as
necessary to make sure that the plane is ready to fly.

At the moment, I am having some issues with my computer and will
probably need to reinstall Windows. Well, that is what I get for
buying things off eBay. Never again.

Aside from that, I started a draft proposal for a JSON entry. I am not
done pre-editing that draft.

I'll post up a change, probably (hopefully) within 6 days.
 
D

David Mark

dhtml said:
I have been thinking about this -- I have not forgotten. I will come
back to this. If it turns out that the section is too long, as it
already seems long, I might just extract it to its own document. The
Code Guidelines document should be scannable, so a reviewer can go
over it quickly and thoroughly. A preflight checklist should not delve
into turgid details about the physics of oil viscosity, thermodynamics
and cowl flaps work, etc. No; only mentioning those things briefly, as
necessary to make sure that the plane is ready to fly.

At the moment, I am having some issues with my computer and will
probably need to reinstall Windows. Well, that is what I get for
buying things off eBay. Never again.

Aside from that, I started a draft proposal for a JSON entry. I am not
done pre-editing that draft.

I'll post up a change, probably (hopefully) within 6 days.

Fix the spelling errors/typos in the browser detection article as well.
"Near-cited" instead of near-sighted and "round" instead of "around".

And what's with the interjected bit about double-negation? It is
completely out of place and sucks all of the momentum out of the piece.
Just change the miserable example (and remove the long-winded
explanation about the ternary operator, boolean type conversion, etc.,
which are also unneeded).
 
D

dhtml

Fix the spelling errors/typos in the browser detection article as well.
 "Near-cited" instead of near-sighted and "round" instead of "around".

It is actually "near-sited" that needs to be near-sighted and "round"
that can be changed to "around", in the sentence "To get round this
problem". The second change is not necessarily a grammatical fix,
though. Keep in mind that "round" may have been used as a verb
intentionally there, omitting the "a". However, considering that later
on, there is a very similar sounding sentence using "around": "To get
around the problem".

Easy changes, already done and uploaded.
And what's with the interjected bit about double-negation?  It is

That, you had wanted at font-size: 90%. Did you change your mind?

Stockton wanted a border on it.
completely out of place and sucks all of the momentum out of the piece.
  Just change the miserable example (and remove the long-winded
explanation about the ternary operator, boolean type conversion, etc.,
which are also unneeded).

That might want to just link to here:
http://www.jibbering.com/faq/notes/type-conversion/#tcBool

| Incidentally, this code is not the optimum method of assigning a
boolean
| value based on the type converted to boolean result of a property
accessor.
| It is better to use the javascript NOT operator ( ! ) twice or to
pass the
| object reference as the argument to the Boolean constructor called
as a function (_more_).

Where _more_ links to the article on type conversion.

Other fixes that will take more time include that of my operating
system, and the backing up of files.

Garrett
 
D

David Mark

dhtml said:
It is actually "near-sited" that needs to be near-sighted and "round"
that can be changed to "around", in the sentence "To get round this
problem". The second change is not necessarily a grammatical fix,
though. Keep in mind that "round" may have been used as a verb
intentionally there, omitting the "a". However, considering that later
on, there is a very similar sounding sentence using "around": "To get
around the problem".

Easy changes, already done and uploaded.


That, you had wanted at font-size: 90%. Did you change your mind?

I don't recall commenting on the font size. It's the first I've seen
it. (?)

My point is it doesn't belong in the middle of that article.
Stockton wanted a border on it.

I agree that the PRE should have a border, but that is beside the point.

Why not just fix the example...
| Incidentally, this code is not the optimum method of assigning a
boolean
| value based on the type converted to boolean result of a property
accessor.
| It is better to use the javascript NOT operator ( ! ) twice or to
pass the
| object reference as the argument to the Boolean constructor called
as a function (_more_).

....then you don't need to interject this bit at all. It's out of place
in the browser detection article.
 
G

Garrett Smith

The trouble is that many people, not just beginners, are hazy about
statements and more so about where the implied semicolons go. They are
likely to insert semicolons almost at random without really knowing why.

If an error message says that an else is a syntax error then experienced
programmers will know to track backwards to see where the parser got
confused. Beginners tend to think that it's the else that's wrong and
waste a lot of time messing about, especially if they don't realise that
a semicolon can be causing the trouble.

That's why I think something should be said in the ASI part, even if
it's only a short sentence.

I added a section on when not to use a semicolon under Formatting:
Semicolons.

I moved the explanations about problems in productions that are not
restricted to a separate document, to help keep the code guidelines at a
higher level overview.

I have also noticed a syntax extension that I was previously unaware of:
A do-while loop that is followed by an Statement is evaluated as if the
while loop had been terminated by a semicolon;

// SyntaxError
var i = 0;
do {
alert(i++);
} while(0) alert("done " + i);

What is the reasoning for allowing that? It looks like a mistake on part
of the developer. It seems more desirable to have the program fail in
SyntaxError so that the problem could be detected.

Garrett
 
G

Garrett Smith

[snip]
That, you had wanted at font-size: 90%. Did you change your mind?

I don't recall commenting on the font size. It's the first I've seen
it. (?)

I'm pretty sure you wanted 90%.
My point is it doesn't belong in the middle of that article.


I agree that the PRE should have a border, but that is beside the point.

No not the PRE, the little subsection. You wanted it 90% I'm pretty sure
about it.

Found it:
http://webcache.googleusercontent.c...hl=en&ct=clnk&gl=us&ie=UTF-8&client=firefox-a

You should be more careful about what you wish for; you might just get it.

Coincidentally, I google searched for the thread (google's real search,
not broken groups search), and the search result had the link to the
google groups thread I was searching for, and when I clicked on that
link, I was not taken to the thread, as I was expecting. Instead, I was
redirected to the google account sign in page.
Why not just fix the example...

Which example is broken? Or do you mean remove the "Boolean Conversion
Tip: !!" note?

I can do that, but I was suggesting toning it down as an alternative and
linking to the article. Subdued proposal:

| Incidentally, this code is not the optimum method of assigning a
| boolean value based on the type converted to boolean result of a
| property accessor. It is better to use the javascript NOT operator
| ( ! ) twice or to pass the object reference as the argument to the
| Boolean constructor called as a function (_more_).

What does the author have to say on that? 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

Forum statistics

Threads
473,767
Messages
2,569,570
Members
45,045
Latest member
DRCM

Latest Threads

Top