# Adding boolean ops to predicate functions in std

**URL:** <https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266>\
**Category:** libs\
**Created:** [May 1, 2020, 2:05pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266 "2020-05-01T14:05:11Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 2:05pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/1 "2020-05-01T14:05:12Z")

</div>

Assuming `type Predicate<T> = FnMut(&T) -> bool` would the following be a useful addition to the standard library and would it require an RFC?

```rust
impl<T> Predicate<T> for bool

impl<T> BitOr/BitAnd<Predicate<T>> for Predicate<T> {
   type Output = Self
}

impl<T> Not for Predicate<T> {
  type Output = Self
}

```

This would enable the following:

```rust
struct Foo {}
impl Foo {
   fn conditional_constructor(p: Predicate<Self>) -> Option<Self>
   fn is_red(&self) -> bool 
   fn is_blue(&self) -> bool
}

fn main() {
  std::iter::once(Foo::conditional_constructor(true)).filter(!(Foo::is_red | Foo::is_blue));
}

```

I.e. there would be a canonical shorthand for always-true or always-false predicates which are non-closure types. This may come in handy for specialization, saves a few keystrokes and may make it more acceptable to not provide unconditional variants of functions that normally take a predicate. And it would provide a way to compose function references the same way one can compose their results in boolean expressions. The ability to negate predicates would also reduce the need to add functions in pairs such as `reject`/`retain`

One wart there is that it would use `|` instead of `||` since the latter does not support overloading.

prior discussions and attempts:

> <https://github.com/rust-lang/rust/issues/65669#issuecomment-545102403>
>
> This method will act as filter with complement of provided predicate.
> If function defined as is\_something(&value) -\> bool {...} (which is a...

> <https://github.com/rust-lang/rust/pull/68332>

---

<div class="post-metadata">

**Author:** ![matklad](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/matklad/32/12266_2.png) [@matklad](https://internals.rust-lang.org/u/matklad)\
**Post date:** [May 1, 2020, 2:30pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/2 "2020-05-01T14:30:56Z")

</div>

That's an interesting API, but probably too niche and magical for the standard library. When I needed this for a DSL, I've used essentially a `struct Predicate<F: FnMut(&T) -> bool>(F)` wrapper and impled bit ops for it. ([source](https://github.com/nix-community/nixpkgs-fmt/blob/260e3c566c33e1910ccb0823d97167eb0a850c4e/src/pattern.rs))

Another wrinkle here is that at the moment you won't actually be able to spell the `type Output` bit without dynamic dispatch. The unboxed output would be a closure type, and those are unnameable. `type Output = Box<dyn FnMut(&T) -> bool>` would work, but it imposes allocation where it, strictly speaking, not necessary.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 2:48pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/3 "2020-05-01T14:48:29Z")

</div>

> [@matklad](#):
>
> The unboxed output would be a closure type

I think it could be implemented as a named struct carrying the two input predicates, if the `type_alias_impl_trait` feature were stable the associated type could also be specified via `impl Trait`

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [May 1, 2020, 6:14pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/4 "2020-05-01T18:14:14Z")

</div>

> [@the8472](#):
>
> may make it more acceptable to not provide unconditional variants of functions that normally take a predicate

Can you elaborate why this is a problem? `|_| true` is a ZST, and inlining/folding ought to remove all conditionals involved...

In fact, passing `true` could even be _worse_, as it's not a ZST. And because it's a `bool`, it wouldn't necessarily fold away either, since it can't know _from the type_ whether it's `true` or `false`.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 6:31pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/5 "2020-05-01T18:31:47Z")

</div>

> [@scottmcm](#):
>
> Can you elaborate why this is a problem? `|_| true` is a ZST, and inlining/folding ought to remove all conditionals involved...

It's more of a visual clutter thing, I suspect people may balk at requiring users to pass `|_| true` to methods and thus, in absence of overloading, add a 2nd method without it. Having `true` and `false` as canonical values would look cleaner and be less of a papercut when writing a call to such a function.

> [@scottmcm](#):
>
> In fact, passing `true` could even be _worse_ , as it's not a ZST. And because it's a `bool` , it wouldn't necessarily fold away either, since it can't know _from the type_ whether it's `true` or `false` .

The `impl<T> FnMut(&T) -> bool for bool` could be const and `#[inline]`. And thus fold to `self` (the boolean) at call sites, it would enjoy the same optimizations while having to instantiate fewer closures (one per type instead of one per call).

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [May 1, 2020, 7:26pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/6 "2020-05-01T19:26:24Z")

</div>

This can be done as a library, so it's best to keep it out of `std` until it's proven itself (something like [this](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=f87ad41b6a45ee4a7021fc1bdecfeedd))

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 7:42pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/7 "2020-05-01T19:42:11Z")

</div>

It's supposed to work for any method that takes `FnMut(&T) -> bool`

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [May 1, 2020, 7:46pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/8 "2020-05-01T19:46:52Z")

</div>

Yes, mine works with all `Fn(&T) -> bool` (with the tiny added wrinkle that you need to call `into_pred`). You can't get around this wrinkle and add operators, Rust's trait system won't allow it. If you don't need to use the operators, you can just pass the closure and not call `into_pred`. If you want `FnMut`, just change `Predicate::test`'s signature from `&self` to `&mut self`, and `Fn` to `FnMut`. Not a big change.

My point stands that this is easily done as a library, so it should be prototyped outside of std and get some usage before being folded in.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 7:55pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/9 "2020-05-01T19:55:19Z")

</div>

The aim is to streamline syntax. If it's an external crate and you need to add `.into_pred()` would anyone go through the effort of using it? After all you can always use the closure approach instead.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [May 1, 2020, 8:06pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/10 "2020-05-01T20:06:23Z")

</div>

I think it would be better to figure out how the api is designed before worrying about streamlining it. What works for other languages may not work for Rust, so you will have to figure out what api you require. Note: Rust will never add operator for all `F: Fn(&T) -> bool`, because the plan is to allow user defined implementations for `Fn*` operators. So you will need to rethink how this will operate anways.

On top of this, Rust likes to keep it's std as minimal as possible. There are some warts here and there, but let's not bloat things too fast. If this is really useful to a large number of people, then it could be added to std, but that's unlikely given that even something like random numbers or serialization are not in `std`, and they probably have more usecases than predicates.

There are a number of ways to streamline my design, try to figure some out and improve on my design. I really didn't put much thought into it, I largely based it off the `Iterator` trait, so you can look there for ideas.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 8:13pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/11 "2020-05-01T20:13:11Z")

</div>

> [@RustyYato](#):
>
> Note: Rust will never add operator for all `F: Fn(&T) -> bool`

Can you elaborate? Considering this is central to the bitops part of what I am proposing.

Also note that your comment says nothing about the other aspect, specifically implementing it for the values of `true` and `false`, which only std can do.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [May 1, 2020, 8:14pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/12 "2020-05-01T20:14:38Z")

</div>

Rust will never add the impl

```rust
impl<F: FnMut(&T) -> bool, T: ?Sized> BitAnd<Anything> for F { ... }

```

Because

1. It's ill-formed, you can't have a free `T` generic parameter
2. It would prevent library code from implementing `FnMut` and `BitAnd` on their own.

Similarly for all other operators.

> [@the8472](#):
>
> Also note that your comment says nothing about the other aspect, specifically implementing it for the values of `true` and `false` , which only std can do.

You can implement your own traits for external types. See `impl Predicate for bool` in my playground example

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [May 1, 2020, 8:20pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/13 "2020-05-01T20:20:25Z")

</div>

To add to @RustyYato's points, Rust is not intended to be a `std`-library-only language. Crate usage is expected as part of the development process. Rust has "forever" forward-compatibility guarantees for the language and for the `std` library, which preclude breaking changes, whereas crates can and do use SemVer to enable and manage breaking changes. Lastly, **nothing** gets in `std` without first having proved its correctness, its generality, and its usefulness to the community via the external crate route.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 8:29pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/14 "2020-05-01T20:29:12Z")

</div>

> [@Tom-Phinney](#):
>
> Lastly, **nothing** gets in `std` without first having proved its correctness, its generality, and its usefulness to the community via the external crate route.

That seems like a misrepresentation of reality. I have seen plenty of minor additions being made to libstd without referencing a crate implementing those changes beforehand.

---

<div class="post-metadata">

**Author:** ![the8472](https://avatars.discourse-cdn.com/v4/letter/t/0ea827/32.png) [@the8472](https://internals.rust-lang.org/u/the8472)\
**Post date:** [May 1, 2020, 8:40pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/15 "2020-05-01T20:40:01Z")

</div>

> [@RustyYato](#):
>
> It's ill-formed, you can't have a free `T` generic parameter

Ah, well, That pretty much puts a knife into it.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [May 1, 2020, 8:42pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/16 "2020-05-01T20:42:36Z")

</div>

After thinking about this a bit more (now that you got me to 🙂), I think you cold do something like this: [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=21e034672ee12735b67db0743c4fdd99), which honestly, isn't that bad. You'll have to start every predicate with `False | ` or `True & `, but after that nothing, you can just use functions!

edit: added missing `bool: IntoPredicate<_>` impl

If you want to develop this further, you can go ahead and take this code. I won't be working on it any more.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [May 1, 2020, 9:20pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/17 "2020-05-01T21:20:04Z")

</div>

> [@the8472](#):
>
> And thus fold to `self` (the boolean) at call sites

That's worse than `|_| true`, though, because if it's folding to a value not to a constant.

To be concrete, let's use [https://doc.rust-lang.org/std/iter/struct.Filter.html](https://doc.rust-lang.org/std/iter/struct.Filter.html).

`.filter(|_| true)` gives `Filter<I, AlwaysTrueClosure>`, which is the same size as `I`, and its `.next()` method compiles down to just `I::next()`.

`.filter(true)` (with this hypothetical `Fn` impl) gives `Filter<I, bool>`, which is at least one byte larger than `I`, and where's there's a test in the generated `.next()` method.

This could be solved by having `std::functions::True`, but I'd rather type `|_| true` than a name like that.

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [July 30, 2020, 9:20pm UTC](https://internals.rust-lang.org/t/adding-boolean-ops-to-predicate-functions-in-std/12266/18 "2020-07-30T21:20:05Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
