末尾セミコロンはしばしば宗教戦争になりますね。
Qiitaでもその他のSNS等でも、そのようなバトルはいくらでも見つかります。
しかし意外にも、この戦争の原因を大本まで辿ってる人はほとんど見当たりません。
見つけたものではこの人(と、この記事を参照している記事)くらいでした。
以下は、JavaScriptの末尾セミコロンについて、JavaScriptの生みの親であるBrendan Eichによる見解、The infernal semicolonの紹介です。
なお2012年の記事なので、存在しないリンクや古くなった知見が含まれる可能性があります。
The infernal semicolon
このツリーのコメントを見るたびに、私は悲しみに包まれます。
問題のコード、
clearMenus()
!isActive && $parent.toggleClass('open')
このコードは自動セミコロン挿入(ASI)に依存しているため、ミニファイを行うためには、ASIを含めた完全なパースを行い、clearMenus()
の次の改行の意味を調べて改行を削除すると同時にセミコロンを挿入しなければなりません。
これはJSMinのバグであるという意見もあるようですが、Doug Crockfordはコードの変更を拒否しました。
参考までに、私はDougの意見に賛成です。
また私は、@cramforceと@jedschmidtの意見にも同意します。
この&&
の使い方は、この言語がJavaからの流れを汲んでいるから許されているにすぎない濫用であり、if文のほうがより良いスタイルであることは間違いありません。
すなわち、JSMinのほうが正しい姿勢でしょう。
しかし、この姿勢は「ASIとミニファイを両方動かしてくれ」を解決するにはあまりにアドホックです。
TC39は、!
を中置演算子として使うことを検討している。
このコードは早晩動かなくなることだろう。
セミコロンの正しい使い方を学んでくれ。
中置演算子としての!
はPromiseのシンタックスシュガーであり、まだ正式な構文は決まってないし、他の構文になる可能性もあります。
とはいえ、Dougの言うとおり、!
は文の終端でもなければ開始地点でもありません。
そして私が追加で主張したいのは、改行も同様である、ということです。
Promiseのプロポーザルで[nlth]
を調べると、ASIと中置演算子について驚くようなことが書かれています。
すなわち、将来的に新しい中置演算子を追加する可能性があるし、それどころかis
やisnt
のようなキーワード演算子も追加する可能性があるというのです。
そして、それらの中置演算子は、[no LineTerminator here]
とさます。
ECMA-262では[no LineTerminator here]
はそこに終端が許可されないことを示し、たとえばreturn
の右に返り値を書かない改行などを表します。
中置演算子の将来変更されるかもしれない機能の変更は、改行コードに敏感であるASIに直接的に影響します。
let flag = x is y; //
x ! p = v; //
Bootstrap自体は優れたライブラリですが、Bootstrapの2行のコードについてはとても悪いというDougの主張について、私は同意します。
この例の1行目の終端記号は、たしかに重要です。
この話の教訓として、ASIは構文エラーを修正する手続きにしかすぎません。
ASIが普遍的な構文規則であるかのようにコーディングしてしまうと、問題が発生します。
これはECMA-262の典型的な例です。
a = b + c
(d + e).print()
同様の問題は[
、/
、単項+
や-
等でも発生します。
なお、エラーがなければASIは適用されないことを覚えておいてください。
この問題は些細なことに思えるかもしれませんが、JavaScriptファイルの結合を始めるとより深刻になります。
そのため、DojoやIRCなど幾つかのスタイルガイドでは、ファイルの冒頭を;
で始めることを推奨していますが、だいたい忘れられがちです。
1995年5月のとある10日間、改行についてもっとよく考えておけばよかったと思います。
きっと、行継続にASIではなく、\
や括弧を必須にするようにしていたことでしょう。
しかし、この船はもう17年も前に出航してしまっていました。
JavaScriptで改行をシステマチックに扱うには、Harmonyによる括弧の使い方の進化が必要です。
私はこれに取り組むつもりですが、ES6ではもうできそうにありません。
GitHubのIssueには、素朴で理想的で、そしてとてもバカバカしいコメントが並んでいます。
いつからプログラミング言語には引数構文がなくなったのでしょうか?
私の知っているあらゆる実用的な言語は、書式に自由度を持っており、良い使い方と同じだけ悪い使い方も可能になっています。
言語設計者は、書き方の自由度を減らす努力はできても、それを完全に排除することはできません。
私の主張はふたつです。
JavaScriptの改行に影響を与えるようなASIの使い方をしないでください。
そして、if
文を使うべきところに&&
や||
を濫用しないでください。
また、JavaScriptの名状しがたく半端に長い歴史を鑑みて、私であればJSMinを修正するであろうと言っておきます。
もっとも、その前に刺々しいコメントのひとつふたつくらい吐いておくとは思いますけどね。
感想
ということで、JavaScriptの生みの親はセミコロン付けろ派でした。
ただし、この記事が書かれたのは2012年であり、その後isnt
なる演算子も消滅し、Standard StyleやらVueやらセミコロン付けないタイプのライブラリも多数進出してきてしまったので、今現在の考えがどうなっているかはわかりません。
あと記事内からの外部リンクが軒並み死んでたので、その先に何が書かれていたのがわからず、それに同意って何に同意なんだよというのがわからないのがだいぶ困りました。
とはいえ全体として、ASIはあくまで構文エラーを緩和する手段でしかないので、それに頼るべきではないという主張です。
ちなみに私は個人的には必ずセミコロンを付けますが、セミコロン付けろ派というよりは文法で禁止しろ派です。
どちらの書き方もできてしまうから紛糾するわけで、付けるにしろ付けないにしろ、どちらかの構文しか使えないようにすれば解決するわけですね。
まあ、こんな主張は互換性が崩れるので絶対通りませんが。
おまけ
発端となったのはbootstrapのIssueです。
englishextra「bootstrapのコードをJSMinでminifyしたら壊れるんだけど。ソースに;
入れてくれ。」
fat「いやそれJSMinのバグだから。Dougに言ってくれ。」
Doug「こんな非常識で愚劣なコードのためにJSMinをどうにかする気はない。」
以後はfatもDougも現れず、第三者同士によるぐだぐだバトルが200コメント以上続くことになりました。
fatはbootstrapのトップコントリビュータのひとりで、そしてDougはJSMinの作者です。
JSMinはJavaScriptコード中のコメントや不要な空白を削除し、サイズを小さくしてくれるライブラリです。
構文解析しているわけではなく形式的に変換しているので、上記のような問題が発生しました。
bootstrapがきちんと;
を入れておけば起こらないバグだということで、Dougは修正を拒否しています。
それにしてもThat is insanely stupid code.とは言いますね。
当時はきっと役立つライブラリだったに違いありませんが、その後Babelやらgulpやらのきちんと構文解析したうえで縮小してくれるMinifierが現れてきたので、現在ではもう役目を終えたと言っていいでしょう。
あとコミットメッセージはもうちょいどうにかしてほしい。