« [読書]プログラマが知るべき97のこと その1 『19:誰にとっての「利便性」か』 | トップページ | NetBeans7上でJDK7を用いてEclipseと結果が異なっていたコンパイラの挙動を確認する »

2011/05/05

JavaScriptで文字列の等価性を==で評価できるのは文字列が基本型だからなのか

 

…というような疑問点が以下のエントリを読んで浮かびました。

 

表題のことを考えるついでに、私も普通の業務系(Java)プログラマが知っておくべきことを絡めてこのエントリを書いていきたいと思います。

 

まず、JavaプログラマがWebブラウザ上でリッチクライアントを実現する場合、JavaScriptを生で触る以外にも選択肢があります。GWT(Google Web Toolkit)は、JavaプログラムをJavaScriptへ変換してくれるツールキットです。これを用いることで

  • JUnitなど、今までJava開発で用いてきたライブラリや、それらのライブラリを使用してきた経験を生かすことができます
  • (プログラマが記述するのはJavaコードなので)JavaScriptにはない、タイプセーフな環境の上で開発が行えます

GWTの登場でJavaプログラマがJavaScriptを利用したアプリケーションを作り上げることはより容易になりましたが、実際にJavaScriptを導入する、すなわちWebブラウザをクライアントとしてシステムを構築する場合にはプログラミングスキルだけではなく、その他色々な検討が必要になると思います。

  • (普段Webを利用しているとあまり気づかなかったり問題の無いレベルのように感じるかもしれませんが)業務アプリは普段目にしているようなWebアプリより局所的には高い性能が求められることがあります。例えば一画面中に表示する必要がある情報量など。何となくWebアプリはJavaアプリより軽量だと感じているかもしれませんが、それはあなたの利用しているWebサービスがそういうふうに工夫しているからであって、単純にあなたが作成している業務アプリをWebアプリへ移植すると、ブラウザのメモリ使用量が大変なことになるでしょう。そしてあなたのアプリに求められている要件に対しては工夫だけでは如何ともしがたい可能性があります。
  • Ext GWT(GXT; Ext JSのGWT移植版です)を利用することなどにより、リッチなGUIを実現できるようにはなりました。が、やはりネイティブアプリに比べると実現できることには限りがあります。そしてGUIを凝ったものにすればするほど重くなります。
  • JavaはJVM上で動作しますが、同様に、JavaScriptはWebブラウザ上で動作します。そしてWebブラウザの壁はJVMの壁より厚いです。OSネイティブな機能を用いれば実現できることがわかっていたとしても遠回りをしなければならなかったり、そもそも実現が不可能だったりします

もしかすると、再度Appletに目を向けてみる良い機会かもしれません。

 

本題に入ります。

表題にさらっと「==で等価性を評価」と記載していますが、ここですでに普通の業務系Javaプログラマが知っておくべき点が隠されています。

  • == は言語によって定義が異なります。特に、軽量プログラミング言語に分類される言語は、一般的にJavaの定義とは異なります。
    • Javaでは(==をオブジェクトに対して用いるとき)”同一性を評価するのに対し、他の言語では”等価性(論理的等価性、等値性とも)”を評価するのに用いられる場合があります。

同一性、等価性については普通の業務系Javaプログラマなら持っているであろう書籍Effective Java第2版の項目8「equalsをオーバーライドするときは一般契約に従う」、あるいはJavaDocのequalsメソッドの説明を読んでみると理解できると思いますが、要するに同一性の評価とは前述の通りJavaオブジェクトに対する==、等価性の評価とは(適切に実装された)equalsメソッドです。

冒頭で示したエントリでは、

Javaプログラマー的な発想では、strとstr2は別々の文字列オブジェクトを参照しているため、最後の行の==による比較がfalseとなるように勘違いしそうですが、JavaScriptでは基本型として値の比較となるためtrueとなります。

とあり、Javaは文字列がオブジェクトだから==では正しく評価できず、JavaScriptは基本型だから正しく評価できる、というように読めますが、可能性としてはこれ以外にも『==の定義がJavaとJavaScriptで異なる』ということが考えられます。事実、Javaと同じくJVM上で動作するGroovy言語において、文字列はオブジェクトであるにも関わらず、以下の評価はJavaScriptと同様trueとなります。

   1: str = "Hello";
   2: str2 = "Hello World".substring(0, 5);
   3:  
   4: println (str == str2); // true

これはGroovyが==を(Javaとは異なり)等価性の評価として使用しているからです。以下にGroovyサイトの”Japanese Differences from Java”良くある落とし穴、の節を引用します。

すべての型において==はequalsを意味します。Javaには、==が基本型については同値性を意味し、オブジェクトにとっては同一性を意味する、という構文上奇妙な部分があります。Groovyではautoboxingを導入しているため、このことはJava開発者の大混乱を招く恐れがあります (なにせxが5のとき、x == 5はほとんどfalseになるでしょうから:)。そこで、単純化のためにGroovyでは==はequals()を意味することになっています。もし本当に同一性が必要なときは、foo.is(bar) というように "is" メソッドを使うことができます。これはnullには使えませんが、その場合には==を使って foo==null とすることができます。

この引用の中で、”同値性”という言葉が出てきます。同値というのは、書籍JavaScript 第5版から引用すると「通常、バイト単位で比較して等しい」(p.42)という意味です。

等価性、同値性、同一性の関係をベン図示しておきます(クリックで拡大)。

equality

つまり、同一であれば同値であるし、同値であれば等価でもあります。ただし逆は成り立ちません。余談になりますが、文脈によっては「等価である」というのは、言外に「同値ではないけれども」と含んでいる場合もありますので注意が必要です(同値と同一の関係の場合も同様)。

 

それでは、JavaScriptではどのような定義になっているのでしょうか。ECMAScript(3rd Ed.)の仕様を日本語訳されている方がいらっしゃったのでそちらのサイトを引用させて頂きます。

文字列に対して==を使うと

11. Type(x) が String ならば、x と y の文字シーケンスが完全に同じ(同じ長さで対応する位置に同じ文字がある)なら true を返し、そうでなければ false を返す。

という定義で評価される、という仕様になっています。つまり、Stringは同値性によって評価されます。この定義を見ればわかる通り、文字列が基本型だから、ではなく、文字列に対して==が同値性評価として機能するから、というのが正しいでしょう。この説明に「等価性」という言葉をねじ込むと、『JavaScriptの==は(同一性ではなく)等価性を評価する演算子である。また、文字列に対して等価性は同値性を以て判断される』ということになるでしょうか。

結果だけを見ると、==を用いるとき、Javaの基本型では同値性評価、JavaScriptの文字列に対しても同値性評価、と同じように見えます。しかし、だからといって『JavaScriptの==はJavaと同じく基本型に対しては同値性の評価を行う』と覚えてしまうと、 true == 1 がtrueになるのかfalseになるのか、あるいはそれ以外なのか判断を誤ります。『同じ値ではないからfalseなのかな?JavaではコンパイルエラーになるけどJavaScriptはコンパイラ言語ではないから実行時エラー?』先に示したECMAScriptの仕様を読めば正解は一目瞭然です。

従って、

  • 同じ記号だからといって異なる言語間で意味が同じだと思い込んで使用するのは、特に==演算子においては危険
    • (そもそもVBのように==演算子が無い言語や、C++のように演算子をオーバロードできる言語もあります)

ということを念頭に置いておくべきでしょう。もちろん言語設計者は既存の言語を参考にしてはいるでしょうが、それは言語間に差異が無いということを意味しているわけではありません。==ではその差異が顕著に表れています。

あと、長々と記述してきましたが、書籍JavaScript: Good Partsでは、JavaScriptの悪いパーツの筆頭に==が挙げられており邪悪な演算子呼ばわりされてますので、定義を暗記するより先に

  • ==演算子は極力使わない

ということを覚えておくのが賢明かもしれません。

 

最後に。冒頭で示したエントリの、JavaScriptには整数と浮動小数の区別が無い、という例示コード、

   1: var intValue = 1;
   2: var doubleValue = 1.0;
   3: // (中略)
   4: // 整数と浮動小数は区別がない
   5: console.log(intValue == doubleValue); // true

これをJavaで同じように書くと

   1: int i = 1;
   2: double d = 1d;
   3: System.out.println(i == d);

となります。Javaには整数と浮動小数の区別があるわけですが、実行結果がどうなるか、そしてその理由は何なのかは普通の業務系Javaプログラマならわかりますよね?

 

[補足]

本文中の「基本型」という用語は参照元エントリに合わせて”primitive datatype”の意味で使用しています。これは、書籍JavaScript 第5版では「基本データ型」と訳されています。一方、本書では「基本型(primitive type)」という用語も登場しますが、基本データ型とは異なる概念です(「基本データ型」と対になるのは「オブジェクト(複合データ型)」、「基本型」と対になるのは「参照型」)。

…と思っていたのですが、参照元エントリをちゃんと読み返すと「基本型」を両方の意味で用いていますね…

« [読書]プログラマが知るべき97のこと その1 『19:誰にとっての「利便性」か』 | トップページ | NetBeans7上でJDK7を用いてEclipseと結果が異なっていたコンパイラの挙動を確認する »

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/18902/51586264

この記事へのトラックバック一覧です: JavaScriptで文字列の等価性を==で評価できるのは文字列が基本型だからなのか:

« [読書]プログラマが知るべき97のこと その1 『19:誰にとっての「利便性」か』 | トップページ | NetBeans7上でJDK7を用いてEclipseと結果が異なっていたコンパイラの挙動を確認する »

other sites

  • follow us in feedly
  • github
  • stackoverflow

ソフトウェアエンジニアとして影響を受けた書籍

  • Christain Bauer: HIBERNATE イン アクション

    Christain Bauer: HIBERNATE イン アクション
    理論と実践が双方とも素晴らしい製品であるHibernate。本書はそのプロダクトを書名に冠していますが、Hibernateを使うつもりがなく、ORマッピングの解説書として読むにしても十分な良書です。Second EditionとしてJava Persistence With Hibernateという書籍も出版されていますが、残念ながら現在のところ 和訳はされていません。-インアクションは2.xの、Java Persistence-は3.1の頃のものなので、最新版とはちょっと違うところもあることに注意。 (★★★★★)

  • アンドリュー・S・タネンバウム: 分散システム 原理とパラダイム 第2版

    アンドリュー・S・タネンバウム: 分散システム 原理とパラダイム 第2版
    クライアント/サーバシステムを構築する上で必要となる知識が総論されてます。Web技術者も、フレームワーク部分を開発するのであれば必読。 (★★★★★)

  • Joel Spolsky∥著: ジョエル・オン・ソフトウェア

    Joel Spolsky∥著: ジョエル・オン・ソフトウェア
    前述の書籍「ソフトウエア開発プロフェッショナル」をより砕いたもの、という感じでしょうか。 前書きではプログラマでなくSE向けの本のように書かれているが、プログラマが読んでも面白い本であると思われます。 SEになった新人(あるいはそういう会社に入る/入りたての人)にとっては、これからどういったことが仕事を遂行していく上で起こりえるのか、どのように考えて行なっていけばいいのか決定する助けになると思います。 元は″Joel on Software″というブログの記事で、web上でも一部日本語で読めます。 http://japanese.joelonsoftware.com/ (★★★)

  • ドナルド・C・ゴース,ジェラルド・M・ワインバーグ: ライト、ついてますか

    ドナルド・C・ゴース,ジェラルド・M・ワインバーグ: ライト、ついてますか
    問題解決(一昔前のの流行語で言うところの『ソリューション』)能力は、システムエンジニアのスキルとして備えるべきもののうちのひとつです。しかし、これは難しい。学校で出されるテストと違い、唯一の、(問題提出者が想定している)解を求めるだけが「問題解決」では無いからです。そもそも、何が問題なのか、それは本当に問題なのか、それは本当に解決すべき問題なのか、その問題解決方法は正しいのか、などを解決しなければ、「その解は正しいのか」に辿りつくことができません。この本の最も良いところのひとつは、本があまり厚くないこと。すぐに読めるし、何回も読み返す気になるでしょう。 (★★★★★)

  • スティーブ・マコネル: ソフトウエア開発プロフェッショナル

    スティーブ・マコネル: ソフトウエア開発プロフェッショナル
    コードコンプリートで有名なスティーブマコネルの著書。新人SEに読んで欲しい。個人として業界の中でどうあるべきか、組織としてどうあるべきか、SEのプロ意識とは?SEの心構え概論、といったところでしょうか。また、業界における資格の重要性についても説かれています。この業界では資格が特に軽んじられる傾向がありますが、この傾向はどんな弊害をもたらすのか、将来的にこの業界は資格に対してどのような姿勢で臨んでいくべきなのか。日経BP社では(他の出版社もだが)最近、似たような類いのあまり面白くない書籍が乱出版されていますが、この本は別格だと思うので安心して購入して欲しいと思います。 (★★★★★)

無料ブログはココログ