On the arbitrariness of truth(iness)

Think the first example was the one referenced, i.e.

julia> all([])
true
1 Like

If they were modular integers like Int64, they would wrap with addition, no?

julia> typemax(Int) + 1
-9223372036854775808

julia> typemax(Bool) + true
2
3 Likes

that’s just Vacuous truth - Wikipedia which is very common. The problem with Python is [] can be interpreted as Boolean, which Julia is very much not able to

2 Likes

Yeah, but I was ju saying the quote on “julia does the same thing” was mentioned only for the first example, and not the one you brought up.

that’s exactly what I don’t understand because the point of @ bkamins is the whole thing, not just all([]) being true or not. I don’t see how “Julia is the same” when it literally is NOT

1 Like

I also don’t think the all([]) example is at all confusing/surprising. That has always been exactly what I wanted it to do; I have always wanted all to mean that there are no exceptions (so all([]) == true), and any to mean that there is an exception (so any([]) == false). Any other behavior I’d find both surprising and annoying, as I’d then be forced to add length checks on all my uses.

The other Python cases I find more surprising.

3 Likes

I know (and sadly had to use) a language which does that: IDL.

1 Like

Does IDL also let you use integers in conditionals?

Yes, see the article linked. And why limiting to integers? They support floating point numbers too, both real and complex, but the rule for floating point numbers is different: zero is false, all the rest is true (complex numbers ignore the imaginary part, so there are plenty of falsy zeros). You get the best of both worlds! :grinning: And appreciate this example from the article

IDL> print, 2 or 0.
         2.00000

The literal 2 is somehow automatically converted to floating point, so it becomes true. You can’t even guess what the code is doing by reading it. IDL is a such a nonsense language that it all makes sense.

5 Likes

Yes, that is why it is the first example in the list. This example is the one that most people get right even without having to run the code. For the next two examples - most people get them wrong in Python if they are asked to guess the results and often even struggle to explain the reason for output produced once they see it.

The point is: such expressions should be easy to reason about without having to run the code.

5 Likes

They look a lot more attractive if you use the dignified term “generalized booleans”.

1 Like

This is great. I love examples of language designs that maybe made some sense in a microcosm but then become totally bizarre when you step back and look at the whole.

3 Likes

Sad that you need the emoticon to make sure we all get that it’s sarcasm :wink:

Hm, interesting I must have misremembered that. That’s unfortunate. In that case, I am a bit more sympathetic to your POV here, though I’d lean instead towards making true + true == false.

As far as I understand, + should be xor and * should be &

2 Likes

:frowning:

julia> true * false
false

In Base:

+(x::Bool, y::Bool) = Int(x) + Int(y)
-(x::Bool, y::Bool) = Int(x) - Int(y)
*(x::Bool, y::Bool) = x & y

It’s not obvious why. But, I’m sure it wasn’t an arbitrary choice.

It’s stated as

## do arithmetic as Int ##

+(x::Bool) =  Int(x)
-(x::Bool) = -Int(x)

+(x::Bool, y::Bool) = Int(x) + Int(y)
-(x::Bool, y::Bool) = Int(x) - Int(y)
*(x::Bool, y::Bool) = x & y
^(x::Bool, y::Bool) = x | !y
^(x::Integer, y::Bool) = ifelse(y, x, one(x))

in bool.jl

1 Like

Just like true & false == false, right? true == 1 and false == 0 so this is all consistent.

Same with true + true == 2 since 2 mod 2 == 0 == false. I just would have wanted addition on Bools to wrap around instead of widening.

4 Likes

Same with true + true == 2 since 2 mod 2 == 0 == false.

But, exactly because it widens this doesn’t make sense. Sure 2 mod 2 == 0 == false, but the return type is Int which doesn’t follow mod 2 artithmetic. I mean, is there a more “practical” reason for widening ?

1 Like

I think to allow something like this

sum(rand(Bool, 1000)) # to count true's

Although a little unfortunate, because there is count. Maybe there are more cases of use.

(Edit: easier example.)

4 Likes

Bools are often used as the “lowest type” form of 1/0 in order to prevent accidental type promotion, could this be a reason to define arithmetic the way it’s done? For example,

julia> I(2)
2×2 Diagonal{Bool, Vector{Bool}}:
 1  ⋅
 ⋅  1

produces a Bool matrix to make sure that, e.g., I(2)*B does not promote the type to a wider type than the type of B.

2 Likes