# Bool behavior for 2+, i.e. illegal values

**URL:** <https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328>\
**Category:** Internals & Design\
**Created:** [September 12, 2024, 1:53pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328 "2024-09-12T13:53:58Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [September 12, 2024, 1:53pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/1 "2024-09-12T13:53:58Z")

</div>

I noticed in Dlang, most recent version:

> **[Change Log: 2.109.1 - D Programming Language](https://dlang.org/changelog/2.109.1.html#dmd.unsafe-boolean-values)**
>
> D Programming Language

> #### Compiler changes
> 
> 1. [bool values other than 0 or 1 are not @safe](https://dlang.org/changelog/2.109.1.html#dmd.unsafe-boolean-values)
> 
> The spec has been updated so that only 0 and 1 are [safe values](https://dlang.org/spec/function.html#safe-values) for bool. This means that reading a bool value whose underlying byte representation has other bits set is implementation-defined and should be avoided. Consequently:

So got me curious what Julia does, and it seems whatever we do we have to live with it:

```julia
julia> reinterpret(Bool, UInt8(0))
false

julia> reinterpret(Bool, UInt8(1))
true

julia> reinterpret(Bool, UInt8(2))
false

julia> reinterpret(Bool, UInt8(3))
true

```

I would have though all non-zero should be true… and simple to check. Only the last bit seems to be “checked” with `and	al, 1`. See: `@code_native reinterpret(Bool, UInt8(2))`.

I believe it’s intentional to have Bool in 8 bits, not 1, in many languages including C++. But non-zero not always might be true in some other languages, or not done the same, so what are the pros and cons of either/any decision? The and is simple, but most often you test with `jne` (including in Julia?), so might Julia have a bug?

People aren’t supposed to construct other than 0 and 1 `Bool`s, so can it be disallowed/deprecated? I’m not sure it can however be stopped without speed penalty… and would be a breaking change to fail when seeing anything else. Or was that not promised behaviour to work?

---

<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:** [September 12, 2024, 2:07pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/2 "2024-09-12T14:07:51Z")

</div>

The `reinterpret` docstring contains a warning:

```julia
help?> reinterpret
  │ Warning
  │
  │ Use caution if some combinations of bits in Out are not considered valid and would otherwise be
  │ prevented by the type's constructors and methods. Unexpected behavior may result without
  │ additional validation.

```

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [September 12, 2024, 2:08pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/3 "2024-09-12T14:08:53Z")

</div>

Perhaps related:

> <https://github.com/JuliaLang/julia/pull/52189>
>
> Teach value\_to\_pointer to convert primitive types to their stored representation… first, to avoid exposing undef bits later (via memcpy).
> 
> Take this opportunity to also generalizes the support for zext Bool to anywhere inside any struct for changing any bitwidth to a multiple of 8 bytes. This would change a vector like \<2 x i4\> from occupying i8 to i16 (c.f. LLVM's LangRef), if such an operation were expressible in Julia today. And take this opportunity to do a bit of code cleanup, now that codegen is better and using helpers from LLVM.
> 
> Fixes #52127
> 
> For backporting this fix to older versions, the minimal diff to use is:
> \`\`\`diff
> diff --git a/src/codegen.cpp b/src/codegen.cpp
> index 5ad4eb4e6e..b89a9f5ca6 100644
> \--- a/src/codegen.cpp
> +++ b/src/codegen.cpp
> @@ -1935,6 +1935,8 @@ static bool valid\_as\_globalinit(const Value \*v) {
> static inline jl\_cgval\_t value\_to\_pointer(jl\_codectx\_t &ctx, Value \*v, jl\_value\_t \*typ, Value \*tindex)
> {
> Value \*loc;
> + if (v-\>getType()-\>isIntegerTy(1))
> + v = ctx.builder.CreateZExt(v, IntegerType::get(v-\>getContext(), 8));
> if (valid\_as\_globalinit(v)) { // llvm can't handle all the things that could be inside a ConstantExpr
> assert(jl\_is\_concrete\_type(typ)); // not legal to have an unboxed abstract type
> loc = get\_pointer\_to\_constant(ctx.emission\_context, cast\<Constant\>(v), Align(julia\_alignment(typ)), "\_j\_const", \*jl\_Module);
> \`\`\`

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [September 12, 2024, 2:17pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/4 "2024-09-12T14:17:13Z")

</div>

Julia has unsafe operations and undefined behaviour, but has not really defined what is safe and what isn’t. The meaning of unsafety and undefined behaviour is mostly (only?) known to a handful of core devs.

However, a recent PR explicitly mentions that creating `Bool` values with other bitpatterns than `0x00` and `0x01` to be undefined behaviour: [Add devdocs on UB by Keno · Pull Request #54099 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/54099/files#diff-cad50cf26296590b1937056ff6064bd99292b8428c0fdff1db0f682e8a48551cR34)

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [September 12, 2024, 2:17pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/5 "2024-09-12T14:17:30Z")

</div>

> [@Palli](#):
>
> So got me curious what Julia does, and it seems whatever we do we have to live with it:

```julia
julia> Bool(2)
ERROR: InexactError: Bool(2)
Stacktrace:
 [1] Bool(x::Int64)
   @ Base ./float.jl:251
 [2] top-level scope
   @ REPL[15]:1

```

`reinterpret` is for bit twiddling.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [September 12, 2024, 2:31pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/6 "2024-09-12T14:31:52Z")

</div>

Julia is a mostly safe language by default, i.e. excluding [ccall (or code depending on packages using… so basically all code), and `@inbounds` and], yes, reinterpret, then I think only for Bool (and only when “illegally” constructed; or on Big-endian, not a real worry).

I’m just thinking what was D’s reasoning, and would it apply to Julia?

I shorten the quote, missing this part from D:

> - void initialization of booleans is now deprecated in @safe code.
> - Reading a bool field from a union is now deprecated in @safe code.

And background:

> ### [Safe Values](https://dlang.org/spec/function.html#safe-values)
> 
> A variable or field [marked as @system](https://dlang.org/spec/attribute.html#system-variables) does not hold a safe value, regardless of its type.
> 
> For a [bool](https://dlang.org/spec/type.html#bool), only 0 and 1 are safe values.
> 
> For all other [basic data types](https://dlang.org/spec/type.html#basic-data-types), all possible bit patterns are safe.
> 
> A pointer is a safe value when it is one of:
> 
> 1. null
> 2. it points to a memory object that is live and the pointed to value in that memory object is safe.

Julia doesn’t have safe or unsafe regions of code (or then implied), like D and Rust, but could maybe.

They have `@safe` (and `@nogc`), a bit better than Julia, I think you need to opt into that (not sure) so actually D is historically an unsafe language like C++, but trying to be safe, has such a subset (I’m not sure if you can enable it globally), I think Julia might have an advantage, by being safe be default, except by how often in practice unsafe (and not easy to undo that or forbid that):

> ## 9.10 [@safe, @trusted, and @system Attributes](https://dlang.org/spec/attribute.html#safe)

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [September 12, 2024, 2:35pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/7 "2024-09-12T14:35:33Z")

</div>

I’m not sure this is related to this issue, but I talked with @gbaraldi at JuliaCon, and it is unclear whether that’s worth it. There are points where a conversion to `i8` are inevitable also in C, I seems to remember Gabriel came up with a C example involving pointers where also Clang was uplifting a boolean to `i8`, but now I don’t remember the details.

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [September 12, 2024, 2:45pm UTC](https://discourse.julialang.org/t/bool-behavior-for-2-i-e-illegal-values/119328/8 "2024-09-12T14:45:37Z")

</div>

But why do you want to use `reintrepret` at all to get a boolean value out of another integer? You even had to wrap it in `UInt8` (and good luck converting 256 with your approach) because that’s not really the intended way to do it. Unless you expect

```julia
julia> reinterpret(Int64, 3.0)
4613937818241073152

```

to return `3`.
