# RFC: Can we remove the \`===\` operator?

**URL:** <https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729>\
**Category:** Help & Support\
**Created:** [May 5, 2019, 1:45pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729 "2019-05-05T13:45:41Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![scott](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/scott/32/948_2.png) [@scott](https://forum.crystal-lang.org/u/scott)\
**Post date:** [May 5, 2019, 1:45pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/1 "2019-05-05T13:45:42Z")

</div>

The `===` vs `==` operators are a great source of confusion in the languages where they are prevalent. People coming from languages without it expect `==` to mean deep equality, and people coming from languages with `===` expect `===` to be deep equality and `==` to mean equality after some type coercion. See [#1749](https://github.com/crystal-lang/crystal/issues/1730).

Throughout the standard library, as far as I’m aware, `===` and `==` both take the same action. However, the presence of both encourages [3rd party library](https://github.com/ysbaddaden/scrypt-crystal#usage) developers to create unintuitive “sloppy equals” operator overloads, especially when translating from ruby.

I think that cases where `==` and `===` differ, if they exist, should be removed, along with the ambiguity the operator creates.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [May 5, 2019, 2:34pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/2 "2019-05-05T14:34:45Z")

</div>

It’s used in Regex, Range and Class. It’s the operator used for case-when. It will not be removed.

---

<div class="post-metadata">

**Author:** ![scott](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/scott/32/948_2.png) [@scott](https://forum.crystal-lang.org/u/scott)\
**Post date:** [May 5, 2019, 2:58pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/3 "2019-05-05T14:58:38Z")

</div>

There aren’t more appropriate alternatives that could be used in those cases?

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [May 5, 2019, 3:20pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/4 "2019-05-05T15:20:16Z")

</div>

I guess we could use a different name or operator. I don’t see people confusing these operators, though.

---

<div class="post-metadata">

**Author:** ![RX14](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rx14/32/633_2.png) [@RX14](https://forum.crystal-lang.org/u/RX14)\
**Post date:** [May 5, 2019, 4:18pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/5 "2019-05-05T16:18:10Z")

</div>

`===` is much less commonly commutative than `==`, i’d be happy to change it to `#similar?` instead of being an operator, since most people don’t use `===` directly, instead only using it indirectly with `case`.

On the other hand, it’s not a big deal to me, but if someone wants to push a PR through i’m open to approving it

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [May 5, 2019, 4:59pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/6 "2019-05-05T16:59:44Z")

</div>

I agree, but `similar?` is not very accurate. I guess the lack of finding a fitting name is why this method is called `===` and it probably will stay like this.

And if this was to change, I wouldn’t want to see a PR directly, but a dedicated discussion about the naming first ;)

---

<div class="post-metadata">

**Author:** ![scott](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/scott/32/948_2.png) [@scott](https://forum.crystal-lang.org/u/scott)\
**Post date:** [May 6, 2019, 11:21am UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/7 "2019-05-06T11:21:36Z")

</div>

It looks like `Regex#===` can just be changed to `Regex#==` – there’s no conflicting overload for `==` on Regex. Either way it’s just a mirror of `#match?` and `~=`.

Range is a bit of a [different case](https://github.com/crystal-lang/crystal/blob/aad364612e2745b277991218439eff6d15cf79e1/src/range.cr#L293) – `0..10 === 5 # => true`. Since most other languages use `===` to mean a sense of especially deep equality, this seems to me to be an extremely unintuitive API.

I don’t really get the difference between what’s happening in `Class#==` and `Class#===`.

After looking over these cases I think it would be best to change case to look at `#match` instead of `===`. `case` statements already do some pattern matching – as evidenced by the examples given. Regex is the most obvious case but I think it would make sense in other cases too.

---

<div class="post-metadata">

**Author:** ![straight-shoota](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/straight-shoota/32/36_2.png) [@straight-shoota](https://forum.crystal-lang.org/u/straight-shoota)\
**Post date:** [May 6, 2019, 12:55pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/8 "2019-05-06T12:55:04Z")

</div>

`match` would certainly be a feasible option for naming this method. However, assigning implicit semantics to such generic method names is problematic. Developers might not be aware of this relation and define a `match` method with completely different meaning. But suddenly, an object with that method behaves very unexpected when used in a `case ... when` context. An operator like `===` is less likely to be unintentionally implemented and it is more obvious that there might be a special meaning associated. This could be avoided by introducing a module `Matchable` which would be implemented by Regex & Co, but that adds more complexity than just a single method.

In order to avoid `===` because it’s not very intuitive, we might consider a different operator. But I think it should be an operator, not a regular method name to avoid accidental implementation. `=~` might also work, but it’s already commutative for String and Regex, so the semantics are different. Maybe something like `=~~` could do, but I fail to see a huge benefit.

---

<div class="post-metadata">

**Author:** ![scott](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/scott/32/948_2.png) [@scott](https://forum.crystal-lang.org/u/scott)\
**Post date:** [May 6, 2019, 1:36pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/9 "2019-05-06T13:36:05Z")

</div>

> [@straight-shoota](#):
>
> assigning implicit semantics to such generic method names is problematic

That’s true, you definitely have a point there. `match` is definitely too generic, and there aren’t any other cases I know of where a normal method like that does something so specific and unique. I definitely rescind that suggestion 🙂

I like `=~` as a “match operator” though – it seems intuitive that it would be.

> [@straight-shoota](#):
>
> `=~` might also work, but it’s already commutative for String and Regex, so the semantics are different

I don’t see what you mean by the semantics being different, could you explain?

---

<div class="post-metadata">

**Author:** ![scott](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/scott/32/948_2.png) [@scott](https://forum.crystal-lang.org/u/scott)\
**Post date:** [May 6, 2019, 1:39pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/10 "2019-05-06T13:39:02Z")

</div>

After this discussion, it seems to me that we have two operators which both roughly mean “matches” – `===` and `=~`.

---

<div class="post-metadata">

**Author:** ![asterite](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/asterite/32/60_2.png) [@asterite](https://forum.crystal-lang.org/u/asterite)\
**Post date:** [May 6, 2019, 1:58pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/11 "2019-05-06T13:58:26Z")

</div>

`x ===` roughly means “belonging to the category denoted by x”. For example, `String ===` means “belonging to the category of Strings”, so `String === "foo"` is `true`. For range, `0..10 ===` means “belonging to the category of things that are in the given range”, for regex is “belonging to the category of strings that match the given regex” and so on.

For `Regex` it happens to be similar to `=~`, but for other cases the semantic is not quite “matches”.

From my point of view, I’d prefer not to make fundamental changes to things that are not broken. That `===` exist in other languages with a different meaning is probably not a problem. The meaning is exactly the same as in Ruby, and Crystal matches most of Ruby’s syntax and semantic.

---

<div class="post-metadata">

**Author:** ![Sija](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/sija/32/737_2.png) [@Sija](https://forum.crystal-lang.org/u/Sija)\
**Post date:** [May 9, 2019, 12:09pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/12 "2019-05-09T12:09:02Z")

</div>

I’m against this change. This will bring confusion to the users coming from Ruby and create a need to define another _sensitive_ method (think of problems arising from redefining `#id`).

If it ain’t broken, don’t fix it please.

---

<div class="post-metadata">

**Author:** ![rogerdpack](https://yyz2.discourse-cdn.com/flex036/user_avatar/forum.crystal-lang.org/rogerdpack/32/117_2.png) [@rogerdpack](https://forum.crystal-lang.org/u/rogerdpack)\
**Post date:** [March 12, 2020, 6:03pm UTC](https://forum.crystal-lang.org/t/rfc-can-we-remove-the-operator/729/13 "2020-03-12T18:03:35Z")

</div>

+1 from me, only because ruby having _so many_ different equals methods (eql? === ==) has always been confusing. It’s not broke but it is ugly. Maybe could. be named…something better? another example (in this case of `eql?`): [https://github.com/crystal-lang/crystal/pull/8893#discussion\_r391093981](https://github.com/crystal-lang/crystal/pull/8893#discussion_r391093981) a mere mortal cannot easily tell what is used for what…FWIW :)
