3 posts were split to a new topic: Argument techniques for bit-twiddling
@garrison made this comment on GitHub:
I think many people against this change will agree even with this statement. As I understand, the question is whether !x for non-Boolean x should be unimplemented and thus error (friendliest to developers coming from other languages; prevents âunexpectedâ behavior), or instead perform a bitwise not (saves a symbol for use elsewhere; provides âconsistencyâ).
If !x for non-Boolean is left unimplemented in Base, then it can be extended as desired by people like me who want to use it as a generic operator, as Jeff showed, without affecting anybody elseâs code.
If it is made to perform a bitwise not, while it saves a symbol, that can be done in other ways (again, see my proposal A Modest Proposal (for !, &, | and ~)), also, it is more likely to cause confusion, as it violates the convention in most languages that !
always returns a boolean value (no matter what it is applied to), and finally, I feel it doesnât really provide consistency with other boolean operators (such as the relational operators, which also take arbitrary input, and always produce a boolean output).
I think that knowing that if !a
is always valid is way more consistent than having it work or fail depending on whether a
is a boolean value or something that can be bitwise complimented.
I actually consider this to be the strongest argument, in practice, for going through with this change. While it seems like it easily could have been controversial, Iâve yet to find a single blog post deriding the Rust developers for this choice (or even a single complaint, anywhere). Of course, Julia is meant to be more approachable than Rust, but many Rust developers will be coming from C where !x means iszero(x), so if it has not been confusing there, perhaps it will not be here either.
I also googled the issue and asked on some Rust discussion boards, and did find a number of comments wanting to know what the Rust bitwise complement operator is, people seeing that everything else matched C,
they expected ~
to work.
Some of us feel itâs silly to use up two ASCII operators for almost the same meaning. The only real difference between them is that ! throws an error for non-Bools.
But the decision on this is still somewhat up in the air, since also for many of us, years of C programming make it hard to read !x as bitwise not.
I feel itâs worth pointing out for the discussion that C has different operators for these because it couldnât dispatch on type. So, unlike Julia, its logical operators arenât simply just a subset of the behaviors of the bitwise operators, but actually distinct operations (the logical operators include an implicit call to the bool operator). Itâs by no means decided that we should change this, since itâs mentally quite surprising to those of us used to C. So itâs also a worthwhile datapoint that there is precedent from the rust developers having chosen to do the same (and it doesnât sound like the experienced developers regret it â beyond the additional entry in the ânotable differencesâ that new users need to memorize if coming from C).
On GitHub, youâd commented:
Just fwiw, this isnât what it means in C++, and various style guides may mention not to write out x when used as in an inferred boolean expression as x != 0 to avoid surprises in template code. See also âThe Safe Bool Idiomâ, since after the number of ways you could overload or implement the conversions that could be applied to this expression, itâs pretty hard to know what if (x) means without checking the documentation for the type of x.
Hmmm, Iâve been using C++ since it first came out in 1986 for the PC (Zortech C++), and thatâs not my understanding at all.
What it means, according to the C++ standard, is that !x
is the negation of the result of applying the bool
operator to x
.
If the operand is not bool, it is converted to bool using contextual conversion to bool: it is only well-formed if the declaration bool t(arg) is well-formed, for some invented temporary t.
The result is a bool prvalue.
For the built-in logical NOT operator, the result is true if the operand is false. Otherwise, the result is false.
Note the following also:
All built-in operators return bool, and most user-defined overloads also return bool so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including void).
Also, both bool
and !
can be overloaded in C++, and are done so in the standard library:
Here is just one example: http://en.cppreference.com/w/cpp/io/basic_ios/operator!
The normal behavior for bool
applied to an integer is just as Iâd stated, it is the same as != 0
,
and there are many many ways that bool
is overloaded (note that itâs not necessary to overload !
in most cases, because simply by overloading bool
, !val
will behave as expected for whatever the type of val is.
I was thinking about technical problems of proposal and till now found only two:
- backward incompatibility with (quite natural?)
!(x) = iszero(x)
in some packages
This is not technical but (more) âpoliticalâ problem. I am talking about discomfort to change these packages. My personal feeling is that it is not big problem but I could be wrong. Till now I see only Scott who is probably using it and maybe somebody (me?) could help him with transition. (although it could be problem if he has close sourced packages!)
bitstring(!0x00) != bitstring(~0x00)
This is technical change where we probably have to think more if it could spoil something or not.
I suspect that we need new definition for bitstring(x::Bool)
too!
It puzzles me to see a late-game change like this. The argument for having !/&&/||
over not/and/or
was that it was compatible with âCâ standard. I would also note that !
is semantically overloaded in Julia to mark mutable functions. Too many symbols in an expression create significant barriers to recognition. As someone coming from Python world, I really miss the readability of not
, and
and or
.
Further overloading of !
may have an impact on readability and maintainability. For example, there are many legacy applications that use 1
and 0
for boolean values. Currently, if you accidentally use !
on them you get a clear error (in Python itâd do the âright thingâ, IMHO). Either approach is fine. However, I think the proposed approach of having !1
silently become -2
may lead to some hair pulling for novice users. I didnât even know that the bitwise &
and |
operators were overloaded with eager boolean logic semantics; that said, it didnât matter since I used only &&
and ||
.
While itâs perhaps dead-on-arrival, Iâd once again ask if and
, or
, and not
could be added so that higher-level business logic programmers doing data analysis could avoid symbolic soup. Thanks.
That would be part of my proposal (A Modest Proposal (for !, &, | and ~)), which is based on the proposal by @sacha (explore fixing #5187 via and/or/xor/not and associated updating ops by Sacha0 ¡ Pull Request #25180 ¡ JuliaLang/julia ¡ GitHub). Note that when applied to boolean values, and
and or
would act as non-shortcircuiting logical operations (as do &
and |
currently), and not(someboolean)
would act the same as !someboolean
.
I also really like that. That is something that I would love to see in Julia.
If you like it, then go express your support for at-sachaâs PR 25180 on GitHub, and/or my proposal to take that PR and also add Unicode operators (suggested by Simon Byrne I believe for not
being ÂŹ
).
(just forget my other ideas for now about using !
generically and &
when it is free)
Novice users likely donât encounter such code. And if they would, the current ~1 == -2
isnât much better. I rather see a hiccup for experienced users, as !1 == -2
goes against all tradition.
This has been discussed here (5238, here (19788) and here (25180) at least. (19788 lists language comparisons for logical operators based on Rosetta). â Those (partly longstanding) issues didnât lead to action.
And imho the choice is arbitrary. From the comparison it seems, the more obscure a language, the more likely is usage of 'and-or-not'
and from the discussion it seems, the more core/senior the (Julia) developer the less enchanted by this proposition.
Your âhigher-level business logic programmersâ remark gave me the thought, that maybe it is even important to prefer '&&'
, '||'
and '!'
to signal that Julia is not some slow wishy-washy hip language but fast, respectable and suited for many tasks besides doing data analysis. â More honestly I think, go, rust, swift, R, Matlab, javascript and of course C have choosen and there is no reason to deviate. (And certainly not in the last minute). I did like the 'and-or-not'
style from Pascal, but when having to write '&&'
etc. in R, it really was not important.