パスワードを忘れた? アカウント作成
13505891 story
プログラミング

JavaScriptで「(a ==1 && a== 2 && a==3)」の結果を真にする手法が議論される 60

ストーリー by hylom
JavaScriptに不可能はない 部門より

JavaScriptで「(a ==1 && a== 2 && a==3)」という式の結果を真にするにはどうすればいいのか、StackOverflowで議論されている。

「aは1でもあり2でもあり3でもある」という状況は一見矛盾しているが、たとえばaをオブジェクトとし、文字列として評価されるごとに異なる結果を返すようにすれば簡単に実現できる。また、ホワイトスペースではなく文字として認識されるハングルの半角スペースを使って同じように見えるが実際は異なる3つの変数を定義するもの、getterを利用するものなど、さまざまな方法が提案されている。

  • by Anonymous Coward on 2018年01月18日 19時34分 (#3347124)

    だいたい以下のような方法があるようだ(自分がすぐ思いついたのは最初の2つだけだった)
    ・toStringをオーバーライドする
    ・getterを定義する
    ・3つのaの前後に不可視(だけど識別子としては合法)な文字を付けて別の変数にする
    ・valueOfをオーバーライドする
    ・[Symbol.toPrimitive]をオーバーライドする

    ちゃんと考えてないけどProxyでもできそう

    一番すごいと思ったのはこれ
    var a = [1,2,3];
    a.join = a.shift;
    解説すると、
    1. aを数値と比較するために==演算子の作用によってtoStringが呼ばれる。
    2. 配列のtoStringは、デフォルトで配列の文字列表現を得るためにjoinを呼ぶ。
    3. joinがshiftでオーバーライドされているので、先頭から要素が1つずつ取り出されていく。

    ここに返信
  • by think49 (38497) on 2018年01月21日 1時09分 (#3348290)

    JavaScriptで「(a ==1 && a== 2 && a==3)」という式の結果を真にするにはどうすればいいのか、StackOverflow [stackoverflow.com]で議論されている。

    まず、`Object.prototpe.valueOf` を使う方法を考えました。


    var a = {valueOf: (value => (() => value++))(1)};
    console.log(a == 1 && a == 2 && a == 3); // true

    このコードが気持ち悪いと思う原因は、`==` にあると考えます。
    `==` は両辺の型が不一致の場合に可能な限り型を合わせようとする為、Object型をPremitive型に変換し、valueOf() による型変換を許してしまいます。
    上記コードは下記の疑似コードとほぼ同じ動作になっています。


    var a = {valueOf: (value => (() => value++))(1)};
    console.log(Number(a) === 1 && Number(a) === 2 && Number(a) === 3); // true

    ですので、両辺の型の不一致を `false` と評価する `===` に変更する事で、このテクニックは使えなくなります。


    var a = {valueOf: (value => (() => value++))(1)};
    console.log(a === 1 && a === 2 && a === 3); // false

    「こんなJavaScriptは気持ち悪い」と評価されるきらいがありますが、本来、この機能は Primitive 型の機能を持ったオブジェクトをユーザが自由に生成できる意図があるように思います。
    Number 型は `Number.prototype` にあるメソッドをプロトタイプチェーンの原則によって使えますが、Number 型の機能を拡張したい場合に `Number.prototype` を拡張するのは影響範囲が大きすぎる為、一般には使われません。
    そこで、`CustomNumber.prototype` を拡張して、ユーザ定義の Number 型であるかのようなオブジェクトを生成したいとします。
    valueOf, toString メソッドを使う事で、ある程度はそのようなオブジェクトを生成する事が出来ます。
    JavaScriptの一部の演算子は Primitive 型に変換する事で役割を果たす為、Primitive 値をコントロールできるといろいろと都合が良いのです。
    そのような「特別なオブジェクト」を生成したい、と考えたときに「JavaScriptは素晴らしい」と感じられるのかもしれません。

    ここに返信
  • by Anonymous Coward on 2018年01月18日 16時50分 (#3347051)

    なんでこんな気持ち悪い事ができてしまうのよw

    ここに返信
    • by Anonymous Coward on 2018年01月18日 17時02分 (#3347053)

      演算子のオーバーロードがある言語でもできてしまいますが

      • by Anonymous Coward

        演算子のオーバーロードの方は、まだ意識してそうならないようにみんな努力してくれるから。
        JavaScriptは不意打ちでバグでるからな。

        • by Anonymous Coward

          意識とか努力とか。
          2行目は指摘と関係ないし。

        • by Anonymous Coward

          とにかく嫌いなんだ、という以上のことが読み取れなかった。
          JavaScript でも意識してそうならないように努力すれば良いのでは。

        • by Anonymous Coward

          不意打ちじゃなくておまえが知らないだけだろ

      • by Anonymous Coward

        結果1・2・3なら単に比較の回数返せば良いだけだよなあ。
        わざわざやる奴はそうそう居ないだろうけど。

    • by Anonymous Coward on 2018年01月18日 17時04分 (#3347055)

      C++/C# とかでも全く同じことできますよ。

      • by Anonymous Coward

        C# でも2種類書いてみた。

        class changeValue
        {
                int i = 1;
                public static implicit operator int(changeValue v)
                {
                        return v.i++;
                }
        }

        class allEqual
        {
                public static bool operator ==(allEqual v1, int v2)
                {
                        return true;
                }

      • by Anonymous Coward

        BYTE b = 1;
        #define a (b++)

        だめ?

    • プログラム言語慣れしてるから気にならないけど、
      JavaScriptに限ったことじゃなく、
      短絡評価を採用しているプログラム言語の論理演算は気持ち悪い。
      とも言えると思う。

      A and B
      は、AとBを同時に評価して、両方がtrueならtrueである。
      みたいな意味のはずだけど、

      プログラム言語では、
      Aを評価し終わってからBを評価するから、Aの評価中にBが変動しちゃう可能性もあるし、
      AがfalseならBを評価すらしない。

      論理演算としてみると、これは気持ち悪いぞ。

      • by Anonymous Coward on 2018年01月19日 11時56分 (#3347458)

        短絡評価の無いプログラミング言語を使うと地獄だぜ。
        具体的にはプログラミング入門演習でやらされたPascal。

        Pascalでの書き方はもう忘れたからCライクに書くけど、

        if(a != null && a[0] == 1){
                puts("a starts with 1");
        }

        こういうので、aの値いかんに依らず、a[0] == 1が評価されて死ぬからな。

        それまでちゃんと考えたことがなくて「短絡評価って高速化のためのおまけだよね」と漠然と思ってたからえらい目に会った。
        恐ろしさを認識できて、問題ないように書くよう意識してからも、エラーが出るわ出るわ、どんだけ短絡評価前提で書いてたんだと、びっくりした。

        &&とかandって表現に違和感が、というのは分かるけど、=で代入を表現する気味悪さと同じく、そこは諦めた方が良い。

    • by Anonymous Coward

      こういう偏見は一生治らんだろうな。

      • by Anonymous Coward

        この手のは、C++のtemplateでやり尽されていて、あまり好ましくないと結論出来ているかと。

        • #<# とか !=! とかオーバーロード専用の演算子が欲しいなぁ
          stream にも << じゃなくて <= とかで出すようにしたほうが…

        • by Anonymous Coward on 2018年01月18日 22時43分 (#3347227)

          JavaScriptをはじめ、後追い言語でもジェネリックプログラミング [wikipedia.org]は大体できるようになってるので、その結論は間違ってるとしか言いようがないですね。

          Rust [wikipedia.org]みたいな、2010年代の言語でもありますし。
          https://doc.rust-lang.org/book/second-edition/ch10-01-syntax.html [rust-lang.org]

          • by Anonymous Coward

            >この手のは、C++のtemplateでやり尽されていて、あまり好ましくないと結論出来ているかと。
            の、「あまり好ましくない」ってのは、
            templateを使うと、一見かっこいい(その人の主観で)syntax sugarまがいを自作できるんだけど、好ましくないって主旨です。

            >>JavaScriptをはじめ、後追い言語でもジェネリックプログラミング [wikipedia.org]は大体できるようになってるので、その結論は間違ってるとしか言いようがないですね。

            だから、genericsそのものの有用性の話じゃないんですよね。人類が扱うにはtemplateが強力すぎたからgenericsに弱められたというか。
            その辺の歴史を勉強してみて。1999~2004ぐらいの、c++0xのtemplate使ったスマートポインタどうするの議論のころだったと思う。

            • by Anonymous Coward

              C♯がわざわざテンプレート抜きで作ったのに、結局現場の要望に応えて入れざるを得なくなった、ってのが正確な歴史。こういう思想家はどこでも一定数いるけど、現実を知らない。

              • by Anonymous Coward
                それはJavaの話
                C#のジェネリックスはJavaの失敗を踏まえて少しはマシな実装になってる
        • by Anonymous Coward on 2018年01月19日 2時32分 (#3347280)

          何だって読み辛く書けば読み辛いコードになるってだけの話なのに、便利な道具を何でも敵視する人がいて困る。
          ラムダ式禁止令の話とか聞くとゾッとする。

          • Re: (スコア:0, すばらしい洞察)

            by Anonymous Coward

            こういうのは便利のうちに入らないんだよ

            • by Anonymous Coward

              諸刃の剣とか利益相反と表現してはいかがでしょうか

    • by Anonymous Coward

      そういう気持ちの悪いJavaScriptが好きで好きでしょうがないというのならともかく、
      こういう一般性に欠くパズルはあまり優れたものとは言い難いね

      • by Anonymous Coward

        近代的なプログラム言語なら、どれでも可能。むしろJavaScript よりも簡単に書けたりする。
        こういうのが「気持ち悪い」と思うなら、他の言語より書き方が面倒なぶんだけ JavaScriptのほうが、まだマシなんじゃないの?

        • by Anonymous Coward

          toStringいじってたら比較演算に影響が出るというのは気持ち悪いんじゃないかなあと

    • by Anonymous Coward

      言語機能をどう使うかはその人(組織)次第
      使う側のバグは言語ではどうにもできません。

      ま、既存の用語や単語を独自の意味に変えて、さらに暗黙知化や常識として取り扱うとこですね。

    • by Anonymous Coward
      任せろ、Rubyならもっと簡単にカオスに突入できるぞ!

      a = Object.new
      b = a
      c = b.dup

      def a.==(x) true end

      p a == 1 && a == 2 && a == 3 # => true
      p b == 1 && b == 2 && b == 3 # => true
      p c == 1 && c == 2 && c == 3 # => false

      # 理に適いすぎていて惚れる
  • by Anonymous Coward on 2018年01月18日 18時24分 (#3347087)

    (a ==1 || a== 2 || a==3)
    こうする。
    ダメか。

    ここに返信
  • by Anonymous Coward on 2018年01月18日 19時22分 (#3347119)

    とか考え出すとゆの in languageにハマった時と同じような状況になる

    ここに返信
  • by Anonymous Coward on 2018年01月18日 20時47分 (#3347176)

    "===" 使えって怒られるですよ
    JavaScript 忘れがちな === と == の違い [qiita.com]

    ここに返信
  • by Anonymous Coward on 2018年01月19日 9時27分 (#3347350)

    =をひとつにすれば簡単に実現できる(適当)

    ここに返信
    • by Anonymous Coward

      フォントと印刷媒体によっては、==も===も長めの=になってしまうのが難点 :P

typodupeerror

アレゲはアレゲ以上のなにものでもなさげ -- アレゲ研究家

読み込み中...