# \[Pre-RFC\] Boolean operators that don't return bool

**URL:** <https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684>\
**Category:** ideas (deprecated)\
**Created:** [March 5, 2015, 8:57am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684 "2015-03-05T08:57:21Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![ryanhiebert](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryanhiebert/32/313_2.png) [@ryanhiebert](https://internals.rust-lang.org/u/ryanhiebert)\
**Post date:** [March 5, 2015, 8:57am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/1 "2015-03-05T08:57:21Z")

</div>

Relevant discussion on the Rust subreddit: [http://www.reddit.com/r/rust/comments/2xu8rn/boolean\_operators\_to\_not\_return\_bools/](http://www.reddit.com/r/rust/comments/2xu8rn/boolean_operators_to_not_return_bools/)

**TL;DR** : I’d like to see the boolean operators currently defined by `Eq` and `Ord` be made available to return non-booleans. I think this includes all of `==`, `!=`, `<`, `<=`, `>`, `>=`. I would expect `Eq` and `Ord` to retain their current semantics, but I’m not sure if that is possible to do in a backward-compatible way.

* * *

In Python, the boolean operators can be overloaded to return any type. It’s more than a bit convoluted how it’s done, with ` __add__ ` and ` __radd__ `, etc to make it all work, but it makes some particularly nice-looking APIs. Take an example from usage of the _SQL Alchemy_ ORM:

```
MyModel.query.filter(MyModel.my_field < 42).first()

```

If Python enforced that `MyModel.my_field < 42` had to return a `bool`, this would not be possible. Of course, since Python doesn’t enforce _any_ return types, it doesn’t, but it’s clear that this polymorphism is desired in other operators, such as `+`, `-`, etc.

The way I envision using these operators is by creating traits for each of those operators (I don’t know that forcing them to be implemented together is strictly necessary in all cases). For the sake of discussion perhaps they could be called `Equal`, `NotEqual`, `Gt`, `Ge`, `Lt`, `Le`. If I had all my druthers, I might instead rename `Eq` to `Equiv`, and use `Eq` and `Ne` to match their method names, but I suspect that’s even less possible than the rest of this proposal.

Then I’d like to see `Eq` and `Ord` simply be one possible concrete abstraction over a usage pattern for these operators. I suspect that there are other legitimate reasons for wanting to overload these operators than just an ORM, though my reasoning includes only that use-case and my desire for having operators in general work the same across the board (like `std::ops`).

Because these are fundamental types and operators that I’m proposing changing, this may be too little too late and too close to 1.0, but I would be remiss to not bring it up for discussion.

---

<div class="post-metadata">

**Author:** ![DanielKeep](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/danielkeep/32/1332_2.png) [@DanielKeep](https://internals.rust-lang.org/u/DanielKeep)\
**Post date:** [March 5, 2015, 11:48am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/2 "2015-03-05T11:48:16Z")

</div>

I’m curious if there are _any_ use cases for this that wouldn’t be satisfied with an `ast!` macro.

Also, I’d be concerned that this would make _using_ these traits far more painful. For example, if something like `fn foo<T: Eq>(a: T, b: T) -> bool` would have to become `fn foo<T: Eq<Result=bool>>(a: T, b: T) -> bool`. Arithmetic traits are kind of a pain as it is because of this.

---

<div class="post-metadata">

**Author:** ![tomaka](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tomaka/32/2842_2.png) [@tomaka](https://internals.rust-lang.org/u/tomaka)\
**Post date:** [March 5, 2015, 4:40pm UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/3 "2015-03-05T16:40:29Z")

</div>

Huge -1

This is a system language, you need to know what your code is actually doing. If I write `==`, `+` or `*` I want to be sure that it executes the corresponding operation, and not produce some sort of marker or lazy evalution thing.

If you want to write something like `MyModel.query.filter(MyModel.my_field < 42)`, the right Rust tool is a macro: `my_model.query.filter(filter! { MyModel.my_field < 42 })`.

---

<div class="post-metadata">

**Author:** ![ryanhiebert](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryanhiebert/32/313_2.png) [@ryanhiebert](https://internals.rust-lang.org/u/ryanhiebert)\
**Post date:** [March 5, 2015, 5:35pm UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/4 "2015-03-05T17:35:24Z")

</div>

@DanielKeep: I’m not sure that there are any, because I’m not very familiar with an `ast!` macro (I need to find those docs).

I certainly get that the ergonomics of this kind of flexibility are annoying, but I have trouble understanding why all the other operators work this way, but not the ones that are defined by `Eq` and `Ord`. It seems to me that as much as possible operators should be implemented consistently, and this seems very inconsistent.

@tomaka: Are you then arguing that allowing the overrides we already do in `std::ops` is too much, because it allows that? I’m inclined to think not. Why should these operators be less overridable than the others?

I agree that it needs to be apparent what happens when you use an operator, but I think that applies equally well to any method or function call, and should be relegated to API design. While there are some libraries that bastardize some operators in Python, they are, in my opinion, used very judiciously by the popular libraries that do override them. I think that the way that SQL Alchemy overrides the `==` operator in Python is perfectly in line with its obvious semantics, it just allows those semantics to be captured and used elsewhere.

For many (most) types, the semantics of `Eq` and `Ord` are exactly what is needed. However, I think that it’s not _always_ exactly what is needed, and that the current operators are _surprisingly_ uncustomizable.

---

<div class="post-metadata">

**Author:** ![sinistersnare](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/sinistersnare/32/18_2.png) [@sinistersnare](https://internals.rust-lang.org/u/sinistersnare)\
**Post date:** [March 5, 2015, 9:41pm UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/5 "2015-03-05T21:41:55Z")

</div>

-1

better fit for macros. will read the whole rfc later, but i think that this type of change is a good idea.

---

<div class="post-metadata">

**Author:** ![DanielKeep](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/danielkeep/32/1332_2.png) [@DanielKeep](https://internals.rust-lang.org/u/DanielKeep)\
**Post date:** [March 6, 2015, 1:22am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/6 "2015-03-06T01:22:58Z")

</div>

> [@ryanhiebert](#):
>
> I'm not sure that there are any, because I'm not very familiar with an ast! macro (I need to find those docs).

It doesn't exist, but it _could_ be written. The idea is that `ast!(my_field < 42)` would be expanded, at compile-time, into a value that represents the expression.

> [@ryanhiebert](#):
>
> It seems to me that as much as possible operators should be implemented consistently, and this seems very inconsistent.

The thing is that arithmetic needs parameterised output to support things like matrix multiplication. Equality is _defined_ as producing a logical true/false result. It's less flexible, yes. I'm personally not convinced that the flexibility is really _worth_ it, assuming the creation of an `ast!` macro.

---

<div class="post-metadata">

**Author:** ![Cyberax](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/cyberax/32/8196_2.png) [@Cyberax](https://internals.rust-lang.org/u/Cyberax)\
**Post date:** [March 10, 2015, 1:29am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/7 "2015-03-10T01:29:05Z")

</div>

I’m quite familiar with LINQ and various other attempts to create a fluent interface for queries.

You really need to have operators that return special wrapped types. Going with ast! route you’ll lose typechecking pretty quickly. Additionally, you often have to perform “strange” actions with database values - a result of “a \< b” might be a database NULL.

Besides, with AST macros you’re going to lose autocomplete support in IDEs.

What _would_ work: simply replace “\<” with a special method “.lt”.

PS: macros should be abolished in general.

---

<div class="post-metadata">

**Author:** ![DanielKeep](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/danielkeep/32/1332_2.png) [@DanielKeep](https://internals.rust-lang.org/u/DanielKeep)\
**Post date:** [March 10, 2015, 6:28am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/8 "2015-03-10T06:28:32Z")

</div>

> [@Cyberax](#):
>
> What would work: simply replace "\<" with a special method ".lt".

So what you're saying is, you could have a macro that rewrites all the `a < b` expressions as `a.lt(b)`? _Sounds good to me!_😛

But seriously, typechecking is a good argument, but I still feel concerned that it would make using comparisons in generic code a massive PITA. I like definition-checked generics, but Rust is already uncomfortably close to the "too verbose to be worth it" line.

> [@Cyberax](#):
>
> macros should be abolished in general.

_Burn the heathen!_

---

<div class="post-metadata">

**Author:** ![ryanhiebert](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryanhiebert/32/313_2.png) [@ryanhiebert](https://internals.rust-lang.org/u/ryanhiebert)\
**Post date:** [March 15, 2015, 2:39am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/9 "2015-03-15T02:39:55Z")

</div>

### Macros

Macros for this work have a serious downside, as has already been noted: they are inherently _not_ part of the normal syntax of the language, and thus language tools won't understand them, only the compiler. This restriction is worked around for built-in macros, but it can't be eliminated in the general case. The restriction means that errors in the the syntax won't be normal syntax errors, they will be errors resolving the macro.

> [@Cyberax](#):
>
> macros should be abolished in general.

While that is impractical in general, I think that considering them a very last resort is wise. The language, without macros, should have sufficient expressiveness if at all possible. Macros are a powerful tool, but we must be careful to use it wisely. I'm not satisfied that this is a wise use of macros.

### Methods versus operators

Methods are the next best option if operators are not going to be able to happen. I don't think macros are as good an option. I think that methods aren't as clear, though, as using operators. Consider this example, which I would like to express a described calculation, including the associativity of the operands:

```
(MyModel.my_field < 13) == MyModel.my_field.lt(13)
(13 > MyModel.my_field) == 13.gt(MyModel.my_field)

```

The translations are straightforward, and not too ugly, but I think that operators express the idea in a more digestible, obvious way.

Operators more obviously vary based on their right operands. When I call a method, it usually makes sense to think of it as value based on doing an operation **_to_** the LHS. With operators, however, I think it's more typical to understand that an operator's result is based on the **_combination_** of the LHS and the RHS.

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [March 15, 2015, 3:10am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/10 "2015-03-15T03:10:28Z")

</div>

Just be Lispy and write `gt(13, MyModel.my_field)`. ;p

Edit to be more constructive: One big problem with C+±style operator overloading is that there is only a finite number of operators, and the resulting syntactic abuse (e.g. `<<` on streams) seriously hurts readability and sanity. Yet Haskell’s solution of allowing any special character sequence to become an operator is… well, its own type of nasty. Perhaps a compromise would be borrowing Haskell’s ability to say “foo `f` bar” for “f foo bar”.

Edit to be less constructive: Though honestly, macros are not that evil and if you’re worrying about the consequences of a language tool not understanding one tiny piece of your code, the fault probably lies in the (thus far hypothetical) language tool.

---

<div class="post-metadata">

**Author:** ![eddyb](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/eddyb/32/8411_2.png) [@eddyb](https://internals.rust-lang.org/u/eddyb)\
**Post date:** [March 15, 2015, 5:35pm UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/11 "2015-03-15T17:35:06Z")

</div>

Custom operators seem like something we would want, but absolute integer precedence values are not optimal.@zwarich seemed to know of a better way to handle precedence, but I didn’t look into it when he first mentioned it.

---

<div class="post-metadata">

**Author:** ![ryanhiebert](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ryanhiebert/32/313_2.png) [@ryanhiebert](https://internals.rust-lang.org/u/ryanhiebert)\
**Post date:** [March 15, 2015, 11:29pm UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/12 "2015-03-15T23:29:56Z")

</div>

> [@comex](#):
>
> Though honestly, macros are not that evil and if you're worrying about the consequences of a language tool not understanding one tiny piece of your code, the fault probably lies in the (thus far hypothetical) language tool

The problem is that a language tool cannot reasonably be _expected_ to understand macros. It would have to know as much as the compiler to do so, and expand the macros.

---

<div class="post-metadata">

**Author:** ![comex](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/comex/32/2587_2.png) [@comex](https://internals.rust-lang.org/u/comex)\
**Post date:** [March 16, 2015, 12:54am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/13 "2015-03-16T00:54:22Z")

</div>

Language tools _should_ know as much as the compiler, but nevertheless I expect them not to be especially helpful around macros. The point is that this should only be a small problem.

---

<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:** [March 25, 2019, 8:24am UTC](https://internals.rust-lang.org/t/pre-rfc-boolean-operators-that-dont-return-bool/1684/14 "2019-03-25T08:24:01Z")

</div>

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