JavaScriptで「(a ==1 && a== 2 && a==3)」の結果を真にする手法が議論される 60
ストーリー by hylom
JavaScriptに不可能はない 部門より
JavaScriptに不可能はない 部門より
JavaScriptで「(a ==1 && a== 2 && a==3)」という式の結果を真にするにはどうすればいいのか、StackOverflowで議論されている。
「aは1でもあり2でもあり3でもある」という状況は一見矛盾しているが、たとえばaをオブジェクトとし、文字列として評価されるごとに異なる結果を返すようにすれば簡単に実現できる。また、ホワイトスペースではなく文字として認識されるハングルの半角スペースを使って同じように見えるが実際は異なる3つの変数を定義するもの、getterを利用するものなど、さまざまな方法が提案されている。
リンク先を見るのが面倒な人へ (スコア:5, 参考になる)
だいたい以下のような方法があるようだ(自分がすぐ思いついたのは最初の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つずつ取り出されていく。
Re:リンク先を見るのが面倒な人へ (スコア:2)
aをどこのスコープに置くかもバリエーションがあったけど、
個人的に window.a を生やすのがツボった。
Re:リンク先を見るのが面倒な人へ (スコア:1)
これを含めてオブジェクトからの暗黙的な型変換利用してるのしかないよね
もっと変態的なのできないのだろうか
Re:リンク先を見るのが面倒な人へ (スコア:2)
変態的ではないけど、
aのように見えてaじゃない文字(а、a)を変数名に使ったフィッシング詐欺的なのはあった。
#どうせUnicode限定なんだろって?違います。なんとどちらもShift-JISに含まれているのです!(笑)
Re:リンク先を見るのが面倒な人へ (スコア:2)
・getterを定義する
・3つのaの前後に不可視(だけど識別子としては合法)な文字を付けて別の変数にする
この2つは、暗黙的な型変換ではないと思います。
// 別の変数にするパターンでは、 a(半角)とa(全角)とа(キリル文字)にするのもあがっていました。
svn-init() {
svnadmin create .svnrepo
svn checkout file://$PWD/.svnrepo .
}
Re: (スコア:0)
配列のjoinって返り値が文字列限定なら妥当な挙動だと思うけど、存在自体はホント無意味だと思う。joinの挙動を残したままtoStringをオーバーライドしたい時のため、なのかな。
== と 型変換の関係性 (スコア:1)
まず、`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は素晴らしい」と感じられるのかもしれません。
この辺がJavaScriptの嫌いなところ (スコア:0, すばらしい洞察)
なんでこんな気持ち悪い事ができてしまうのよw
Re:この辺がJavaScriptの嫌いなところ (スコア:1)
演算子のオーバーロードがある言語でもできてしまいますが
Re: (スコア:0)
演算子のオーバーロードの方は、まだ意識してそうならないようにみんな努力してくれるから。
JavaScriptは不意打ちでバグでるからな。
Re: (スコア:0)
意識とか努力とか。
2行目は指摘と関係ないし。
Re: (スコア:0)
とにかく嫌いなんだ、という以上のことが読み取れなかった。
JavaScript でも意識してそうならないように努力すれば良いのでは。
Re: (スコア:0)
不意打ちじゃなくておまえが知らないだけだろ
Re: (スコア:0)
結果1・2・3なら単に比較の回数返せば良いだけだよなあ。
わざわざやる奴はそうそう居ないだろうけど。
Re:この辺がJavaScriptの嫌いなところ (スコア:1)
C++/C# とかでも全く同じことできますよ。
Re: (スコア:0)
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;
}
Re: (スコア:0)
BYTE b = 1;
#define a (b++)
だめ?
Re: (スコア:0)
変数無しの
#define a 1 || 1
でOK
Re:この辺がJavaScriptの嫌いなところ (スコア:1)
#define a 0,3
でもOKですね
Re: (スコア:0)
#define == |
とか考えたけどさすがに無理だった
Re: (スコア:0)
C/C++で評価順序が規定されているところはわりと少ない。
Re: (スコア:0)
Re:この辺がJavaScriptの嫌いなところ (スコア:1)
プログラム言語慣れしてるから気にならないけど、
JavaScriptに限ったことじゃなく、
短絡評価を採用しているプログラム言語の論理演算は気持ち悪い。
とも言えると思う。
A and B
は、AとBを同時に評価して、両方がtrueならtrueである。
みたいな意味のはずだけど、
プログラム言語では、
Aを評価し終わってからBを評価するから、Aの評価中にBが変動しちゃう可能性もあるし、
AがfalseならBを評価すらしない。
論理演算としてみると、これは気持ち悪いぞ。
Re:この辺がJavaScriptの嫌いなところ (スコア:1)
短絡評価の無いプログラミング言語を使うと地獄だぜ。
具体的にはプログラミング入門演習でやらされたPascal。
Pascalでの書き方はもう忘れたからCライクに書くけど、
if(a != null && a[0] == 1){
puts("a starts with 1");
}
こういうので、aの値いかんに依らず、a[0] == 1が評価されて死ぬからな。
それまでちゃんと考えたことがなくて「短絡評価って高速化のためのおまけだよね」と漠然と思ってたからえらい目に会った。
恐ろしさを認識できて、問題ないように書くよう意識してからも、エラーが出るわ出るわ、どんだけ短絡評価前提で書いてたんだと、びっくりした。
&&とかandって表現に違和感が、というのは分かるけど、=で代入を表現する気味悪さと同じく、そこは諦めた方が良い。
Re:この辺がJavaScriptの嫌いなところ (スコア:2)
VBはショートサーキットをしなかった
不満が出たのかVB.NETではAndAlso/OrElseと言うショートサーキット演算子が導入されましたね、
Re: (スコア:0)
こういう偏見は一生治らんだろうな。
Re: (スコア:0)
この手のは、C++のtemplateでやり尽されていて、あまり好ましくないと結論出来ているかと。
Re:この辺がJavaScriptの嫌いなところ (スコア:2)
#<# とか !=! とかオーバーロード専用の演算子が欲しいなぁ
stream にも << じゃなくて <= とかで出すようにしたほうが…
Re:この辺がJavaScriptの嫌いなところ (スコア:1)
JavaScriptをはじめ、後追い言語でもジェネリックプログラミング [wikipedia.org]は大体できるようになってるので、その結論は間違ってるとしか言いようがないですね。
Rust [wikipedia.org]みたいな、2010年代の言語でもありますし。
https://doc.rust-lang.org/book/second-edition/ch10-01-syntax.html [rust-lang.org]
Re: (スコア:0)
>この手のは、C++のtemplateでやり尽されていて、あまり好ましくないと結論出来ているかと。
の、「あまり好ましくない」ってのは、
templateを使うと、一見かっこいい(その人の主観で)syntax sugarまがいを自作できるんだけど、好ましくないって主旨です。
>>JavaScriptをはじめ、後追い言語でもジェネリックプログラミング [wikipedia.org]は大体できるようになってるので、その結論は間違ってるとしか言いようがないですね。
だから、genericsそのものの有用性の話じゃないんですよね。人類が扱うにはtemplateが強力すぎたからgenericsに弱められたというか。
その辺の歴史を勉強してみて。1999~2004ぐらいの、c++0xのtemplate使ったスマートポインタどうするの議論のころだったと思う。
Re: (スコア:0)
C♯がわざわざテンプレート抜きで作ったのに、結局現場の要望に応えて入れざるを得なくなった、ってのが正確な歴史。こういう思想家はどこでも一定数いるけど、現実を知らない。
Re: (スコア:0)
C#のジェネリックスはJavaの失敗を踏まえて少しはマシな実装になってる
Re:この辺がJavaScriptの嫌いなところ (スコア:1)
何だって読み辛く書けば読み辛いコードになるってだけの話なのに、便利な道具を何でも敵視する人がいて困る。
ラムダ式禁止令の話とか聞くとゾッとする。
Re: (スコア:0, すばらしい洞察)
こういうのは便利のうちに入らないんだよ
Re: (スコア:0)
諸刃の剣とか利益相反と表現してはいかがでしょうか
Re: (スコア:0)
そういう気持ちの悪いJavaScriptが好きで好きでしょうがないというのならともかく、
こういう一般性に欠くパズルはあまり優れたものとは言い難いね
Re: (スコア:0)
近代的なプログラム言語なら、どれでも可能。むしろJavaScript よりも簡単に書けたりする。
こういうのが「気持ち悪い」と思うなら、他の言語より書き方が面倒なぶんだけ JavaScriptのほうが、まだマシなんじゃないの?
Re: (スコア:0)
toStringいじってたら比較演算に影響が出るというのは気持ち悪いんじゃないかなあと
Re: (スコア:0)
言語機能をどう使うかはその人(組織)次第
使う側のバグは言語ではどうにもできません。
ま、既存の用語や単語を独自の意味に変えて、さらに暗黙知化や常識として取り扱うとこですね。
とても好きです (スコア:0)
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
# 理に適いすぎていて惚れる
Re: (スコア:0)
モデレーション警察です
モデレーションはそういう用途で使うものではありません
https://srad.jp/faq/com-mod [srad.jp]
FAQすら読まない(ry
アルファでありオメガである (スコア:0)
(a ==1 || a== 2 || a==3)
こうする。
ダメか。
Re: (スコア:0)
???
JavaScript以外ではどうだろ? (スコア:0)
とか考え出すとゆの in languageにハマった時と同じような状況になる
怒られるだろ (スコア:0)
"===" 使えって怒られるですよ
JavaScript 忘れがちな === と == の違い [qiita.com]
とりあえず (スコア:0)
=をひとつにすれば簡単に実現できる(適当)
Re: (スコア:0)
フォントと印刷媒体によっては、==も===も長めの=になってしまうのが難点 :P
Re:で? (スコア:1)
元記事は「こんな質問が大手企業の面接でありましたが、あなたならどう考える?」って書かれてるから、
たまにGoogleやマイクロソフトの面接試験エピソードとかで聞こえてくるやつのような、
どう考えるか発想力を問う問題をあれこれ知恵を持ち寄ってるトピックなだけだと思うよ。
Re:で? (スコア:1)
その辺の反応で、アレゲ界に足を突っ込んでるかどうか判断する試金石になりそう。
Re: (スコア:0)
ioccc も盛り上らなくなってるようで、アレゲじゃない人の比率があがってきたんでしょうかね。