<p>Some languages (C, C++, JavaScript, Python) allow one to use integers as booleans and vice versa:</p>
<pre><code>int x;
if (x) // Equivalent to: x != 0
    y();
</code></pre>
<p>Or:</p>
<pre><code>int x = 10 + (y &gt; 10); // Equivalent to: y &gt; 10 ? 11 : 10
</code></pre>
<p>However, other languages such as Java, C#, and Swift disallow this. They do not even allow explicit casting and force users to explicitly write <code>!= 0</code> and <code>? 1 : 0</code> to cast from integer to boolean or boolean to integer respectively.</p>
<p>What is the rationale for disallowing this? Allowing integers and booleans to freely convert allows certain logic to be expressed much more concisely, such as that to <a href="https://stackoverflow.com/a/65031220/16217248">determine if exactly N conditions are true</a>. So what are the drawbacks?</p>

<numbers><integers><booleans>
What are the drawbacks of allowing implicit boolean/integer conversions?
CC BY-SA 4.0
2023-11-22T08:02:48.367Z
This sort of implicit conversion would probably remove the ability to do nullability checks on nullable types. In typescript it saves a lot of space when checking if something is null or undefined to have a check like 'if (!someNullableInt) ...' that checks if the value has been set. It would have to be replaced with a full check like 'if (someNullableInt === null) ...'. I think C# or VB might have the same kind of check.
TheEvilMetal
CC BY-SA 4.0
2023-11-22T13:30:24.527Z
Note that Python does not have bool/integer *conversions*. Booleans *values* are integers - namely 0 and 1 of an integer subtype. This is separate from *general* values - incidentally, including integers - having boolean *meaning* such as empty lists being falsy and non-empty lists being truthy. The two are separate mechanisms each with their own drawbacks.
MisterMiyagi
CC BY-SA 4.0
2023-11-23T18:49:07.033Z
It may not be clear which of 0 and 1 is true and which is false. E.g., the return code of  a successful command or system call is traditionally 0 and that of an unsuccessful command is nonzero (with different values hinting to different reasons of failure). Nevertheless, one would rather associate true with success and false with failure. And even if one knows about this logic quirk, it is much safer to write `if (something() == ERROR_SUCCESS)` instead of `if (!something())`
Hagen von Eitzen
<h3>Booleans may not just be 1 or 0</h3>
<p>Much of this depends on the underlying representation of the value.  My particular experience of this is with C.</p>
<p>Before C99, there was no boolean type, only integers treated as booleans.  Boolean data of course can only be 0 or 1; but an integer type can clearly have more states.  Consider the code</p>
<pre><code>if (x == TRUE)
    do_something();

do_another_thing();

if (x == FALSE)
    do_something_else();
</code></pre>
<p>Clearly if x is boolean then one or other function should be called.  But if x (as an integer) has been set to 2 for example, then <em><strong>neither</strong></em> function will be called!  For that reason, coding standards often required the form</p>
<pre><code>if (x)
    do_something();

do_another_thing();

if (!x)
    do_something_else();
</code></pre>
<p>so that all non-zero values would be covered by the first case.  (I should say here that this is not just a theoretical issue.  I have personally seen this bug happen, and it was really hard to find!)</p>
<p>C99 solved this particular problem by adding a <code>bool</code> type, where <code>if (x == TRUE)</code> succeeds for any non-zero value of x.  However you can still go wrong with this.  Most notably, your &quot;efficient&quot; method of summing bools to find how many values are set true is going to fail badly if any are stored as integer values greater than 1.</p>
<p>More interestingly still, you can't even quantify how badly that method will fail.  C merely requires <code>bool</code> to have at least 2 states, and the compiler is perfectly free to store this in a single bit, a byte, or a 32-bit word.  I can point you to compilers/hardware which would give you all of these cases.  I've personally stumbled over a bug where two different processors accessing shared memory represented <code>bool</code> as a byte on one side and a 32-bit word on the other, so I actually had to replace the &quot;better&quot; <code>bool</code> definitions in the shared memory structures with fixed-size integers which both sides could agree on.</p>
<p>This is all somewhat specific to C, of course, but the principles apply to most languages.  Ultimately your boolean value needs to be stored somewhere, and if execution speed is an issue then your language may well use a single word per boolean value so that your code runs faster.  Of course this may not be as applicable to interpreted languages such as Python, where the language is already slow enough that a small extra delay is not significant.</p>
<h3>A class of bugs can be eliminated</h3>
<p>Bugs happen, let's be real about that.  One sign of clearly-written code is that it can be easier to find bugs when they happen.  And one sign of a language that helps you is where a class of bugs can be eliminated by a language feature.</p>
<p>If you got the wrong variable in your <code>if (x)</code> check (and hands up any coder who hasn't? no hands? good, we're all in the real world here) then you've got a bug.  If you accidentally use the name of another boolean variable then your code will build, and it will misbehave, but at least it will misbehave in a predictable, repeatable way.</p>
<p>If you accidentally use the name of an integer variable though, with a language which gives you implicit conversions, all the issues above could come out of the woodwork.  If your language gives you an implicit zero/non-zero comparison then at least some of those problems go away, but reproducing it is likely to be <em>hard</em>.  If your language stops these bugs at compile time, an entire class of bugs will simply go away.  This is generally a good thing (assuming you can potentially handle a bit of inefficiency in the code anyway).</p>

CC BY-SA 4.0
2023-11-21T17:08:07.550Z
2023-11-21T23:23:55.030Z
2023-11-21T23:23:55.030Z
Graham
<p>The main drawback of allowing implicit boolean/integer conversions is, it makes it impossible to prevent errors that result from confusion of a boolean and an integer.</p>
<p>Next time you confuse the order of the arguments to a function that takes an integer and a boolean, instead of getting a nice error message that points out what you did wrong, it will compile and do something unexpected.</p>
<p>It is a fairly important drawback. If the conversion is infrequently used, forcing the user to be explicit is a good thing. Besides, <code>!= 0</code> and <code>? 1 : 0</code> are not that long to write.</p>

CC BY-SA 4.0
2023-11-20T22:36:46.813Z
2023-11-20T22:36:46.813Z
Eldritch Conundrum
CC BY-SA 4.0
2023-11-21T07:57:15.303Z
You don't even need `? 1 : 0` for converting boolean to integer, you can have an _explicit_ conversion syntax such as `int(b)` or `b as int`.
Matthieu M.
CC BY-SA 4.0
2023-11-21T10:50:19.313Z
Treating ints like booleans made sense in C, which didn't originally _have_ a separate boolean type — you _always_ used ints, with 0 meaning false and non-zero true.  (And IIRC, when a boolean keyword was first added, it was effectively just a synonym for int anyway.)  In that case, it made sense for conditions to accept an int.  But, as you say, that has very significant drawbacks.  Strongly-typed languages with a separate boolean type don't _need_ to treat ints as booleans — the benefits of doing so are minimal.  (As you show, it's easy to convert, though IME you hardly ever need to.)
gidds
CC BY-SA 4.0
2023-11-21T10:51:14.203Z
@MatthieuM. (That depends upon the language.)
gidds
CC BY-SA 4.0
2023-11-21T10:54:35.833Z
@gidds: I'm not talking about _any_ language in particular, I'm talking about _language design_. When designing a language, you can introduce a more specialized syntax than `? 1 : 0` to convert from boolean to integer.
Matthieu M.
CC BY-SA 4.0
2023-11-21T13:14:43.357Z
A nice Python idiom (mentioned in the link in the question) that is based on this implicit conversion is of `sum(booleans)` to count how many True values there are in a boolean collection. It's of course possible to also do this more explicitly with something like `sum(map(int, booleans))`, but I do feel something would be lost in expressiveness if this implicit conversion was absent.
yoniLavi
CC BY-SA 4.0
2023-11-21T18:19:07.557Z
@MatthieuM. Indeed — but some languages don't have explicit boolean-to-int casts/conversions, just as some don't have conditional expressions (as opposed to statements).  (And even those that do don't always agree — some languages use -1 for true instead of 1, and others use 0 for true and non-zero for false.)  Of course, if you're designing a new language, you're free to choose — but why not choose to have a proper boolean type, and avoid all the complications and bug possibilities that come from entangling it with integers at all?
gidds
CC BY-SA 4.0
2023-11-22T07:47:07.640Z
@gidds: I never said anything about existing languages, so I don't understand your rant. And as for your question, explicit conversion is precisely about converting between two proper types... so, we're in agreement?
Matthieu M.
CC BY-SA 4.0
2023-11-22T08:53:45.393Z
@yoniLavi Actually in python it would probably be much safer to do `sum(map(bool, booleans))` than `sum(map(int, booleans))` to avoid unexpected behaviours in the case where some of the "booleans" turns out not to be of type bool. See kaya3 's answer for fun examples.
Stef
CC BY-SA 4.0
2023-11-22T15:22:29.297Z
@MatthieuM. Rust satisfies your request! It requires an explicit cast from bool to int! e.g. `false as u32` --> `0u32`, `true as i8` --> `1i8`.
Nayuki
CC BY-SA 4.0
2023-11-22T15:33:45.563Z
@Nayuki: Yes, I know. Once again, I'm not looking for an existing language so much as discussing ways to have ergonomic explicit conversions in general.
Matthieu M.
CC BY-SA 4.0
2023-11-23T11:55:51.597Z
Thanks @Stef, yes, absolutely agreed. But my point is just the fact that being able to add up booleans is expressively pleasing. Also, a common sub-idiom of this would be of using a generator expression, whereby I know all elements are bools, e.g.: `sum(word.endswith("s") for word in words)`
yoniLavi
CC BY-SA 4.0
2023-12-05T23:18:54.507Z
While `cond ? 1 : 0` isn't that long to write, I've gotten annoyed at having to write `CASE WHEN cond THEN 1 ELSE 0 END` in SQL dialects without implicit Boolean/integer conversions.
dan04
<p>One particularly bad issue with int to bool conversions is that if you have an expression based language, the assignment <code>x=7</code> will typically return <code>7</code>. This makes <code>if x=7</code> valid syntax, which is really bad since this is a common typo for <code>if x==7</code>.</p>

CC BY-SA 4.0
2023-11-22T03:42:47.697Z
2023-11-22T03:42:47.697Z
Oscar Smith
CC BY-SA 4.0
2023-11-22T12:30:45.043Z
Some people might argue that things like `if (errCode = tryDoingSomething()) { handleError(errCode); }` make this a good feature, and equality checks should be written flipped like `if (7==x)` to avoid the bug possibility. I wouldn't necessarily agree with them.
leftaroundabout
CC BY-SA 4.0
2023-11-22T21:01:47.413Z
@leftaroundabout That use-case is still allowed as `if((errCode = tryThing()) != 0) ...`, and is more explicit that way. If I saw the code without `!= 0` I would have to think about it because it looks so much like a mistake.
kaya3
CC BY-SA 4.0
2023-11-22T23:52:56.830Z
@kaya3 I like neither of these, would prefer `case tryThing() of { Ok -> ... ; Failure errCode -> ... }`.
leftaroundabout
<p>There are some common errors that result from integer to boolean conversions.</p>
<p>One of the most common among C beginners is the <code>strcmp()</code> function. As a comparison function, it's easy to assume that it returns a boolean, with the truthy value meaning the strings are equal. But it's actually tri-valued: negative and positive for unequal (indicating whether one string is lexicographically lower or higher), and zero (C's falsey value) meaning equal.</p>
<p>Another class of functions with a similar problem is functions that search a string or array and return the index of a match. Since most languages use zero-based indexes, <code>0</code> is a valid index of a successful search, and some other value must be returned to indicate failure. JavaScript returns <code>-1</code>; PHP returns <code>false</code> (you must use the strict comparison operator to avoid automatic coercion that makes <code>0 == false</code>); Python returns <code>-1</code> from some functions and raises an exception from others. But again, it's a common mistake to treat the searching function as boolean.</p>

CC BY-SA 4.0
2023-11-21T15:30:09.180Z
2023-11-21T15:30:09.180Z
Barmar
<p>In addition to all the other fine answers, Boolean coercions are not consistent across languages:</p>
<ul>
<li><p>Zero (<code>0</code>) is considered falsy in Python and JavaScript, but truthy in Ruby.</p>
</li>
<li><p>The empty array (<code>[]</code>) is considered falsy in Python, but truthy in JavaScript and Ruby.</p>
</li>
<li><p>Not-a-number (<code>NaN</code>) is considered falsy in JavaScript, but truthy in Python and Ruby.</p>
</li>
</ul>
<p>Note that the only two falsy values in Ruby are <code>false</code> and <code>nil</code>. That means everything else is truthy. Python and JavaScript have longer lists of falsy and truthy values. Python and C++ allow operator overloading to define custom coercions to <code>bool</code>.</p>
<p>I personally agree with the strict, explicit approach to Booleans that is enforced by Java, C#, and Rust.</p>

CC BY-SA 4.0
2023-11-22T15:17:59.643Z
2023-11-22T15:17:59.643Z
Nayuki
CC BY-SA 4.0
2023-11-23T08:15:23.330Z
Just for fun you should add POSIX shell or Bash to your list.
detly
CC BY-SA 4.0
2023-11-23T08:33:30.363Z
As an embedded engineer mostly working with C and C++, that's a brilliant point I hadn't even thought of. And a good prompt to me to learn some more languages. :)
Graham
<h2>There might not be a sensible, unambiguously correct conversion</h2>
<p>The popular Numpy third-party library for Python provides a clear case study for this possibility. Because Python is dynamically typed, it is forced to accept code that would invoke an implicit conversion. Early on, the language implementers chose to allow such conversions to be attempted, and specified that types could define this conversion using the <code>__bool__</code> &quot;magic method&quot;.</p>
<p>This is a trade-off made for pragmatic reasons; in many other places, Python refuses implicit conversions and remains fairly <em>strongly</em> typed (for example, it does not allow concatenating an integer to a string with the semantics of implicitly using a string representation of the integer). In the case of conditional logic, the Python implementers apparently felt that requiring conversions all the time to avoid exceptions would be too tedious. <strong>However, the Numpy implementers found a need to refuse this convenience</strong>.</p>
<p>Numpy defines an array type that provides a bunch of operator overloads that implicitly &quot;broadcast&quot; operations - comparing two identically-shaped arrays element-wise, or repeating the comparison along one or more axes if the array shapes are &quot;compatible&quot;.</p>
<p>In particular, for two arrays <code>a</code> and <code>b</code> of the same shape, <strong>the <code>==</code> operator</strong> (via overloaded <code>__eq__</code> method) will compare each pair of corresponding elements, and <strong>return a new array of booleans</strong> of the same shape with the comparison results in the corresponding places:</p>
<pre><code>&gt;&gt;&gt; import numpy as np
&gt;&gt;&gt; a = np.ones((3,3))
&gt;&gt;&gt; b = np.ones((3,3))
&gt;&gt;&gt; a[:,1] = 0
&gt;&gt;&gt; b[1,:] = 0
&gt;&gt;&gt; a
array([[1., 0., 1.],
       [1., 0., 1.],
       [1., 0., 1.]])
&gt;&gt;&gt; b
array([[1., 1., 1.],
       [0., 0., 0.],
       [1., 1., 1.]])
&gt;&gt;&gt; a == b
array([[ True, False,  True],
       [False,  True, False],
       [ True, False,  True]])
</code></pre>
<p>This sort of functionality is considered very useful, and a huge part of the reason why Python enjoys the popularity it does today with data scientists.</p>
<p>So the next question is, what should we expect to happen for <code>if a == b:</code>, or in a conditional expression like <code>'y' if a == b else 'n'</code>?</p>
<p>Python has built-in fallback logic for comparisons - normally, everything that isn't explicitly falsy via an overloaded <code>__bool__</code>, is truthy (via <code>object.__bool__</code>). However, <strong>Numpy explicitly overloads <code>__bool__</code> for arrays to raise an exception unless the array has exactly one element</strong>. (It used to consider <em>zero</em>-element arrays falsy, but current versions also raise an exception here.)</p>
<p>Why?</p>
<p>This is in accordance with the Zen of Python: <strong>&quot;In the face of ambiguity, refuse the temptation to guess&quot;</strong>.</p>
<p>Think about it: <code>if a == b:</code> comparing two Numpy arrays, presumably, <em>probably</em> meant to check whether <em>every</em> corresponding pair of elements is equal. But the result of <code>a == b</code> is just an array of boolean values. Meanwhile, <code>if c:</code>, where <code>c</code> was an already existing array of boolean values, <em>probably</em> means to check whether <em>any</em> element is <code>True</code>. <strong>There is no way for the <code>__bool__</code> operator overload to know which was meant</strong>, because <em>it does not have access to the AST</em>.</p>
<p>Moreover, <strong>such logic is often wrong-headed anyway</strong>. Commonly, people want the code inside the block to describe work to do with a single pair of elements, and the code author wants that calculation to be broadcast - but Numpy simply cannot work this way. There definitely <strong>isn't any operator to overload</strong>, because <code>if</code> is a statement rather than an expression. But even the conditional expression form doesn't work, and Numpy couldn't make it work if they wanted to. One might think that <code>'y' if a == b else 'n'</code> ought to produce an array of strings, but <strong>even if it could work, this would be deeply magical</strong> and many Pythonistas would complain about it being complex and surprising. (Even using the <code>x if y else z</code> conditional expression is not universally accepted; but it would be especially hard to accept that the result might be neither <code>x</code> nor <code>z</code>!)</p>
<p>Instead, that job requires a different tool, such as <code>numpy.where</code>, or using the <code>a == b</code> result as a mask for another array, etc.</p>
<p>See also the <a href="https://stackoverflow.com/q/10062954">corresponding canonical on Stack Overflow</a> about the error message generated by the attempted implicit conversion - especially <a href="https://stackoverflow.com/a/75338248">my answer there</a>.</p>

CC BY-SA 4.0
2023-11-24T04:22:36.183Z
2023-11-24T04:22:36.183Z
Karl Knechtel
<p>Many of the advantages associated with allowing implicit conversion could be achieved by instead providing convenient means of handling the scenarios where such conversions would be most useful.  If one wants to branch if <code>foo</code> and <code>bar</code> have any bits in common, being able to write an expression where <code>foo</code> and <code>bar</code> are the only things that look like values, e.g. <code>if (foo &amp; bar)</code> is nicer than having to do something like <code>if ((foo &amp; bar) != 0)</code>.  If, however, there were an operator which would accept two integers and return a Boolean, that would make intent even clearer than the form using implicit integer-to-Boolean conversion.</p>
<p>Additionally, if a language had an operator that behaves like Javascript's &amp;&amp; operator, yielding the second operand's value when the first is &quot;truthy&quot;, then an expression like <code>(a==b) | ((x==y)*2)</code> could be written as <code>((a==b) &amp;&amp; 1) + ((x==y) &amp;&amp; 2)</code>.  I'm not sure <code>&amp;&amp;</code> would be the best choice for that operator, but having an operator with such semantics would accommodate the second most common use case for implicit Boolean/integer conversions.</p>
<p>An as-yet unmentioned downside to opening up arbitrary integer-to-Boolean conversions in languages which support bit fields, the semantics of Boolean bitfields would differ from those of other types.  For example, given:</p>
<pre><code>struct foo {unsigned char bit:1; _Bool boo:1;} it;
void test(int value)
{
  it.bit=value;
  it.boo = value;
}
</code></pre>
<p>invoking <code>test(2)</code> would set <code>it.bit</code> to zero but <code>it.boo</code> to 1.</p>

CC BY-SA 4.0
2023-11-21T19:42:00.490Z
2023-11-22T19:13:59.057Z
2023-11-22T19:13:59.057Z
supercat
CC BY-SA 4.0
2023-11-21T21:35:19.243Z
I'm not sure how your proposed `&&` operator works when the first operand is false. Presumably it needs to evaluate to 0?
kaya3
CC BY-SA 4.0
2023-11-21T21:37:23.500Z
@kaya3: It would evaluate to a zero of the second operand's type.  Shorthand for `x ? y : 0`.
supercat
CC BY-SA 4.0
2023-11-22T12:38:00.273Z
I don't see what's wrong with `if ((foo & bar) != 0)`. Very few extra characters in exchange for substantially better understandable code, without needing any special definitions. In fact I'd be tempted to write it like `if ((foo & bar) != 0x0000)`.
leftaroundabout
CC BY-SA 4.0
2023-11-22T16:00:50.337Z
@leftaroundabout: In many cases, the intended semantics would check whether some subset of the bits in a value match a pattern--equivalent to `if (((value ^ pattern) & mask) != 0)`, but if the pattern bits are all zero, `^pattern` can be omitted.  This construct only works if the right hand side of the `!=` is zero, but writing out the `0` in source code suggests that some other value could be substituted.
supercat
CC BY-SA 4.0
2023-11-22T18:09:48.970Z
@leftaroundabout: If a langue had types for values that could be used like integers or read-only bitfields, then a construct like `if (WIDGET->CONTROL & WIDGET_CONTROL_FNORBLE_MASK)` or `if ((WIDGET->CONTROL & WIDGET_CONTROL_FNORBLE_MASK) != 0)` could sensibly be replaced by `if (WIDGET.CONTROL.FNORBLE)` [for a one-bit field] or  `if (WIDGET.CONTROL.FNORBLE != 0)` [for a multi-bit field], but I've not seen any language that would facilitate such constructs.
supercat
CC BY-SA 4.0
2023-11-23T00:18:53.317Z
Well, conceptually what we're dealing with here are sets, then the special case is just an element lookup `if (fnorble∈control)`, or `if (widget.control.contains(FNORBLE))`, and the general case is `if (isEmpty(foo∩bar))` or `if (foo.intersect(bar).empty())`. Of course a typical set data type is much slower than bitmasks, but you could have a type parameterised by a type-level list that has an interface like a set but is under the hood just an integer where each bit denotes an element. It's not too difficult to code this up in Haskell, and should also be possible in modern C++.
leftaroundabout
CC BY-SA 4.0
2023-11-23T07:10:39.723Z
@leftaroundabout: Yeah, it's possible to implement such things in C++, and I've actually done it when writing an emulation wrapper that could process PIC C code as a Windows application with simulated I/O, but if one doesn't have such facilities being able to use bitmasks conveniently without having to test an intersection against zero would be nicer than not being able to do so.
supercat
CC BY-SA 4.0
2023-11-23T09:51:41.430Z
@supercat, If I got that right, I would write it as `if ((value & mask) != pattern)`
ilkkachu
CC BY-SA 4.0
2023-11-23T15:56:45.707Z
The `(value ^ pattern) & mask` pattern will handle cases like testing if all any the specified 4-bit fields in a word hold something other than 0x0B via `if ((value ^ 0xBBBBBBBB) & mask)`, without having to adjust the pattern according to the mask.  One could use `if ((value & mask) != (0xBBBBBBBB & mask))`, but that would violate the "don't repeat yourself" principle even if a compiler was able to optimize it to the faster sequence of operations using xor.
supercat
<p>If <code>int</code> implicitly converts to boolean I can't write <code>x ?: 3</code> where <code>x</code> is <code>maybe&lt;int&gt;</code>, and <code>?:</code> is null coalesce operator. This ends up being ambiguous between coalesce null to 3 and coalesce 0 to 3. (GCC has the latter operator: 0 ?: 3 does in fact produce 3. The operator is more useful when the left side is a pointer.)</p>
<p>If you make the choice <code>maybe&lt;int&gt; -&gt; bool</code>, you then have to choose between 0 is kept or coalesced. If you choose coalesced, your type system ultimately requires backtracking to determine the type of a chained coalesce (<code>maybe&lt;int&gt; ?: a : b</code> is hard to find the type of if b is a ternary). If you choose kept, you then have to decide what <code>maybe&lt;int&gt;(0) ? a : b</code> does. If you choose a, you end up with a big difference between <code>maybe&lt;int&gt;</code> and <code>int</code> such that the program becomes hard to read if you have the <code>var</code>/<code>auto</code> mechanism for getting type of variable from its right side (which is typically a function call return); and if you choose b, you have a behavior difference between coalesce and ternary.</p>
<p>If <code>T[]</code> (array) collapses to <code>bool</code>; it's ambiguous between <code>maybe&lt;[]&gt;</code> and <code>{}</code> (empty array); empty array collapsing to <code>bool</code> as false always bugged me for this very reason, but collapsing to <code>bool</code> as true is totally unexpected. (Yes I really did mean to write collapse as this converts a vector to a scalar.)</p>
<p>You really don't want <code>maybe&lt;bool&gt;</code> converting to <code>bool</code>; bug rats nest. If you think you need it, consider allowing <code>if(maybe&lt;bool&gt;)</code> to be valid as-is; that is <code>if</code>, <code>while</code>, and <code>for</code> take <code>maybe&lt;bool&gt;</code> directly. This will, however, make for a small headache if you also have <code>maybe&lt;T&gt;</code> converting to bool as the standard way to check if a <code>maybe</code> has a value, which will typically exist in languages that do implicit conversions to bool.</p>

CC BY-SA 4.0
2023-11-21T22:32:29.427Z
2023-11-23T16:45:06.540Z
2023-11-23T16:45:06.540Z
Joshua
CC BY-SA 4.0
2023-11-23T16:04:02.810Z
I'm having trouble following the reasoning here. In languages I am familiar with, if we have something like `maybe<int>` then a null coalesce operator will be sensitive to a `None`/`Null`/`maybe:None` value *that is separate from boolean `false`*. Can you clarify why you assume conversion `int` -> `bool` also implies conversion `maybe<int>` -> `bool`? Are you confusing conversion to bool with conversion to null/undef/...? Perhaps clarifying by which language's semantics you are reasoning here would be helpful for making the answer easier to follow.
MisterMiyagi
CC BY-SA 4.0
2023-11-23T16:46:17.853Z
@MisterMiyagi: I filled in a whole bunch of reasoning. Ultimately this is hard to understand because it's a case of something has to be surprising but the language designer can choose which thing is surprising.
Joshua
CC BY-SA 4.0
2023-12-03T18:35:54.063Z
Swift had a similar problem. They allowed optionals in an if, treating nil as false and not nil as true. Then someone realised that an optional bool that is false behaved differently from a non-optional bool that is false. That feature was removed.
gnasher729
<p>The reason to not allow it is that booleans are not numbers. Just like pointers are neither numbers nor booleans. So without 50 years of prejudice from C programming, there is no sane reason why a cast, either implicit or explicit should be allowed.</p>

CC BY-SA 4.0
2023-12-03T18:31:57.863Z
2023-12-03T18:31:57.863Z
gnasher729
CC BY-SA 4.0
2023-12-03T18:45:56.210Z
The question asks what the drawbacks are; you have not proposed any drawbacks. This answer is really just a philosophical opinion.
kaya3
CC BY-SA 4.0
2023-12-07T09:45:42.500Z
The obvious drawback is confusion between two incompatible concepts.
gnasher729
<p>There is a particular drawback of allowing implicit conversions (aka coercions*) from <code>bool</code> to <code>int</code> in dynamic languages such as Python, where many other types have coercions to <code>bool</code>. Coercions are generally not <a href="https://en.wikipedia.org/wiki/Transitive_relation" rel="noreferrer">transitive</a>, meaning that e.g. allowing coercion from <code>list</code> to <code>bool</code> and coercion from <code>bool</code> to <code>int</code>, does not imply that there is a coercion from <code>list</code> to <code>int</code>, let alone that this coercion would be consistent with the composition of the other two.</p>
<p>So consider code like this:</p>
<pre class="lang-python prettyprint-override"><code>def exactly_two(x, y, z):
    return x + y + z == 2
</code></pre>
<p>The <code>exactly_two</code> function uses <code>bool</code>-to-<code>int</code> coercion to test whether exactly two of the conditions are true. However, this means it relies on the arguments being <code>bool</code> values; yet in most places where a condition is tested, the condition is allowed to be some other type which coerces to <code>bool</code>. Consider:</p>
<pre class="lang-python prettyprint-override"><code>a, b, c = [1, 2, 3], [], [4, 5]
print(exactly_two(a, b, c))
</code></pre>
<p>The desired behaviour of the above program is to print &quot;True&quot;, since exactly two of the given lists are truthy (non-empty). However this program actually prints &quot;False&quot;, since <code>x + y + z</code> is a sum of lists, not a sum of Booleans coerced to integers.</p>
<p>This can get even messier when the coercion from <code>int</code> to <code>bool</code> is also considered:</p>
<pre class="lang-python prettyprint-override"><code>p, q, r = 2, 3, 0
print(exactly_two(p or q, p and r, q and r))
</code></pre>
<p>In Boolean logic, the above program should print &quot;False&quot; since only the condition <code>p or q</code> is true. However, in Python the condition <code>2 or 3</code> doesn't evaluate as <code>True</code>, it evaluates as <code>2</code>. Then the condition <code>x + y + z</code> is <code>2 + 0 + 0</code>, and hence the program prints &quot;True&quot;.</p>
<hr />
<p><sup>*Technically, Python doesn't coerce from <code>bool</code> to <code>int</code>, rather in Python <code>bool</code> is a subtype of <code>int</code> and the <a href="https://en.wikipedia.org/wiki/Liskov_substitution_principle" rel="noreferrer">Liskov substitution principle</a> applies. But I'll say &quot;coercion&quot; for the sake of brevity and language-agnosticism.</sup></p>

CC BY-SA 4.0
2023-11-20T23:33:45.973Z
2023-11-20T23:33:45.973Z
kaya3
# What are the drawbacks of allowing implicit boolean/integer conversions?
Posted by: username_0 on 2023-11-20
Some languages (C, C++, JavaScript, Python) allow one to use integers as booleans and vice versa:
int x;
if (x) // Equivalent to: x != 0
    y();

Or:
int x = 10 + (y > 10); // Equivalent to: y > 10 ? 11 : 10

However, other languages such as Java, C#, and Swift disallow this. They do not even allow explicit casting and force users to explicitly write != 0 and ? 1 : 0 to cast from integer to boolean or boolean to integer respectively.
What is the rationale for disallowing this? Allowing integers and booleans to freely convert allows certain logic to be expressed much more concisely, such as that to determine if exactly N conditions are true. So what are the drawbacks?
**Tags:** numbers integers booleans
> **Comments:**
> **username_1**: This sort of implicit conversion would probably remove the ability to do nullability checks on nullable types. In typescript it saves a lot of space when checking if something is null or undefined to have a check like 'if (!someNullableInt) ...' that checks if the value has been set. It would have to be replaced with a full check like 'if (someNullableInt === null) ...'. I think C# or VB might have the same kind of check.  
> **username_2**: Note that Python does not have bool/integer *conversions*. Booleans *values* are integers - namely 0 and 1 of an integer subtype. This is separate from *general* values - incidentally, including integers - having boolean *meaning* such as empty lists being falsy and non-empty lists being truthy. The two are separate mechanisms each with their own drawbacks.  
> **username_3**: It may not be clear which of 0 and 1 is true and which is false. E.g., the return code of  a successful command or system call is traditionally 0 and that of an unsuccessful command is nonzero (with different values hinting to different reasons of failure). Nevertheless, one would rather associate true with success and false with failure. And even if one knows about this logic quirk, it is much safer to write `if (something() == ERROR_SUCCESS)` instead of `if (!something())`  
---
## 10 answers
### Answer by username_14 on 2023-11-20. Score: 24 | Accepted answer
There is a particular drawback of allowing implicit conversions (aka coercions*) from bool to int in dynamic languages such as Python, where many other types have coercions to bool. Coercions are generally not transitive, meaning that e.g. allowing coercion from list to bool and coercion from bool to int, does not imply that there is a coercion from list to int, let alone that this coercion would be consistent with the composition of the other two.
So consider code like this:
def exactly_two(x, y, z):
    return x + y + z == 2

The exactly_two function uses bool-to-int coercion to test whether exactly two of the conditions are true. However, this means it relies on the arguments being bool values; yet in most places where a condition is tested, the condition is allowed to be some other type which coerces to bool. Consider:
a, b, c = [1, 2, 3], [], [4, 5]
print(exactly_two(a, b, c))

The desired behaviour of the above program is to print "True", since exactly two of the given lists are truthy (non-empty). However this program actually prints "False", since x + y + z is a sum of lists, not a sum of Booleans coerced to integers.
This can get even messier when the coercion from int to bool is also considered:
p, q, r = 2, 3, 0
print(exactly_two(p or q, p and r, q and r))

In Boolean logic, the above program should print "False" since only the condition p or q is true. However, in Python the condition 2 or 3 doesn't evaluate as True, it evaluates as 2. Then the condition x + y + z is 2 + 0 + 0, and hence the program prints "True".

*Technically, Python doesn't coerce from bool to int, rather in Python bool is a subtype of int and the Liskov substitution principle applies. But I'll say "coercion" for the sake of brevity and language-agnosticism.
---
### Answer by username_5 on 2023-11-20. Score: 30
The main drawback of allowing implicit boolean/integer conversions is, it makes it impossible to prevent errors that result from confusion of a boolean and an integer.

Next time you confuse the order of the arguments to a function that takes an integer and a boolean, instead of getting a nice error message that points out what you did wrong, it will compile and do something unexpected.

It is a fairly important drawback. If the conversion is infrequently used, forcing the user to be explicit is a good thing. Besides, `!= 0` and `? 1 : 0` are not that long to write.
> **Comments:**
> **username_6** (2023-11-21): You don't even need `? 1 : 0` for converting boolean to integer, you can have an _explicit_ conversion syntax such as `int(b)` or `b as int`.  
> **username_7** (2023-11-21): Treating ints like booleans made sense in C, which didn't originally _have_ a separate boolean type — you _always_ used ints, with 0 meaning false and non-zero true.  (And IIRC, when a boolean keyword was first added, it was effectively just a synonym for int anyway.)  In that case, it made sense for conditions to accept an int.  But, as you say, that has very significant drawbacks.  Strongly-typed languages with a separate boolean type don't _need_ to treat ints as booleans — the benefits of doing so are minimal.  (As you show, it's easy to convert, though IME you hardly ever need to.)  
> **username_7** (2023-11-21): @MatthieuM. (That depends upon the language.)  
> **username_6** (2023-11-21): @gidds: I'm not talking about _any_ language in particular, I'm talking about _language design_. When designing a language, you can introduce a more specialized syntax than `? 1 : 0` to convert from boolean to integer.  
> **username_8** (2023-11-21): A nice Python idiom (mentioned in the link in the question) that is based on this implicit conversion is of `sum(booleans)` to count how many True values there are in a boolean collection. It's of course possible to also do this more explicitly with something like `sum(map(int, booleans))`, but I do feel something would be lost in expressiveness if this implicit conversion was absent.  
> **username_7** (2023-11-21): @MatthieuM. Indeed — but some languages don't have explicit boolean-to-int casts/conversions, just as some don't have conditional expressions (as opposed to statements).  (And even those that do don't always agree — some languages use -1 for true instead of 1, and others use 0 for true and non-zero for false.)  Of course, if you're designing a new language, you're free to choose — but why not choose to have a proper boolean type, and avoid all the complications and bug possibilities that come from entangling it with integers at all?  
> **username_6** (2023-11-22): @gidds: I never said anything about existing languages, so I don't understand your rant. And as for your question, explicit conversion is precisely about converting between two proper types... so, we're in agreement?  
> **username_9** (2023-11-22): @yoniLavi Actually in python it would probably be much safer to do `sum(map(bool, booleans))` than `sum(map(int, booleans))` to avoid unexpected behaviours in the case where some of the "booleans" turns out not to be of type bool. See kaya3 's answer for fun examples.  
> **username_10** (2023-11-22): @MatthieuM. Rust satisfies your request! It requires an explicit cast from bool to int! e.g. `false as u32` --> `0u32`, `true as i8` --> `1i8`.  
> **username_6** (2023-11-22): @Nayuki: Yes, I know. Once again, I'm not looking for an existing language so much as discussing ways to have ergonomic explicit conversions in general.  
> **username_8** (2023-11-23): Thanks @Stef, yes, absolutely agreed. But my point is just the fact that being able to add up booleans is expressively pleasing. Also, a common sub-idiom of this would be of using a generator expression, whereby I know all elements are bools, e.g.: `sum(word.endswith("s") for word in words)`  
> **username_11** (2023-12-05): While `cond ? 1 : 0` isn't that long to write, I've gotten annoyed at having to write `CASE WHEN cond THEN 1 ELSE 0 END` in SQL dialects without implicit Boolean/integer conversions.  
---
### Answer by username_4 on 2023-11-21. Score: 9
Booleans may not just be 1 or 0
Much of this depends on the underlying representation of the value.  My particular experience of this is with C.
Before C99, there was no boolean type, only integers treated as booleans.  Boolean data of course can only be 0 or 1; but an integer type can clearly have more states.  Consider the code
if (x == TRUE)
    do_something();

do_another_thing();

if (x == FALSE)
    do_something_else();

Clearly if x is boolean then one or other function should be called.  But if x (as an integer) has been set to 2 for example, then neither function will be called!  For that reason, coding standards often required the form
if (x)
    do_something();

do_another_thing();

if (!x)
    do_something_else();

so that all non-zero values would be covered by the first case.  (I should say here that this is not just a theoretical issue.  I have personally seen this bug happen, and it was really hard to find!)
C99 solved this particular problem by adding a bool type, where if (x == TRUE) succeeds for any non-zero value of x.  However you can still go wrong with this.  Most notably, your "efficient" method of summing bools to find how many values are set true is going to fail badly if any are stored as integer values greater than 1.
More interestingly still, you can't even quantify how badly that method will fail.  C merely requires bool to have at least 2 states, and the compiler is perfectly free to store this in a single bit, a byte, or a 32-bit word.  I can point you to compilers/hardware which would give you all of these cases.  I've personally stumbled over a bug where two different processors accessing shared memory represented bool as a byte on one side and a 32-bit word on the other, so I actually had to replace the "better" bool definitions in the shared memory structures with fixed-size integers which both sides could agree on.
This is all somewhat specific to C, of course, but the principles apply to most languages.  Ultimately your boolean value needs to be stored somewhere, and if execution speed is an issue then your language may well use a single word per boolean value so that your code runs faster.  Of course this may not be as applicable to interpreted languages such as Python, where the language is already slow enough that a small extra delay is not significant.
A class of bugs can be eliminated
Bugs happen, let's be real about that.  One sign of clearly-written code is that it can be easier to find bugs when they happen.  And one sign of a language that helps you is where a class of bugs can be eliminated by a language feature.
If you got the wrong variable in your if (x) check (and hands up any coder who hasn't? no hands? good, we're all in the real world here) then you've got a bug.  If you accidentally use the name of another boolean variable then your code will build, and it will misbehave, but at least it will misbehave in a predictable, repeatable way.
If you accidentally use the name of an integer variable though, with a language which gives you implicit conversions, all the issues above could come out of the woodwork.  If your language gives you an implicit zero/non-zero comparison then at least some of those problems go away, but reproducing it is likely to be hard.  If your language stops these bugs at compile time, an entire class of bugs will simply go away.  This is generally a good thing (assuming you can potentially handle a bit of inefficiency in the code anyway).
---
### Answer by username_10 on 2023-11-22. Score: 8
In addition to all the other fine answers, Boolean coercions are not consistent across languages:

* Zero (`0`) is considered falsy in Python and JavaScript, but truthy in Ruby.
* The empty array (`[]`) is considered falsy in Python, but truthy in JavaScript and Ruby.
* Not-a-number (`NaN`) is considered falsy in JavaScript, but truthy in Python and Ruby.

Note that the only two falsy values in Ruby are `false` and `nil`. That means everything else is truthy. Python and JavaScript have longer lists of falsy and truthy values. Python and C++ allow operator overloading to define custom coercions to `bool`.

I personally agree with the strict, explicit approach to Booleans that is enforced by Java, C#, and Rust.
> **Comments:**
> **username_16** (2023-11-23): Just for fun you should add POSIX shell or Bash to your list.  
> **username_4** (2023-11-23): As an embedded engineer mostly working with C and C++, that's a brilliant point I hadn't even thought of. And a good prompt to me to learn some more languages. :)  
---
### Answer by username_12 on 2023-11-22. Score: 6
One particularly bad issue with int to bool conversions is that if you have an expression based language, the assignment `x=7` will typically return `7`. This makes `if x=7` valid syntax, which is really bad since this is a common typo for `if x==7`.
> **Comments:**
> **username_13** (2023-11-22): Some people might argue that things like `if (errCode = tryDoingSomething()) { handleError(errCode); }` make this a good feature, and equality checks should be written flipped like `if (7==x)` to avoid the bug possibility. I wouldn't necessarily agree with them.  
> **username_14** (2023-11-22): @leftaroundabout That use-case is still allowed as `if((errCode = tryThing()) != 0) ...`, and is more explicit that way. If I saw the code without `!= 0` I would have to think about it because it looks so much like a mistake.  
> **username_13** (2023-11-22): @kaya3 I like neither of these, would prefer `case tryThing() of { Ok -> ... ; Failure errCode -> ... }`.  
---
### Answer by username_15 on 2023-11-21. Score: 5
There are some common errors that result from integer to boolean conversions.

One of the most common among C beginners is the `strcmp()` function. As a comparison function, it's easy to assume that it returns a boolean, with the truthy value meaning the strings are equal. But it's actually tri-valued: negative and positive for unequal (indicating whether one string is lexicographically lower or higher), and zero (C's falsey value) meaning equal.

Another class of functions with a similar problem is functions that search a string or array and return the index of a match. Since most languages use zero-based indexes, `0` is a valid index of a successful search, and some other value must be returned to indicate failure. JavaScript returns `-1`; PHP returns `false` (you must use the strict comparison operator to avoid automatic coercion that makes `0 == false`); Python returns `-1` from some functions and raises an exception from others. But again, it's a common mistake to treat the searching function as boolean.
---
### Answer by username_17 on 2023-11-24. Score: 1
There might not be a sensible, unambiguously correct conversion
The popular Numpy third-party library for Python provides a clear case study for this possibility. Because Python is dynamically typed, it is forced to accept code that would invoke an implicit conversion. Early on, the language implementers chose to allow such conversions to be attempted, and specified that types could define this conversion using the __bool__ "magic method".
This is a trade-off made for pragmatic reasons; in many other places, Python refuses implicit conversions and remains fairly strongly typed (for example, it does not allow concatenating an integer to a string with the semantics of implicitly using a string representation of the integer). In the case of conditional logic, the Python implementers apparently felt that requiring conversions all the time to avoid exceptions would be too tedious. However, the Numpy implementers found a need to refuse this convenience.
Numpy defines an array type that provides a bunch of operator overloads that implicitly "broadcast" operations - comparing two identically-shaped arrays element-wise, or repeating the comparison along one or more axes if the array shapes are "compatible".
In particular, for two arrays a and b of the same shape, the == operator (via overloaded __eq__ method) will compare each pair of corresponding elements, and return a new array of booleans of the same shape with the comparison results in the corresponding places:
>>> import numpy as np
>>> a = np.ones((3,3))
>>> b = np.ones((3,3))
>>> a[:,1] = 0
>>> b[1,:] = 0
>>> a
array([[1., 0., 1.],
       [1., 0., 1.],
       [1., 0., 1.]])
>>> b
array([[1., 1., 1.],
       [0., 0., 0.],
       [1., 1., 1.]])
>>> a == b
array([[ True, False,  True],
       [False,  True, False],
       [ True, False,  True]])

This sort of functionality is considered very useful, and a huge part of the reason why Python enjoys the popularity it does today with data scientists.
So the next question is, what should we expect to happen for if a == b:, or in a conditional expression like 'y' if a == b else 'n'?
Python has built-in fallback logic for comparisons - normally, everything that isn't explicitly falsy via an overloaded __bool__, is truthy (via object.__bool__). However, Numpy explicitly overloads __bool__ for arrays to raise an exception unless the array has exactly one element. (It used to consider zero-element arrays falsy, but current versions also raise an exception here.)
Why?
This is in accordance with the Zen of Python: "In the face of ambiguity, refuse the temptation to guess".
Think about it: if a == b: comparing two Numpy arrays, presumably, probably meant to check whether every corresponding pair of elements is equal. But the result of a == b is just an array of boolean values. Meanwhile, if c:, where c was an already existing array of boolean values, probably means to check whether any element is True. There is no way for the __bool__ operator overload to know which was meant, because it does not have access to the AST.
Moreover, such logic is often wrong-headed anyway. Commonly, people want the code inside the block to describe work to do with a single pair of elements, and the code author wants that calculation to be broadcast - but Numpy simply cannot work this way. There definitely isn't any operator to overload, because if is a statement rather than an expression. But even the conditional expression form doesn't work, and Numpy couldn't make it work if they wanted to. One might think that 'y' if a == b else 'n' ought to produce an array of strings, but even if it could work, this would be deeply magical and many Pythonistas would complain about it being complex and surprising. (Even using the x if y else z conditional expression is not universally accepted; but it would be especially hard to accept that the result might be neither x nor z!)
Instead, that job requires a different tool, such as numpy.where, or using the a == b result as a mask for another array, etc.
See also the corresponding canonical on Stack Overflow about the error message generated by the attempted implicit conversion - especially my answer there.
---
### Answer by username_18 on 2023-11-21. Score: 0
Many of the advantages associated with allowing implicit conversion could be achieved by instead providing convenient means of handling the scenarios where such conversions would be most useful.  If one wants to branch if foo and bar have any bits in common, being able to write an expression where foo and bar are the only things that look like values, e.g. if (foo & bar) is nicer than having to do something like if ((foo & bar) != 0).  If, however, there were an operator which would accept two integers and return a Boolean, that would make intent even clearer than the form using implicit integer-to-Boolean conversion.
Additionally, if a language had an operator that behaves like Javascript's && operator, yielding the second operand's value when the first is "truthy", then an expression like (a==b) | ((x==y)*2) could be written as ((a==b) && 1) + ((x==y) && 2).  I'm not sure && would be the best choice for that operator, but having an operator with such semantics would accommodate the second most common use case for implicit Boolean/integer conversions.
An as-yet unmentioned downside to opening up arbitrary integer-to-Boolean conversions in languages which support bit fields, the semantics of Boolean bitfields would differ from those of other types.  For example, given:
struct foo {unsigned char bit:1; _Bool boo:1;} it;
void test(int value)
{
  it.bit=value;
  it.boo = value;
}

invoking test(2) would set it.bit to zero but it.boo to 1.
> **Comments:**
> **username_14** (2023-11-21): I'm not sure how your proposed `&&` operator works when the first operand is false. Presumably it needs to evaluate to 0?  
> **username_18** (2023-11-21): @kaya3: It would evaluate to a zero of the second operand's type.  Shorthand for `x ? y : 0`.  
> **username_13** (2023-11-22): I don't see what's wrong with `if ((foo & bar) != 0)`. Very few extra characters in exchange for substantially better understandable code, without needing any special definitions. In fact I'd be tempted to write it like `if ((foo & bar) != 0x0000)`.  
> **username_18** (2023-11-22): @leftaroundabout: In many cases, the intended semantics would check whether some subset of the bits in a value match a pattern--equivalent to `if (((value ^ pattern) & mask) != 0)`, but if the pattern bits are all zero, `^pattern` can be omitted.  This construct only works if the right hand side of the `!=` is zero, but writing out the `0` in source code suggests that some other value could be substituted.  
> **username_18** (2023-11-22): @leftaroundabout: If a langue had types for values that could be used like integers or read-only bitfields, then a construct like `if (WIDGET->CONTROL & WIDGET_CONTROL_FNORBLE_MASK)` or `if ((WIDGET->CONTROL & WIDGET_CONTROL_FNORBLE_MASK) != 0)` could sensibly be replaced by `if (WIDGET.CONTROL.FNORBLE)` [for a one-bit field] or  `if (WIDGET.CONTROL.FNORBLE != 0)` [for a multi-bit field], but I've not seen any language that would facilitate such constructs.  
> **username_13** (2023-11-23): Well, conceptually what we're dealing with here are sets, then the special case is just an element lookup `if (fnorble∈control)`, or `if (widget.control.contains(FNORBLE))`, and the general case is `if (isEmpty(foo∩bar))` or `if (foo.intersect(bar).empty())`. Of course a typical set data type is much slower than bitmasks, but you could have a type parameterised by a type-level list that has an interface like a set but is under the hood just an integer where each bit denotes an element. It's not too difficult to code this up in Haskell, and should also be possible in modern C++.  
> **username_18** (2023-11-23): @leftaroundabout: Yeah, it's possible to implement such things in C++, and I've actually done it when writing an emulation wrapper that could process PIC C code as a Windows application with simulated I/O, but if one doesn't have such facilities being able to use bitmasks conveniently without having to test an intersection against zero would be nicer than not being able to do so.  
> **username_19** (2023-11-23): @supercat, If I got that right, I would write it as `if ((value & mask) != pattern)`  
> **username_18** (2023-11-23): The `(value ^ pattern) & mask` pattern will handle cases like testing if all any the specified 4-bit fields in a word hold something other than 0x0B via `if ((value ^ 0xBBBBBBBB) & mask)`, without having to adjust the pattern according to the mask.  One could use `if ((value & mask) != (0xBBBBBBBB & mask))`, but that would violate the "don't repeat yourself" principle even if a compiler was able to optimize it to the faster sequence of operations using xor.  
---
### Answer by username_20 on 2023-11-21. Score: -1
If `int` implicitly converts to boolean I can't write `x ?: 3` where `x` is `maybe`, and `?:` is null coalesce operator. This ends up being ambiguous between coalesce null to 3 and coalesce 0 to 3. (GCC has the latter operator: 0 ?: 3 does in fact produce 3. The operator is more useful when the left side is a pointer.)

If you make the choice `maybe -> bool`, you then have to choose between 0 is kept or coalesced. If you choose coalesced, your type system ultimately requires backtracking to determine the type of a chained coalesce (`maybe ?: a : b` is hard to find the type of if b is a ternary). If you choose kept, you then have to decide what `maybe(0) ? a : b` does. If you choose a, you end up with a big difference between `maybe` and `int` such that the program becomes hard to read if you have the `var`/`auto` mechanism for getting type of variable from its right side (which is typically a function call return); and if you choose b, you have a behavior difference between coalesce and ternary.

If `T[]` (array) collapses to `bool`; it's ambiguous between `maybe<[]>` and `{}` (empty array); empty array collapsing to `bool` as false always bugged me for this very reason, but collapsing to `bool` as true is totally unexpected. (Yes I really did mean to write collapse as this converts a vector to a scalar.)

You really don't want `maybe` converting to `bool`; bug rats nest. If you think you need it, consider allowing `if(maybe)` to be valid as-is; that is `if`, `while`, and `for` take `maybe` directly. This will, however, make for a small headache if you also have `maybe` converting to bool as the standard way to check if a `maybe` has a value, which will typically exist in languages that do implicit conversions to bool.
> **Comments:**
> **username_2** (2023-11-23): I'm having trouble following the reasoning here. In languages I am familiar with, if we have something like `maybe<int>` then a null coalesce operator will be sensitive to a `None`/`Null`/`maybe:None` value *that is separate from boolean `false`*. Can you clarify why you assume conversion `int` -> `bool` also implies conversion `maybe<int>` -> `bool`? Are you confusing conversion to bool with conversion to null/undef/...? Perhaps clarifying by which language's semantics you are reasoning here would be helpful for making the answer easier to follow.  
> **username_20** (2023-11-23): @MisterMiyagi: I filled in a whole bunch of reasoning. Ultimately this is hard to understand because it's a case of something has to be surprising but the language designer can choose which thing is surprising.  
> **username_21** (2023-12-03): Swift had a similar problem. They allowed optionals in an if, treating nil as false and not nil as true. Then someone realised that an optional bool that is false behaved differently from a non-optional bool that is false. That feature was removed.  
---
### Answer by username_21 on 2023-12-03. Score: -2
The reason to not allow it is that booleans are not numbers. Just like pointers are neither numbers nor booleans. So without 50 years of prejudice from C programming, there is no sane reason why a cast, either implicit or explicit should be allowed.
> **Comments:**
> **username_14** (2023-12-03): The question asks what the drawbacks are; you have not proposed any drawbacks. This answer is really just a philosophical opinion.  
> **username_21** (2023-12-07): The obvious drawback is confusion between two incompatible concepts.  
---
