Jest to więc bardziej teoretyczne pytanie. C ++ i języki (in) bezpośrednio na nim oparte (Java, C #, PHP) mają operatory skrótów do przypisywania wyniku większości operatorów binarnych do pierwszego operandu, takie jak
a += 3; // for a = a + 3
a *= 3; // for a = a * 3;
a <<= 3; // for a = a << 3;
ale kiedy chcę zmienić wyrażenie boolowskie, zawsze piszę coś takiego
a = !a;
co staje się irytujące, gdy a
jest to długie wyrażenie.
this.dataSource.trackedObject.currentValue.booleanFlag =
!this.dataSource.trackedObject.currentValue.booleanFlag;
(tak, prawo Demeter, wiem).
Zastanawiałem się więc, czy istnieje język z jednoargumentowym operatorem przełączania typu boolean , który pozwoliłby mi skrócić a = !a
bez powtarzania wyrażenia a
, na przykład
!=a;
// or
a!!;
Załóżmy, że nasz język ma odpowiedni typ boolowski (jak bool
w C ++) i to a
jest tego typu (więc nie ma stylu C int a = TRUE
).
Jeśli możesz znaleźć udokumentowane źródło, chciałbym się również dowiedzieć, czy np. Projektanci C ++ rozważali dodanie takiego operatora, kiedy bool
stał się typem wbudowanym, a jeśli tak, to dlaczego zdecydowali się na nie.
(Uwaga: Wiem, że niektórzy ludzie są zdania, że zadanie nie należy używać
=
i że ++
i +=
nie są użyteczne, ale operatorzy wady projektowe; niech tylko zakładać, że jestem zadowolony z nich i skupić się dlaczego oni nie rozciąga się bools).
źródło
void Flip(bool& Flag) { Flag=!Flag; }
Skraca twoje długie wyrażenie.this.dataSource.trackedObject.currentValue.booleanFlag ^= 1;
*= -1
jednak, co z jakiegoś powodu wydaje mi się bardziej intuicyjne niż^= true
.Odpowiedzi:
To pytanie jest rzeczywiście interesujące z czysto teoretycznego punktu widzenia. Pomijając, czy jednoargumentowy, mutujący operator przełączający byłby przydatny, czy też dlaczego wiele języków zdecydowało się go nie udostępniać, zaryzykowałem poszukiwanie, czy rzeczywiście istnieje.
TL; DR najwyraźniej nie, ale Swift pozwala na wdrożenie jednego. Jeśli chcesz tylko zobaczyć, jak to się robi, możesz przewinąć do końca tej odpowiedzi.
Po (szybkim) wyszukiwaniu funkcji w różnych językach mogę śmiało powiedzieć, że żaden język nie zaimplementował tego operatora jako ścisłej operacji mutacji w miejscu (popraw mnie, jeśli go znajdziesz). Więc następną rzeczą byłoby sprawdzenie, czy istnieją języki, w których można go zbudować. Wymagałoby to dwóch rzeczy:
Wiele języków zostanie natychmiast wykluczonych ze względu na brak obsługi jednego lub obu tych wymagań. Java dla one nie zezwala na przeciążanie operatorów (lub operatorów niestandardowych), a ponadto wszystkie typy pierwotne są przekazywane przez wartość. Go w ogóle nie obsługuje przeciążania operatorów (z wyjątkiem hacków ). Rust zezwala na przeciążanie operatorów tylko dla typów niestandardowych. Możesz to prawie osiągnąć w Scali , która pozwala ci używać bardzo twórczo nazwanych funkcji, a także pomijać nawiasy, ale niestety nie ma żadnego odniesienia do przekazywania. języka Fortran jest bardzo blisko, ponieważ pozwala na niestandardowych operatorów, ale wyraźnie zabrania im inout parametry (które są dozwolone w normalnych funkcjach i podprogramach).
Jest jednak co najmniej jeden język, który spełnia wszystkie niezbędne warunki: Swift . Chociaż niektórzy ludzie utworzyli linki do nadchodzącej funkcji składowej .toggle () , możesz także napisać własny operator, który rzeczywiście obsługuje argumenty inout . Oto i oto:
źródło
Przełączanie bitu boolowskiego
To podejście nie jest tak naprawdę czystym operatorem „mutującego odwrócenia”, ale spełnia powyższe kryteria; prawa strona wyrażenia nie obejmuje samej zmiennej.
Każdy język z logicznym przypisaniem XOR (np.
^=
) Pozwoliłby na odwrócenie bieżącej wartości zmiennej, powiedzmya
, za pomocą przypisania XOR dotrue
:Jak zauważył @cmaster w komentarzach poniżej, powyższe zakłada, że
a
jest to typbool
, a nie np. Liczba całkowita lub wskaźnik. Jeślia
w rzeczywistości jest czymś innym (np.bool
Czymś nieoceniającym do „prawdziwej” lub „fałszywej” wartości, z reprezentacją bitową, która nie jest0b1
lub0b0
, odpowiednio), powyższe nie obowiązuje.Na przykład Java jest językiem, w którym jest dobrze zdefiniowany i nie podlega żadnym cichym konwersjom. Cytując komentarz @ Boann z dołu:
Szybki:
toggle()
W wersji Swift 4.2 przyjęto i wdrożono następującą propozycję ewolucji:
To dodaje natywną
toggle()
funkcję doBool
typu w Swift.Nie jest to operator sam w sobie, ale pozwala na natywne podejście języka do przełączania wartości logicznych.
źródło
W C ++ można popełnić kardynalny grzech przedefiniowania znaczenia operatorów. Mając to na uwadze i trochę ADL, wszystko, co musimy zrobić, aby uwolnić chaos w naszej bazie użytkowników, to:
oczekiwany wynik:
źródło
operator<<
zaczęło oznaczać „przesyłane strumieniowo” z powodu pierwotnego nadużycia w STL. Nie będzie to naturalnie oznaczać „zastosuj funkcję transformacji na RHS”, co zasadniczo jest tym, do czego ponownie ją tutaj zamierzyłem.<<
jest to operator przesunięcia bitowego, a nie operator „wypływu”. Problem z twoją redefinicją nie polega na tym, że jest ona niespójna z istniejącymi znaczeniami operatora, ale raczej na tym, że nie dodaje ona żadnej wartości do prostego wywołania funkcji.<<
wydaje się być dużym przeciążeniem. Zrobiłbym!invert= x;
;)Jeśli włączymy język asemblera ...
NAPRZÓD
INVERT
do bitowego uzupełnienia.0=
dla logicznego (prawda / fałsz) uzupełnienia.źródło
not
jest operatorem "przełączającym" :-)Zmniejszanie C99
bool
przyniesie pożądany efekt, podobnie jak zwiększenie lub zmniejszeniebit
typów obsługiwanych w niektórych dialektach z małymi mikrokontrolerami (które z tego, co zaobserwowałem, traktują bity jako pola bitowe o szerokości jednego bitu, więc wszystkie liczby parzyste są obcinane do 0 i wszystkie liczby nieparzyste do 1). Nie polecałbym szczególnie takiego użycia, po części dlatego, że nie jestem wielkim fanembool
semantyki typu [IMHO, typ powinien był określićże abool
do którego zapisana jest wartość inna niż 0 lub 1 może zachowywać się po przeczytaniu zawiera nieokreśloną (niekoniecznie spójną) wartość całkowitą; jeśli program próbuje zapisać wartość całkowitą, o której nie wiadomo, czy jest równa 0 lub 1, powinien!!
najpierw użyć na niej].źródło
bool
aż do C ++ 17 .język programowania
Zobacz https://www.tutorialspoint.com/assembly_programming/assembly_logical_instructions.htm
źródło
; here edx would be 0xFFFFFFFE because a bitwise NOT 0x00000001 = 0xFFFFFFFE
if(x)
konstrukcji , całkowicie rozsądne jest zezwolenie na 0 / -1 jako fałsz / prawda, jak przy porównaniach SIMD ( felixcloutier.com/x86/PCMPEQB:PCMPEQW:PCMPEQD.html ). Ale masz rację, że to się psuje, jeśli użyjesz go do jakiejkolwiek innej wartości.Zakładam, że nie będziesz wybierać języka opartego wyłącznie na tym :-) W każdym razie możesz to zrobić w C ++ za pomocą czegoś takiego:
Zobacz na przykład następujący kompletny program:
To daje, zgodnie z oczekiwaniami:
źródło
return b = !b
? Ktoś czytającyfoo = makenot(x) || y
lub po prostu prostyfoo = makenot(bar)
mógłby założyć, żemakenot
to czysta funkcja i założyć, że nie ma żadnego efektu ubocznego. Zagrzebanie efektu ubocznego w większym wyrażeniu jest prawdopodobnie złym stylem, a jedyną korzyścią wynikającą z braku pustego typu powrotu jest umożliwienie tego.template<typename T> T& invert(T& t) { t = !t; return t; }
, który szablon zostanie przekonwertowany na / z,bool
jeśli zostanie użyty nabool
obiekcie niebędącym obiektem. IDK, czy to dobrze, czy źle. Prawdopodobnie dobrze.PostScript , będący konkatenatywnym , zorientowanym na stos językiem, takim jak Forth, ma jednoargumentowy przełącznik, a nie . nie operator przełącza wartość na górze stosu. Na przykład,
Patrz Poradnik języka PostScript (pdf) , str. 458.
źródło
Visual Basic.Net obsługuje to poprzez metodę rozszerzenia.
Zdefiniuj metodę rozszerzenia w następujący sposób:
A potem nazwij to tak:
Twój oryginalny przykład wyglądałby mniej więcej tak:
źródło
Flip()
:=
iNot
. Warto się dowiedzieć, że w przypadku wywołaniaSomeInstance.SomeBoolean.Flip
działa, nawet jeśliSomeBoolean
jest właściwością, podczas gdy równoważny kod C # nie będzie się kompilował.W Rust możesz stworzyć własną cechę, aby rozszerzyć typy, które ją implementują
Not
:Możesz również użyć
^= true
zgodnie z sugestią, aw przypadku Rusta nie ma problemu, aby to zrobić, ponieważfalse
nie jest to „zamaskowana” liczba całkowita, jak w C lub C ++:źródło
W Pythonie
Python obsługuje taką funkcjonalność, jeśli zmienna ma typ bool (czyli True lub False) z
exclusive or (^=)
operatorem:źródło
W C # :
Operatorem boolowskim ^ jest XOR, a XOR z wartością true jest tym samym, co odwracanie.
źródło