Hacker News new | past | comments | ask | show | jobs | submit login
An 'in' operator for Ruby (rubyhacker.com)
88 points by charlieegan3 on Feb 15, 2016 | hide | past | favorite | 62 comments



Rails implements this as `in?`

https://github.com/rails/rails/blob/d61baee52adcd1baebe15f10...

You're welcome to try and merge that into Ruby core itself. That said, "I like whitespace" isn't a good reason to add a new operator over a method. Ruby is object oriented, meaning you are calling methods on objects.


He addresses this in his post.

  if x.in? my_set   # very ugly
With that said, I personally don't agree with the post.


I don't know what's so ugly about this.

I wouldn't call the method "in?" but maybe "element_of?" or "member_of?" but besides that, I don't see the need for an operator.


Then why have 2 * 4 when you can write 2.multiply_by 4...

What I love about ruby is its focus on making programming delightful rather than adhering to weird ass rules like 'Ruby is object oriented, meaning you are calling methods on objects.' that people pretend are laws of physics when really you can break them anytime you want, unlike laws of physics.

Similar to the way you can write

  def foo
    "bar"
  end 
instead of

  class Kernel
  
    def foo
      "bar"
    end
  
  end


The difference here is that `` literally maps onto a method called `` in Ruby. I find this aspect of Ruby delightful and it's not something I willingly chip away at.

Generally speaking, Ruby eschews syntax that invokes a protocol behind the scenes for a consistent 1:1 mapping between method syntax and the methods they invoke.


[deleted]


Smalltalk messages/methods:

   a in: set.
   2 * 4.
Just sayin'


Of course, but then

    2 * 4 + 5.
In Smalltalk evaluates to 18.


No, that's 13. You probably meant

  4 + 5 * 2.
Also:

Compilation Order: Smalltalk-78 had perpetuated the post-evaluation of receiver expressions so as to avoid delving into the stack to find the receiver. In the Smalltalk-80 language, however, we encoded the number of arguments in the send instruction. This enabled strictly left- to-right evaluation, and no one has since complained about surprising order of evaluation. We suspect that this change will yield further fruit in the future when someone tries to build a very simple compiler.

http://sdmeta.gforge.inria.fr/FreeBooks/BitsOfHistory/BitsOf... p. 21


Ah, thanks. I sit corrected :-)


I actually found it more interesting that Ruby hashmaps ("hashes" :S) preserve insertion order and guarantee predictable insertion.

I was taught to never trust the ordering returned by iterating over keys of hashmaps because it can be a source of bugs as you move between architectures or interpreters. If you need a guaranteed ordering, keep (and pay for) the appropriate auxiliary data structure.

Has this lesson become obsolete? Perhaps "computers are fast" so now Ruby can afford to use ordered hashmaps everywhere. On the other hand, I know Go chose to randomize iteration order of keys on purpose so developers cannot rely on them.


It's a side effect of their implementation and you should continue to not trust their default ordering.


Yes, you can. Ordering has been guaranteed since ruby v1.9, very much intentionally.

The implementation of a ruby hash is now as a doubly linked list [0]. This has inevitably caused a slight performance hit, but the benefits far outweigh the cost IMO.

[0] https://www.igvita.com/2009/02/04/ruby-19-internals-ordered-...


It appears that since Ruby 1.9 they guarantee insertion order: http://ruby-doc.org/core-2.3.0/Hash.html

I guess there are two approaches to solving the problem of people using your data structures the wrong way.

Edit: wrong link


As opposed to Go [0]

> When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. Since Go 1 the runtime randomizes map iteration order, as programmers relied on the stable iteration order of the previous implementation.

[0] https://blog.golang.org/go-maps-in-action


When I was first learning Ruby, having to invert my natural thought process in order to use `include?` was one of the most frustrating things I had to get used to. I think that's more a testament to how amazing Ruby is at imitating natural language patterns when that was my biggest complaint.

Having said that, I don't agree that it needs to be an operator over a method. I agree that it would be prettier, but methods provide additional benefits like being easy to override or pass as arguments to other methods (like :respond_to?). If you're ok with a method, you can easily monkey patch ruby to support an `in` (or `in?`) method yourself.


One of my favorite aspects of Ruby is that everything is an object with methods. Adding global operators/functions like this would only complicate the language.

> But we also -- perhaps more often? -- ask questions like "Is this item part of this group?" We are asking a question about the item.

Here we are actually asking the group a question about itself. An item would not know a group's contents.


If we're talking about the natural language question, "Is Bob part of the Physics Department," then sometimes we conceptualize "groups" as more like tags. Like, Bob has a tag that says, "->physics-dept." And so we ask Bob if he has that tag. He doesn't need to know the entire list of people who also have that tag in order to answer that question authoritatively.


> One of my favorite aspects of Ruby is that everything is an object with methods. Adding global operators/functions like this would only complicate the language.

But people love operators, that's why Ruby already includes loads of them instead of giving them identifier names and requiring you to call them with a dot. You have x+y instead of x.plus y, x==y instead of x.equals? y, x<y instead of x.less_than? y, most people write x..y instead of Range.new(x,y), etc. I don't think most Ruby programmers or the language designers agree with you about not wanting operators.


Totally agree with you. I do think it is more natural to ask a collection if it has an element. On the other hand, it would be possible for Object to have an in? method that would receive a collection.


> if item not in collection # travesty!

> if ! (item in collection) # ok

Riiiiiiiight. No more language suggestions from you, thanks ;)


Agreed

> if item not in collection

reads quite nicely. I don't see what the problem is there? Anyway, I don't think his one gripe with this is enough reason to throw the rest of his argument out.


I actually find that the use of "!" over "not" improves readability. English words tend to all blend together and take more time to parse, whereas a nice "!" token is easy to recognize at a glance. That being said, "not" is of course more understandable for somebody who has no idea about the language; however, asking a programmer to learn a single symbol for "not" is not too much to ask :)


depends how much attention you're paying at the moment.

its easier to miss a ! than a 'not' at a quick glance


good point! all syntax highlighters should color negations in neon red


unless item in collection

Obviously is the best choice


Yes, and it's the idiomatic Ruby one.


Touché ;)


[deleted]


I believe the parent comment is agreeing with you (?) and disagreeing with the author of the linked article.


>> if item not in collection

he should have suggested

if not item in collection

which should then work out of the box anyways

[I completely agree with the need for the 'in' operator]


  if x.in? my_set   # very ugly
I guess we disagree there. This is arguably more readable than most languages with `in?` being still just a method.


I agree, I quite like it as a method as it keeps its congruence with .include? as an opposite of .in? (what .in? does should have been what .include? did from the get go).

Perhaps another way of doing this is calling the method .within?


Seconded. One of the ways in which I prefer Ruby to Python is the way that it always favours "plain methods" over "syntax that maps to special methods under the covers".


But that's not true, as far as I can tell. Ruby does allow you to write 5.+(8), but as far as I can tell most people prefer 5+8. Ruby also has special syntax for <, == and indexing arrays. What things does Python have special syntax for that Ruby doesn't? Off the top of my head I can only remember "in".


This would go against the ruby style of using predicates for this sort of thing (think `include?`, `empty?`, `nil?`).

I personally wouldn't be in favor of it.

Addition: Arguing that "Ruby isn't English" and then stating conformity to mathematical notation as a benefit seems hypocritical. Programming languages (besides APL, maybe) do not use strict mathematical notation, and we shouldn't want them to.


.include? isn't really a predicate, as predicates are typically unary. Rather, it's the 'member of' relational operator written in the wrong direction. Since we don't have '∈' in ascii, the author is proposing using the word 'in' instead.

I do disagree with the author on one point: 'not in' should also be a valid operator, representing '∉'.

But I don't use Ruby; I mostly use Python, which has these operators.


It's not a problem using non ASCII method names in Ruby: https://gist.github.com/bhaak/91428b9aee88ac50dd1d

I can't think of any modern programming language that isn't unicode aware even though for the standard library methods, there are very good reasons not to use them (I know, Perl 6 does but even in this case there are ASCII fallbacks).

You should also have very good reasons to put methods on the root class of your class hierarchy.


> It's not a problem using non ASCII method names in Ruby

Making it easy for people to type them, on the other hand...


> Making it easy for people to type them, on the other hand...

That's a problem of the code editors people are using. ;-)

I'm often surprised with how dysfunctional editors people are programming.

For example if all editors would show tabs and spaces (or whitespace in general) in a reasonable way, we wouldn't have had that much pointless discussion about the correct indentation whitespace character.


I don't think it 'goes against' anything... it's simply a more concise way of doing the .include? - it's syntactic sugar.

And as he points out, 'in' is already a keyword anyway - so if it makes a more readable way of doing things, then why not?


As for programming languages, I've always wondered how languages would've looked if computers, and as a result programming languages, had been invented in non-english speaking countries.

An immediate example that comes to mind is Python's use of None, rather than null (like in Java/JavaScript). I remember speaking in Dutch about Java in college was always slightly awkward, because it was easy to confuse "null" with 0 (or "nul"). I wonder if Guido (being Dutch) called the Python void type "None" on purpose, to avoid awkwardness when speaking about it in Dutch.


I understand the perceived benefit of compositional eloquence that this may add (pretty much borrowing from Python) but as others have pointed out, this is incongruent to the design of Ruby as a language and how it treats the relation between objects and their methods. Additionally, you lose any compositional elegance you may have gained when you decided not to use:

  x not in y
and instead propose:

  !(x in y)
Seems like a zero-sum addition to the language to me.


I find `not in` highly dubious - it makes the expression grammar awkward and harder to parse. Is `not in` a two-token operator? Or is `not` an adverb in this context? What else resembles this?

To cite an alternatice, in Tcl, `in` is an operator and its negation is `ni`. A cute pun and echo of Monty Python that I'm disappointed Python didn't follow :).


You should be happy, as Python 3 would have renamed it to "Ekke Ekke Ekke Ekke Ptang Zoo Boing!"

As to the "what else resembles this"? I would turn it around and ask what else could resemble this. I'm not sure the conclusion would be that "not in" is a good thing, but not sure of the reverse, either:

  if x not = 3
looks weird, but I think I could grow to like it.


Well, shell has the '-ne' operator, which is 'not equals' in a terser style.

Really '!=' is just an attempt at rendering '≠' using only ASCII characters. They're a bit like digraphs and trigraphs in C/C++, except everyone is used to them.

I wonder if Unicode is ubiquitous enough now that you could write a language where the real maths operators were used instead. What would that look like?


Haskell allows unicode in operators and there appear to be packages that implement aliases for the default ASCII versions.

https://wiki.haskell.org/Unicode-symbols


Scala allows using unicode arrows (→) in place of their ASCII version (->), but not things like '≠'.

I'm currently using the Monoid font (https://larsenwork.com/monoid/), which uses ligatures to achieve the visual effect of things like the not equals symbol, while the underlying code remains the same. It's a pretty nice work-around for current languages.


Another alternative is the way D does it. Its the same idea as `not in` but instead of adding a 2 keyword operator and non-standard usage of negation (`not` instead of `!`) it is simply: `!in`


If it's this importing why not propose it: https://bugs.ruby-lang.org/

Ruby has a place for this sort of thing and they'll answer you.


It was proposed in 2010 and rejected by Matz in 2012: https://bugs.ruby-lang.org/issues/3845


something went wrong between

Matz: I am neutral for this proposal.

... ...

Matz: This proposal is only for cosmetics. I don't want a new operator that does not introduce something new.

[I personally disagree and think the 'in' operator should be added]


Could be worse, consider testing for inclusion in Javascript with Array#indexOf, where you don't even get a boolean value back.

The fact that the Ruby method is called include? and not includes? is annoying though.



One day we will have a 'no-awkward'™ english like syntax: https://github.com/pannous/english-script


AppleScript tried to do just that:

https://en.wikipedia.org/wiki/AppleScript

It doesn't work out very well in practice. Inevitably the syntax diverges, and then it's pretty confusing for the novice user: why do some sentences work but most don't?


from my experience Apple's problem with AppleScript was not so much diverging syntax but constant undebuggable crashes


[deleted]


"in" is already a reserved word in Ruby.


Yes! Do it.


/me Comes to this thread, upvotes all the comment mentionning `.in?`


so.. is 10 'in' 10..100? is 100?


10..100 is a Range in Ruby. 10..100 does include 100 (it includes both bounds). On the other hand 10...100 (note the three dots) does not.


> On the other hand 10...100 (note the three dots) does not. reply > On the other hand 10...100 (note the three dots) does not.

To be clear, 10...100 includes 10, but not 100. So, it includes one bound: the one mentioned first, the lower bound.

  (10...100).to_a
  => [10, 11, 12, 13, ... 98, 99]


    [1] pry(main)> 10..100
    => 10..100
    [2] pry(main)> (10..100).class
    => Range
    [3] pry(main)> (10..100).to_a
    => [10, 11, 12, 13, 14, ..., 99, 100]




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: