The fact that &
and |
operate on Bool
is actually an argument in favor of also allowing !
to operate (as a logical operator, not bitwise) on Integer
types (converting non-zero to false
, and zero to true
).
If Julia supported primitive types that were not a multiple of 8 bits (something like that which would be great for dealing with fields in C/C++/etc. structs), then Bool
could be implemented as primitive type Bool 1 end
instead of making it a UInt8
under the hood.
I disagree, I think that allowing non-booleans in contexts one expects booleans makes it easy for bugs to slip though. This was an unfortunate choice in C, but also in the Lisp family (anything not nil
is true), and many other languages that follow that pattern. Julia chose to have a Bool
type, instead of repurposing some other type or allowing anything to be interpreted as a boolean with a bit of imagination.
I also rather like the !!x == x
invariance, which !
operating on Int
s in the manner you suggest would break.
Where is that an invariance? Iāve never seen that described as a property of !
in any language before.
Using !!var
is an old C idiom, to convert an integer in var to 0 or 1, instead of (var != 0)
, 2 characters vs. 7.
In Julia (at least that is my impression), now for ~
and !
separately (unless I missed some case), but after the merge for !
. I find this rather neat.
And a quite horrible one IMO. One of those 1000+ C idioms where a string of characters does what you want, but for some reason people refrain from naming it for that purpose. If you know the idiom, you can reverse engineer intent, otherwise not. Truly an idiom in the sense of
an expression whose meanings cannot be inferred from the meanings of the words that make it up
Some people consider such idioms bad style.
Excuse me to put it this way but I disagree on your disagreement.
Itās not an idiom in that sense at all. Any C/C++/ā¦ programmer knows that ! will convert 0/non-zero to 1/0 (true/false), and that doing that twice would give you 0/1.
Changing this in Julia I think is the sort of thing that can lead to bugs, when pretty much every other common language (except Rust) has !
and ~
with separate meanings for logical and bitwise.
This is the same as the problem of false cognates when learning a foreign language, for example when somebody tries to say āembarrassedā in Spanish, and comes up with āpregnantā (embarazada).
If people are so dead set on the desire to free up ~
, then at least donāt conflate bitwise and logical for !
, and change ~
to Ā¬
instead (and possibly free up &
and |
, and move those to ā§
and āØ
, so the bitwise operators are consistently Unicode operators in Julia.).
At least then, people reading bit-twiddling code in Julia would probably recognize the meanings of those Unicode operators, or at least know to look them up, instead of seeing !
and believing it is doing something that it does not.
Right, only math guys ever multiply numbers by 2. Most programmers would never do anything like that, ever.
I think most programmers donāt mind the extra character - and would rather not worry about all the strange cases that using juxtaposition as syntax causes.
TBH, for mathematicians in Julia, the justification though doesnāt seem to be saving one character, but rather, make stuff look like math.
I should be clear, Iām not trying to say thatās necessarily a bad thing, itās just something that needs to be thought about a lot in advance, all the pros and cons of something like using juxtaposition, or changing an operator that has pretty much the same meaning on all major languages, just to free up one, for ?.
Julians are lucky in that they can use any number of Unicode operators for anything new, without making code confusable by being almost, but not quite, the same as most of the other languages.
I love the juxtaposition syntax, even though itās to a large degree about aesthetics. Itās not just one character, though. Itās all those cases where I can change
a/(2 * n)
into
a/2n
Yes, like I said, I wasnāt trying to say itās a bad thing, and probably the right choice for a language with a focus on being able to do math well, but for people that donāt have a lot of *
s in their code anyway (I have almost none), having the code look like math or saving a few characters in that case is not a big deal, while some of the weird edge cases in the syntax cause more problems.
For bit twiddlers used to C, being able to test for 0 vs. non-zero with a simple !
feels the same, the code feels rather clumsy and inelegant without it.
(Nicely enough with Julia , as I said before, a one-line bit of piracy means my code still looks nice and succinct to me, by making !
work on Integer
, where otherwise it would just have been a MethodError
)
A good way to do this is to define
!x = Base.:!(x)
!(x::Integer) = (x == 0)
in your code. Then thereās not even any piracy.
I guess Iām missing something, how is that definition different from:
(waiting to learn from the Jedi (oops) Julia Master!)
Edit: maybe I get it now, itās overwriting !
in my package, not extending it, right?
Yes, itās creating a new !
inside your module that defaults to Base.!
behavior for everything but Integer
s. This way everybody else who uses !
will continue to get the standard behavior (unless they import !
from your module).
The one difficulty is Iād like to make that definition easily available by just using a module, and I donāt see how to do that without extending Base.:!
You would have to say using Foo: !
.
I thought that would give a conflict (you know, use must use Base.xxx and Foo.xxx)
Folks - let me know what you feel about my proposal, consolidated from otherās ideas here and on GitHub, and join in the Tomatina (a festival in Spain of throwing tomatos) .
!(val::Integer) = (val == 0)
Please donāt do this. I love that values non-booleans donāt have magic comparison properties like in Python, itās just too many special cases to remember. Also it would be weird if if !a end
worked for a variable where if a end
errors.
If !
is used for both logical and bitwise not, couldnāt foo &= ~0x00ff
become foo &= !0x00ff
which is equally concise?
Special cases? I actually think of it as being a very generic rule, no special cases at all. !
returns a boolean based on the type of the value. That seems very Julian to me. Just like the relational operators can be used with many different types of values, but they always return a boolean value.
Just as if iszero(a) ...
works, even if if a
doesnāt, so should if !a
work.
The problem there is that anybody used to most of the languages in the world expect that !
returns a boolean value, and never anything else (just the Rust people donāt, that Iām aware of so far)
I think that foo ā§= Ā¬0x00ff
would be more likely to be understood, people arenāt used to using those Unicode operators, but they may very well know that they are boolean operations. foo and= not(0x00ff)
is also less likely to confuse people coming from the many C-like languages.
(there are many languages that in other aspects are not at all like C, but that follow Cās conventions for logical and bitwise operators, like PHP, Perl, Ruby, or some or most of them, like Python or Rust).