# From<bool> for primitive integer types

Hi all,

It has probably already been discussed somewhere but I can’t find anything on this forum nor on google.

Is there any reason why `From<bool>` is not implemented for all integer types (signed & unsigned) ?

Kind regards

2 Likes

It’s lossless and works through `as`, so having it in `From` sure sounds reasonable to me.

Maybe just make a PR and see what libs says?

2 Likes

Indeed, I’m already preparing it

4 Likes

Sounds right, since wider integer types already implement `From<narrower_integer_type>` too.

I was trying to find a counterargument; `bool` isn’t exactly an integer type, semantically speaking, so how can one canonically map true and false to integers, except by convention (false = 0, true = 1).

However, I failed to convince myself that any other mapping would do because of the ring isomorphism to u1: addition = XOR and multiplication = AND. So there’s only one mapping that makes sense, and that mapping is lossless, plus calling `.into()`, is explicit. I’m out of arguments. Do it.

3 Likes

There are three potential mappings: true/false => 1/0, 0/1, -1/0. Four if you count 1/0/FileNotFound.

Conceptual shortcuts make it easier to make conceptual mistakes.

1 Like

@DanielKeep: As @GolDDranks points out, only two of those are consistent with the fact that `|` and `&` work on `bool` as a 1-bit number: 1/0 or -1/0.

But it’s all academic anyway, since the `as` operator already defines the meaning of the conversion.

But `as` defines narrowing conversions, so by that logic, `From<u64> for u8` should also be implemented. I’m not saying `From<bool> for {integer}` should disagree with `as`; I don’t think `bool as {integer}` is a particularly good conversion in the first place, so I don’t think it makes the best argument for defining a `From` implementation in this case.

3 Likes

I’m not sure about this. Bool isn’t a regular number. It has meaning beyond `u1`, so this conversion could hide bugs, e.g. if you thought a function returns a value, but it only reports success:

``````let bytes_written: u64 = write(stuff).into();
``````
1 Like

Then should’nt this API use a `Result<(), ()>` rather than a boolean ?

It should, but not all APIs are like that. Also Result is noisy and may be annoying for calls where it’s not critical to check (eg write to stderr was such case, eprintln doesn’t report now)

My initial incentive for that question is because we often have to extract bits from integer while working on embedded targets. Writing generic for becomes tedious when a function should insert/extract from a register the in the same way for all fields.

It can be worked around with a newtype :

``````use std::convert::From;
use std::convert::Into;

struct MyBool(bool);
impl From<bool> for MyBool {
fn from(v: bool) -> MyBool {
MyBool(v)
}
}
impl Into<u32> for MyBool {
fn into(self) -> u32 {
self.0 as u32
}
}

fn do_something<T>(v: T) where T: Into<u32> {
let u: u32 = v.into();
println!("{}", u);
}

fn main() {
do_something(MyBool::from(true));
}
``````

But I don’t find it really elegant.

Note that Python, which is considered to be a strongly-typed dynamically typed language, bool is, in fact, a number:

``````>>> import numbers
>>> isinstance(True, numbers.Number)
True
>>> True + True
2
>>>
``````

I don't think that this causes any problems, and can be sometimes useful.

Which is why I explicitly also said "It's lossless", so no, it's not "by that logic".

1 Like

Why not just: `do_something(true as u32);`? It's not bad that `as` is used for non-obvious primitive conversions.

Wow. That's quite the contrast from theory, given that boolean algebra has 1+1=1 since + acts as the OR operator.

It is an example where you cannot assume what type will be used internally by `do_something`.

And this does not compile :

``````fn do_something<T>(v: T) {
println!("{}", v as u32);
}

fn main() {
do_something(true);
}
``````

Sorry, the actual point I failed to emphasize was that if you have a function with generic type `T: Into<u64>`, you can just pass in a `u64`, as the conversion is trivial to write caller-side (`b as u64`). The use of `as` is almost beside the point, but it's easier to defend in this case since the conversion is not lossy. A clearer alternative might be to make a more descriptive helper method or inline its trivial implementation:

``````fn one_if_true(b: bool): u64 { if b {1} else {0} }
...
do_something(one_if_true(true));
do_something(if b {1} else {0});
``````

Generally, an implementation of `Into` is useful when the intended conversion is obvious (and especially so if its implementation is non-trivial). I agree with @DanielKeep's original comment: mathematically speaking, there's not an obvious canonical choice for conversion from `bool`, although some languages have settled on `false`/`true` -> `0`/`1`.

This example has no constraints on `T` at all, making `v` unusable within the body. My point is, if you have `T: Into<u64>` on the method, just pass in `u64` by doing an explicit conversion client-side as that's trivial for `bool`s given a choice of numbers for `true` and `false`.

If this can be of any help, this is the usecase that’s driving my reflection.

I have a macro that generates function that needs to convert between some types (that might be `bool`) to some primitive integer type. If you uncomment line 216 everything breaks simply because bool does not implement from and you cannot implemented it (trait & type defined in another crate).

2 Likes

Thanks, that makes your use-case (and the workaround strategy) clearer. Perhaps you are already aware of this solution, but in case you didn’t try it: you can work around the omission of `From<bool> for u32` by adding an extension trait as follows.

``````trait IntoU32 {
into_u32(&self): u32;
}

impl<T: Into<u32>> IntoU32 for T {
into_u32(&self): u32 { self.into() };
}

impl IntoU32 for bool {
into_u32(&self): u32 { self as u32 };
}
``````

and using `into_u32()` instead of `into()` everywhere. Since `IntoU32` is local to your crate, it has the semantics that make most sense for your specific crate for `bool -> u32` conversion.

1 Like