8

After reading a comment to an answer in another question and doing a little research, I see that =~ is defined on Object and then overridden by String and Regexp. The implementations for String and Regexp appear to assume the other class:

"123" =~ "123" # => TypeError: type mismatch: String given
/123/ =~ /123/ # => TypeError: can't convert Regexp to String

Although =~ is defined for Object, + is not:

Object.new =~ 1 # => nil
Object.new + 1 # => undefined method `+' for #<Object:0x556d38>

Why has Object#=~ been defined, rather than restricting =~ to to String and Regexp?

Community
  • 1
  • 1
Eric Walker
  • 7,063
  • 3
  • 35
  • 38
  • FWIW, it's defined in object.c as `static VALUE rb_obj_match(VALUE obj1, VALUE obj2) { return Qnil; }`. – Dogbert Dec 22 '12 at 13:40
  • Did some googling, and there doesn't seem to be much of an answer anywhere. – Linuxios Dec 22 '12 at 15:13
  • @Dogbert I saw that. Maybe looking through the Subversion history would shed light on this. – Eric Walker Dec 22 '12 at 18:54
  • 1
    @EricWalker, [here's the commit](https://github.com/ruby/ruby/commit/9d8075b99cf131e0b2522bcf82a5b47e82d3882e). Doesn't seem to help answer the question though. – Dogbert Dec 22 '12 at 19:00

3 Answers3

2

Well, I suppose that's actually nicely answered in String =~ documentation:

Match — If obj is a Regexp, use it as a pattern to match against str,and returns the position the match starts, or nil if there is no match.

Otherwise, invokes obj.=~, passing str as an argument. The default =~ in Object returns nil.

The point is, you can write your own implementation of Object =~ - and it will be used in String =~ Not Regexp statement.

raina77ow
  • 103,633
  • 15
  • 192
  • 229
  • 1
    This is not answering much. When would you want to use `String =~ Not Regexp`? – sawa Dec 22 '12 at 14:56
  • Also, why not do that with `+` as well (which is not defined for `Object`, unlike `=~`) -- that's what's not very clear to me. It's almost like there was an additional thought going into it beyond convenience, e.g., a change in approach, a specific problem case, etc. – Eric Walker Dec 22 '12 at 18:50
2

Because it allows any object to be used in a match expression:

Object.new =~ /abc/
=> nil

I guess this makes sense in the way that Object.new does not match the regexp /abc/ and the code would blow up if the left argument wasn't a String object. So it generally simplifies the code because you can have any object on the left side of the =~ operator.

Nicholas
  • 2,147
  • 3
  • 23
  • 31
2

From your comments, your actual question is why is =~ defined on Object while + isn't.

The reason is that Object#=~ can return nil for random objects (since they don't match), but Object#+ can not return a meaningful result.

It is not necessarily super useful, but it can not be said to be false (you would have to show a match to prove that a nil result is a contradiction). See the mathematical concept of vacuous truth. On the other hand, any result for Object.new + 1 could lead to contradictions.

This is similar to <=> that can return nil (and is thus also defined on Object) while <, >, ..., can not return true nor false while being completely consistent. Note that for Class#> it was decided to return nil in those cases.

Marc-André Lafortune
  • 78,216
  • 16
  • 166
  • 166
  • I appreciate the point. But I don't see how `Object.new =~ 1` is more meaningful than `Object.new + 1`. – Eric Walker Dec 23 '12 at 03:20
  • Tried editing my answer. Can you provide a meaningful result for `Object.new + 1`? Do you agree that `Object.new <=> 1 #=> nil` is logical? – Marc-André Lafortune Dec 23 '12 at 10:08
  • +1 for an interesting discussion. It seems to me like there could be the following cases here: (1a) there was a clear reason, and one or more responders here have gotten it; (1b) there is a clear reason, and it hasn't been mentioned yet; and (2) there was no compelling reason, it was just done this way without too much thought going into it. I'm not convinced yet that we have (1a), yet. I didn't intend to ask a question I would have a hard time approving an answer to. – Eric Walker Dec 23 '12 at 18:11
  • I do agree that `Object.new <=> 1 #=> nil` is logical. I'm not convinced that `Object.new =~ 1 #=> nil` falls into the same category, though. It seems just as likely that it would have been a good idea to raise an exception in the latter instance, as is done with other operators. – Eric Walker Dec 23 '12 at 18:17