1. ホーム
  2. language-agnostic

[解決済み] 単項のブーリアン・トグル演算子を持つ言語はありますか?

2022-05-27 06:14:38

質問

これはより理論的な質問です。C++およびそれに直接基づいた言語 (Java、C#、PHP) には、以下のような特徴があります。 ショートカット演算子 のような、ほとんどの二項演算子の結果を最初のオペランドに代入するためのがあります。

a += 3;   // for a = a + 3
a *= 3;   // for a = a * 3;
a <<= 3;  // for a = a << 3;

のような書き方をしていますが、boolean 式をトグルさせたいときはいつも

a = !a;

というのは a のような長い表現になります。

this.dataSource.trackedObject.currentValue.booleanFlag =
    !this.dataSource.trackedObject.currentValue.booleanFlag;

(ええ、デメテルの法則ですね)。

そこで思ったのですが 単項のブール型トグル演算子を持つ言語はあるのだろうか? を省略することができるような a = !a の式を繰り返さずに a の式を繰り返すことなく、例えば

!=a;  
// or
a!!;

この言語が適切なブーリアン型(例えば bool のように)、そして a がその型であること(したがって、C スタイルの int a = TRUE ).

もし文書化されたソースを見つけることができれば、例えば C++ の設計者がそのような演算子を bool が組み込み型になったとき、そのような演算子を追加することを検討したかどうか、そしてもしそうなら、なぜそれを断念したのかを知りたいと思います。


(注意: 割り当ての際に = を使うべきでないという意見もあることは承知しています。 ++ であり += は有用な演算子ではなく、設計上の欠陥です。私がそれらに満足していると仮定して、それらがブールに拡張されない理由に焦点を当てましょう)。

どのように解決するのですか?

この質問は、純粋に理論的な見地からすると実に興味深いものです。を使用するかどうかはさておき 単項演算子、突然変異を起こすブーリアン・トグル演算子 が有用であるかどうか、または多くの言語がそれを提供しないことを選択した理由はさておき、私はそれが本当に存在するかどうかを確認するための探求を敢行しました。

TL;DR 明らかに違いますが、Swiftでは1つ実装することができます。それがどのように行われるかを見たいだけなら、この回答の一番下までスクロールできます。


さまざまな言語の機能を(すばやく)検索した結果、どの言語もこの演算子を厳密な変異インプレース操作として実装していないと言って差し支えないでしょう(もし見つけたら、私を修正してください)。ですから、次にすることは、それを作ることができる言語があるかどうかを確認することです。これには2つのことが必要です。

  1. 関数で(単項)演算子を実装できること。
  2. 関数に参照渡しの引数を持たせることができる(引数を直接変更することができる)。

多くの言語は、これらの要件のどちらか、あるいは両方をサポートしていないため、すぐに除外されるでしょう。 Java は演算子のオーバーロード (またはカスタム演算子) を許可しておらず、さらに、すべてのプリミティブ型は値で渡されます。 Go は演算子のオーバーロードをサポートしていません(ただし ハック を除いて)演算子のオーバーロードを全くサポートしていません。 さび はカスタムタイプに対してのみ演算子のオーバーロードを許可しています。あなたは ほとんど でこれを実現できます。 Scala では、非常に創造的な名前の関数を使うことができ、括弧も省略できますが、悲しいことに参照渡しがありません。 フォートラン は、カスタム演算子を許可しているという点では非常に近いのですが、特に inout パラメータ(通常の関数やサブルーチンでは許可されている)を持つことを特に禁止しています。


しかし、少なくとも1つ、必要なボックスをすべて満たす言語があります。 Swift . 一部の人々は、近日公開予定の .toggle() メンバ関数をリンクしている人もいますが、独自の演算子を書くこともでき、それは実際に inout 引数をサポートします。驚いてください。

prefix operator ^

prefix func ^ (b: inout Bool) {
    b = !b
}

var foo = true
print(foo)
// true

^foo

print(foo)
// false