# Truthiness and short circuit or

**URL:** <https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486>\
**Category:** New to Julia\
**Created:** [February 5, 2026, 7:19pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486 "2026-02-05T19:19:56Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![Magnus\_Lilledahl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/magnus_lilledahl/32/51079_2.png) [@Magnus\_Lilledahl](https://discourse.julialang.org/u/Magnus_Lilledahl)\
**Post date:** [February 5, 2026, 7:19pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/1 "2026-02-05T19:19:56Z")

</div>

…based on a made up story:  
Somewhere in the cold, dark code

```julia-auto
>a = true && "scam"

```

The greedy novice wonders trough the code and asks:

```julia-auto
>a == false
false

```

…so `a` must `true`. Sweet!

```julia-auto
try
    if a 
        println("send me a billion dollars")
    end
catch e
   "You got scammed!"
end

```

…waiting to be rich…

```julia-auto
"You got scammed"

```

Whaaaat!?

I have seen that the functionality of the short circuit boolean operators have been discussed for many years ([an old discussion](https://discourse.julialang.org/t/proposal-then-else-syntax-to-replace-short-circuiting/1323)), but given all the high-and-mighty talk about no truthinesses in Julia I was (as a newbie) surprised to find that the first statement above did not return an error…

I guess this is more of comment than a question…

---

<div class="post-metadata">

**Author:** ![BioTurboNick](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bioturbonick/32/6380_2.png) [@BioTurboNick](https://discourse.julialang.org/u/BioTurboNick)\
**Post date:** [February 5, 2026, 7:25pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/2 "2026-02-05T19:25:24Z")

</div>

Well, you’re abusing try/catch to “use” a non-boolean variable as if it were a boolean. Without that, you would have seen the error telling you it wasn’t a boolean in the if statement.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [February 5, 2026, 7:40pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/3 "2026-02-05T19:40:51Z")

</div>

What did any of this have to do with truthiness and why would the greedy novice not just print the value of `a`?

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [February 5, 2026, 7:54pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/4 "2026-02-05T19:54:33Z")

</div>

> [@Magnus\_Lilledahl](#):
>
> surprised to find that the first statement above did not return an error…

Except… it does! You just caught and ignored it. Don’t do that (and similarly, don’t do things like `if a == true`).

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [February 5, 2026, 8:12pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/5 "2026-02-05T20:12:27Z")

</div>

The following three Julia expressions are essentially equivalent:

```julia
x = a && b && c

x = a ? (b ? c : b) : a

x = if a
    if b
        c
    else
        b
    end
else
    a
end

```

In particular, notice that `c` is never treated as a boolean. It is simply the value of the expression if `a` and `b` are `true`. You can also observe this in

```julia-repl
julia> true && 1 && 2 # 1 isn't a Bool
ERROR: TypeError: non-boolean (Int64) used in boolean context

julia> false && 1 && 2 # never tries to evaluate 1 as a Bool
false

```

---

<div class="post-metadata">

**Author:** ![technocrat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/technocrat/32/220947_2.png) [@technocrat](https://discourse.julialang.org/u/technocrat)\
**Post date:** [February 5, 2026, 9:54pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/6 "2026-02-05T21:54:41Z")

</div>

I’m quite fond of the ternary operator version because it’s both terse and easily translatable to

> Is `a` true? If so, if `b` is true, you have `c`, but if it’s not you still have just `a`.

Except that `c` may be `true` even if `b` is not. Too bad we don’t have a naive set theory operator to express `c <=> b`.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 6, 2026, 10:00am UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/7 "2026-02-06T10:00:35Z")

</div>

FWIW, julia mostly represents `Bool` as a byte, with `0x01 === true` and `0x00 === false`. However, testing for truthiness often only checks the lowest bit.

Now you might ask, what about “denatured” booleans like `0x02` or `0x03`? The answer is of course “bats in your nose undefined behavior”. Sometimes such heisenbools are `===` true/false, sometimes they are not, depending on how the compiler felt that day. (_of course_ behavior in interpreted and compiled mode will differ, making for a more teachable debugging experience)

Alas, you _can_ end up with denatured heisenbools if you play funny pointer games or use `Vector{T}(undef, ...)`.

Typical example would be

```julia-auto
struct WrappedBool value::Bool end;
v=Vector{WrappedBool}(undef, 100);

```

(I’m not sure whether we should consider this a bug)

PS. To give a complete example of a teachable debugging story:

```julia-auto
julia> struct WB x::Bool end; a=[0x02]; z=reinterpret(WB,a);

julia> f(wb)=@assert wb===WB(true);

julia> f(z[1]);

julia> @assert z[1]===WB(true);
ERROR: AssertionError: z[1] === WB(true)
Stacktrace:
 [1] top-level scope
   @ REPL[4]:1

```

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 6, 2026, 10:13am UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/8 "2026-02-06T10:13:59Z")

</div>

> [@foobar\_lv2](#):
>
> FWIW, julia mostly represents `Bool` as a byte, with `0x01 === true` and `0x00 === false`. However, testing for truthiness often only checks the lowest bit.

I suspect I know know what you mean here, but just to be clear for others reading along, julia’s bools are _not_ bytes semantically, and we do not allow truthiness:

```julia-auto
julia> 0x01 === true
false

julia> 0x00 === false
false

julia> if 0x01
           println("boo!")
       end
ERROR: TypeError: non-boolean (UInt8) used in boolean context
Stacktrace:
 [1] top-level scope
   @ REPL[13]:1

```

rather, the **underlying** data is a byte:

```julia-auto
julia> reinterpret(UInt8, true) === 0x01
true

julia> reinterpret(UInt8, false) === 0x00
true

```

This’d be like saying that

```julia-auto
struct Foo
    x::Int
end

```

is just an `Int`, but it’s not actually an `Int`, it’s a completely different type with arbitrarily different semantics and meaning in the language, it just happens to have a memory representation that’s identical to an `Int`.

---

<div class="post-metadata">

**Author:** ![technocrat](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/technocrat/32/220947_2.png) [@technocrat](https://discourse.julialang.org/u/technocrat)\
**Post date:** [February 6, 2026, 10:21am UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/9 "2026-02-06T10:21:42Z")

</div>

> [@foobar\_lv2](#):
>
> denatured heisenbools

Where has this lovely term been all my life?

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 6, 2026, 10:52am UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/10 "2026-02-06T10:52:46Z")

</div>

> [@Mason](#):
>
> This’d be like saying that

No, it’s more saying that: The underlying representation is an UIn8. But there are more `UInt8`s (`i8`) than there are `Bool`s (`i1`), so there are necessarily some possible memory contents that do not correspond to a valid Bool. I called them denatured heisenbools.

In julia (and rust) such denatured heisenbools are evil poison sludge: We don’t want to pay the price of treating the remaining 7 bits as structure padding, because that would make a lot of stuff more expensive (e.g. we would not be able to memcmp bool-containing structs to check for identity). So we simply assume that they are always zero and no denatured heisenbools ever appear, and try to guard the edges of our data.

If a denatured heisenbool manages to sneak in, then you are in for a bad time:

You cannot reliably check for that, because the compiler knows that the remaining bits are zero and will try its best to optimize the check away. And if you add debug print assert logging to your misbehaving code, or try to step through it in interpreted mode, then behavior will change because the optimizer takes different paths.

And you can end up in seemingly impossible situations, where something appears to be neither true nor false, or appears to be both at the same time, or change its truthiness depending on context.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 6, 2026, 11:05am UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/11 "2026-02-06T11:05:15Z")

</div>

> [@foobar\_lv2](#):
>
> No, it’s more saying that: The underlying representation is an UIn8. But there are more `UInt8`s (`i8`) than there are `Bool`s (`i1`), so there are necessarily some possible memory contents that do not correspond to a valid Bool. I called them denatured heisenbools.
> 
> In julia (and rust) such denatured heisenbools are evil poison sludge: We don’t want to pay the price of treating the remaining 7 bits as structure padding, because that would make a lot of stuff more expensive (e.g. we would not be able to memcmp bool-containing structs to check for identity). So we simply assume that they are always zero and no denatured heisenbools ever appear, and try to guard the edges of our data.

I could do the same thing with my `Foo` struct via inner constructors and other stuff (e.g. only accept even integers or whatever).

I get your wider point here, and I get that there are real potential problems with these things, I just want to make it clear to people reading this that what you said is completely false if read literally. `0x01 === true` does not hold. It’s false. They’re different types.

The reason I bring this up is that this entire thread was originally about @Magnus_Lilledahl using a `try catch` block to (falsely) claim that julia has truthy values when it doesn’t.

Something can only be used as a `Bool` if it is of type `Bool`. The fact that it’s possible to bypass the inner constructor of `Bool` and create values of type `Bool` that don’t conform to the actual requirements of the `Bool` type is of course important and dangerous, but I’d say it’s not the same thing as truthiness, and it certainly is not the same thing as `0x01 === true` (which again, does not hold).

---

<div class="post-metadata">

**Author:** ![Magnus\_Lilledahl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/magnus_lilledahl/32/51079_2.png) [@Magnus\_Lilledahl](https://discourse.julialang.org/u/Magnus_Lilledahl)\
**Post date:** [February 6, 2026, 12:32pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/12 "2026-02-06T12:32:31Z")

</div>

Thank you all for a very interesting and enlightening discussion, I certainly learned a lot more than I could hope for.

When I read in the manual about the how the only logical values allowed in Julia are `true` and `false` (and of type `Bool`), I extrapolated from this that all logical operations will only allow arguments of type `Bool` (which I guess is true?).

My confusion arose when I saw the following in a line of code

```julia-auto
float(r) == p || r

```

where `r` and `p` are some number types. Since I (wrongly?) thought `||` and `&&` were logical operators (OR and AND) I was confused about what this meant since Julia is so strict about truth values and `r` is a number.

But maybe it is more correct to think of `||` and `&&` as conditional statements (that can be used as logical statements) as illustrated by @mikmoore?

My rather contrived story in the original post was an more an attempt to illustrate my original confusion (which was primarily about `||` and `&&` and not Julias truth values) than anything else.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [February 6, 2026, 12:43pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/13 "2026-02-06T12:43:04Z")

</div>

> [@Magnus\_Lilledahl](#):
>
> My rather contrived story in the original post was an more an attempt to illustrate my original confusion (which was primarily about `||` and `&&` and not Julias truth values) than anything else.

I see, but I think if you read back your original post, you might agree that your contrived example completely rested on `try / catch` throwing away an error that would have invalidated the example.

> [@Magnus\_Lilledahl](#):
>
> My confusion arose when I saw the following in a line of code
> 
> ```julia-auto
> float(r) == p || r
> 
> ```
> 
> where `r` and `p` are some number types. Since I (wrongly?) thought `||` and `&&` were logical operators (OR and AND) I was confused about what this meant since Julia is so strict about truth values and `r` is a number.
> 
> But maybe it is more correct to think of `||` and `&&` as conditional statements (that can be used as logical statements) as illustrated by @mikmoore?

In the future, I’d maybe just say that, because this makes it much more clear what the actual problem you are addressing is.

I agree that `||` and `&&` can be a bit misleading. If you want the logical operators, you should use `|` and `&`.

```julia-auto
julia> true | 1.0
ERROR: MethodError: no method matching |(::Bool, ::Float64)
The function `|` exists, but no method is defined for this combination of argument types.

```

`a || b` should instead be understood as convenient syntax for

```julia-auto
cond = a
if cond
    cond
else
    b
end

```

and `a && b` should be understood as convenient syntax for

```julia-auto
cond = a
if cond
    b
else
    cond
end

```

this means that the left hand side of `||` or `&&` has to evaluate to a `Bool`, but the right hand side can be anything. For the most part, these operators are used in contexts where `b` doesn’t actually return anything. i.e. people will write stuff like

```julia-auto
a && break

```

or

```julia-auto
a || error(...)

```

---

<div class="post-metadata">

**Author:** ![Magnus\_Lilledahl](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/magnus_lilledahl/32/51079_2.png) [@Magnus\_Lilledahl](https://discourse.julialang.org/u/Magnus_Lilledahl)\
**Post date:** [February 6, 2026, 1:35pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/14 "2026-02-06T13:35:51Z")

</div>

> [@Mason](#):
>
> I see, but I think if you read back your original post, you might agree that your contrived example completely rested on `try / catch` throwing away an error that would have invalidated the example.

Absolutely.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [February 6, 2026, 3:43pm UTC](https://discourse.julialang.org/t/truthiness-and-short-circuit-or/135486/15 "2026-02-06T15:43:04Z")

</div>

> [@Magnus\_Lilledahl](#):
>
> But maybe it is more correct to think of `||` and `&&` as conditional statements (that can be used as logical statements) as illustrated by @mikmoore?

From Julia 1.12, the docstring is quite enlightening:

```julia-auto
help?> &&
search: && &

  x && y

  Short-circuiting boolean AND.

  This is equivalent to x ? y : false: it returns false if x is false and the result of evaluating y if x is
  true. Note that if y is an expression, it is only evaluated when x is true, which is called
  "short-circuiting" behavior.

  Also, y does not need to have a boolean value. This means that (condition) && (statement) can be used as
  shorthand for if condition; statement; end for an arbitrary statement.

  See also &, the ternary operator ? :, and the manual section on control flow.

```
