# Why is float not comparable

**URL:** <https://forum.modular.com/t/why-is-float-not-comparable/1479>\
**Category:** Standard Library\
**Created:** [May 20, 2025, 10:52am UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479 "2025-05-20T10:52:14Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![jdp](https://avatars.discourse-cdn.com/v4/letter/j/c6cbf5/32.png) [@jdp](https://forum.modular.com/u/jdp)\
**Post date:** [May 20, 2025, 10:52am UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/1 "2025-05-20T10:52:14Z")

</div>

I’m trying to make a generic assertion function for 2 tuples

```mojo
def tuple_eq[T: Comparable & Copyable & Movable](a: Tuple[T, T], b: Tuple[T, T]) -> Bool:
    return a[0] == b[0] and a[1] == b[1]

```

when call it with a float64 parameter i get the error shown below.

 ![image](https://us1.discourse-cdn.com/flex001/uploads/modular/original/1X/c3c3a8fe25c35e1e79ef60e54c1c7d9a2adb44a8.png)

and when it fill the function with floats it works fine.

```mojo
def tuple_eqf(a: Tuple[Float64, Float64], b: Tuple[Float64, Float64]) -> Bool:
    return a[0] == b[0] and a[1] == b[1]

```

---

<div class="post-metadata">

**Author:** ![sora](https://avatars.discourse-cdn.com/v4/letter/s/ad7895/32.png) [@sora](https://forum.modular.com/u/sora)\
**Post date:** [May 20, 2025, 1:02pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/2 "2025-05-20T13:02:36Z")

</div>

Unfortunately, due to a limitation in our current type system, `SIMD` is not `Comparable`.

To put it simply, `SIMD. __op__ ` returns `SIMD[bool, width]` instead of `Bool`.

---

<div class="post-metadata">

**Author:** ![jdp](https://avatars.discourse-cdn.com/v4/letter/j/c6cbf5/32.png) [@jdp](https://forum.modular.com/u/jdp)\
**Post date:** [May 20, 2025, 8:42pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/3 "2025-05-20T20:42:53Z")

</div>

Why can i do `==` when i specify the types fully?

---

<div class="post-metadata">

**Author:** ![sora](https://avatars.discourse-cdn.com/v4/letter/s/ad7895/32.png) [@sora](https://forum.modular.com/u/sora)\
**Post date:** [May 20, 2025, 9:23pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/4 "2025-05-20T21:23:35Z")

</div>

The `Comparable` variant tries to find a ` __eq__ ` with signature `fn(T, T) -> Bool`, which `SIMD` doesn’t have. The `eqf` variant calls the ` __eq__ ` defined on `SIMD` itself.

---

<div class="post-metadata">

**Author:** ![jdp](https://avatars.discourse-cdn.com/v4/letter/j/c6cbf5/32.png) [@jdp](https://forum.modular.com/u/jdp)\
**Post date:** [May 20, 2025, 9:48pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/5 "2025-05-20T21:48:53Z")

</div>

Thanks for explaining

---

<div class="post-metadata">

**Author:** ![clattner](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.modular.com/clattner/32/201_2.png) [@clattner](https://forum.modular.com/u/clattner)\
**Post date:** [June 2, 2025, 8:40pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/6 "2025-06-02T20:40:55Z")

</div>

Out of curiosity though, why isn’t SIMD comparable? It seems like we’ll want floats and sized integer types to work with generic algorithms.

@adakkak do you have an opinion on this?

---

<div class="post-metadata">

**Author:** ![sora](https://avatars.discourse-cdn.com/v4/letter/s/ad7895/32.png) [@sora](https://forum.modular.com/u/sora)\
**Post date:** [June 2, 2025, 9:05pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/7 "2025-06-02T21:05:59Z")

</div>

`SIMD` isn’t directly comparable because ` __eq__ ` and ` __ne__ ` return a `SIMD[bool, ...]` vector, not a single boolean.

- We can’t make `Scalar[dt]` comparable (yet) because there’s no support for conditional conformance.

- We also can’t simply change the `Comparable` trait to return a `Boolable`, since that introduces a confluence issue: for example, if `bool(v)` is defined as `v.all()`, then we would have the following:

I had a long discussion with @Joe about this last year, and it’s a rather tricky problem to resolve.

---

<div class="post-metadata">

**Author:** ![clattner](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.modular.com/clattner/32/201_2.png) [@clattner](https://forum.modular.com/u/clattner)\
**Post date:** [June 3, 2025, 8:08pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/8 "2025-06-03T20:08:48Z")

</div>

Ah, thank you for explaining this. I don’t know the ramifications, but I’d be in favor of renaming the simd-returning comparisons to make it possible for these types to conform to the comparable/equatable traits. I’m not sure the best way to spell this, but SIMD-returning comparisons are pretty rare, so I think that `x.cmp_lt(y)` or `is_less` etc would probably be acceptable.

---

<div class="post-metadata">

**Author:** ![owenhilyard](https://sea1.discourse-cdn.com/flex001/user_avatar/forum.modular.com/owenhilyard/32/41_2.png) [@owenhilyard](https://forum.modular.com/u/owenhilyard)\
**Post date:** [June 4, 2025, 2:01pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/9 "2025-06-04T14:01:51Z")

</div>

Is there a good, non-surprising behavior for `SIMD(1,2,3) < SIMD(1,3,2)`? I would personally expect an element-wise comparison, and numpy also treats arrays this way.

I was also part of that discussion with Joe and Sora, and what we decided was that there was no good consistent behavior for any comparison other than a vector of length one. Equality should be doable for equal size vectors, since we can make that strict equality, but we are still left with how to handle size mismatches.

Conditional conformance should help handle the scalar case, but I don’t know if there’s a good behavior for `width >= 2`.

---

<div class="post-metadata">

**Author:** ![sora](https://avatars.discourse-cdn.com/v4/letter/s/ad7895/32.png) [@sora](https://forum.modular.com/u/sora)\
**Post date:** [June 4, 2025, 3:09pm UTC](https://forum.modular.com/t/why-is-float-not-comparable/1479/10 "2025-06-04T15:09:59Z")

</div>

> [@clattner](#):
>
> but SIMD-returning comparisons are pretty rare, so I think that `x.cmp_lt(y)` or `is_less` etc would probably be acceptable.

IIRC, Joe told me it’s exactly @adakkak who doesn’t like this idea. And for the record, I didn’t like it either.

> [@owenhilyard](#):
>
> Equality should be doable for equal size vectors, since we can make that strict equality, but we are still left with how to handle size mismatches.

We simply don’t handle size mismatches; they don’t type-check. That’s not the tricky part. The real contention lies between wanting syntactic sugar for numerical code and supporting generic programming.

> [@owenhilyard](#):
>
> we decided was that there was no good consistent behavior for any comparison other than a vector of length one.

That’s not how I remember it. We lack an `Eq SIMD` instance due to language/type system/API design constraints, not semantic ones. Moreover, being a value type (or a “regular” type, in the Stepanov sense) doesn’t inherently require additional comparison operators, so the absence of e.g. a `<` operator is far less problematic.

We can imagine a version of Mojo where dunder methods (which provide syntactic convenience) and `Eq`-conforming methods are distinct. In that hypothetical world, we could already implement `Eq SIMD`.

```mojo
trait Eq:
  fn eq(Self, Self) -> Bool: ...

struct SomeStruct(Eq):
  fn eq(...) -> Bool: ...
  fn __eq__ (...) -> Bool: return self.eq(rhs)

struct SIMD[...](Eq):
  fn eq(...) -> Bool: ...
  fn __eq__ (...) -> SIMD[bool, ...]: ...

```

Of course, this approach comes with its own set of drawbacks, and Python doesn’t allow us to take this route. I’m merely using this example to illustrate how vast the design space is and how many ways there are to solve this problem (long post pending – stay tuned). My favourite is the Swift approach: introduce `.op` variants (e.g., `.==`) for element-wise comparison.
