An 'in' operator for Ruby

November 13, 2019

I have had two fairly small changes I wanted to make in Ruby. The first was realized years ago. Hashes now preserve insertion order and iterate in a predictable way. That's fairly minor, but it did/does have some use cases, and it had no impact on performance.

Here's another one. Personally, this is a bigger thing to me.

I've always believed personally that Ruby should have an in operator.

I've mentioned this in speaking (including lightning talks) and in writing. It's not a giant big deal for me, but it is one of my personal favorite ideas. Here are some details.

My proposal

I propose to let x in y be syntax sugar for y.include? x

You may ask: Why?

include? is backwards from common usage -- if the item is our focus, we don't ask whether a group includes an item, but whether an item is in a group. The same is true of a container.

is backwards from common usage -- if the is our focus, we don't ask whether a group includes an item, but whether an item is in a group. The same is true of a container. Ruby isn't English; and more generally, programming languages aren't human languages. But programming languages are based on human languages and on everyday experience. We do sometimes ask questions like "Does this container or group include this item?" We are asking a question about the group .



if barrel.include? rotten_apple # Is barrel going bad?





on human languages and on everyday experience. We do sometimes ask questions like "Does this container or group include this item?" We are asking a question . But we also -- perhaps more often? -- ask questions like "Is this item part of this group?" We are asking a question about the item .



if fruit in [:apple, :pear, :peach] # Is this fruit something I like?





. include? is backwards from mathematical usage -- we ask whether a member is in a set ("epsilon"-like notation), not whether a set contains a memeber.

is backwards from mathematical usage -- we ask whether a member is in a set ("epsilon"-like notation), not whether a set contains a memeber. I ran across someone else a couple of years ago (I wish I could remember who it was!) who bemoaned the absence of this operator. His argument was that he would have a "conversation" with an object, for example, when he tested it repeatedly. Here's a contrived example I just made up. [" if foo == var1 ||", " foo =~ var2 ||", " foo < var3 ||", " var4.include?(foo) || # <== This is the ugly part", " foo > var5]"] To quote him as well as I remember: "I was having this perfectly nice conversation with foo , and then var4 interrupted it..." Better: [" if foo == var1 ||", " foo =~ var2 ||", " foo < var3 ||", " foo in var4 ||", " foo > var5]"]

I prefer to put the tested entity earlier in the statement:

[" if [GA, VA, MS, TX, MD, NC].include? state # ehhhh", " if state in [GA, VA, MS, TX, MD, NC] # better"] Also a "variable/constant" issue -- I tend to put the variable data on the left and the constant on right; this is unlike people who say if 5 == x . (After all, 5 is only equal to x very rarely; 5 is always equal to 5, even for very large values of 5.)

. (After all, is only equal to very rarely; is equal to 5, even for very large values of 5.) Also a question of focus: Whatever entity you are really dealing with, name that one first.

Many languages already have an in operator -- notably Python, Pascal, even SQL. It is familiar to users of those languages as well as those who use mathematical notation.

operator -- notably Python, Pascal, even SQL. It is familiar to users of those languages as well as those who use mathematical notation. in is already a reserved word in Ruby -- used in the for loop (syntax sugar for each ). Let's increase the justification for its presence.

is already a reserved word in Ruby -- used in the loop (syntax sugar for ). Let's increase the justification for its presence. An in operator would sometimes make parentheses unnecessary:

operator would sometimes make parentheses unnecessary: [" if (10..100).include? x # Need parens", " if x in 10..100 # Don't need parens -- also prettier code"] The newer language Elixir (which I'm happy to report occupies a lot of my time lately) also sports this operator. This is yet another reason to love that language.

Frequently Whined Whines

I'd prefer a method. I understand this, but I find it to be needlessly ugly. I like less punctuation, more whitespace. And I find this inappropriate for something that is conceptually an operator. [" if x.in mylist # ugly ", " if x.== 5 # also ugly ", " if c1.and c2 # ugly - if it worked ", " if x == 5 # better ", " if c1 and c2 # better ", " if x in mylist # better"]

I understand this, but I find it to be needlessly ugly. I like less punctuation, more whitespace. And I find this inappropriate for something that is conceptually an operator. I'd prefer a method with a ? on it. I understand the concept, too, but I find it inappropriate for what is inherently a relational operator. [" if x.in? my_set # very ugly ", " if x.==? 5 # very ugly - if it worked", "", " if x in my_set # natural", " if x == 5 # natural"]

I understand the concept, too, but I find it inappropriate for what is inherently a relational operator. What about for x in list ? Would this evaluate as for true or for false ? Certainly not. It's a matter of parsing. The for loop itself is just syntax sugar.

Certainly not. It's a matter of parsing. The loop itself is just syntax sugar. I'll bet you like junctions, too. No, in fact, I dislike junctions greatly. I don't even know Perl. Are junctions still a thing?

No, in fact, I dislike junctions greatly. I don't even know Perl. Are junctions still a thing? If you like SQL's in , you must like not in also. No, I don't condone its use of "not in": if item not in collection # travesty! if ! (item in collection) # ok if x not == y # horrible Ruby travesty - if it worked Yes, I say this even though ! ( item in collection) requires parentheses. See the comment about parentheses on ranges.

No, I don't condone its use of "not in": What about precedence? I would place in at the same level of precedence as the (other) relational operators < > <= >= etc.

People have ignored me on this for at least ten years. They probably still will. That, as they say, is life.