Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: Why does Hash === {} return true?

Tags:

ruby

I have a hash, let's say:

ahash = {test1: "test1", test2: "test2"}

Why is it that Hash === ahash returns true, but ahash === Hash doesn't? Is this some default ruby behavior with === and class name?

like image 869
JohnDel Avatar asked Sep 18 '14 20:09

JohnDel


2 Answers

It's just how the === method works. It's directional and that applies to any class:

"foo" === String
# => false
String === "foo"
# => true

This is because that evaluates to:

"foo".send(:===, String)
String.send(:===, "foo")

Those are two different methods, one for the class, one for the instance.

If you're only concerned with class information:

"foo".is_a?(String)
# => true

{ }.is_a?(Hash)
# => true

This method makes it a lot more clear what your intention is.

like image 91
tadman Avatar answered Nov 01 '22 00:11

tadman


You Aren't Testing What You Think You're Testing

Module#=== (also called the "case equality operator") returns true if the object on the right-hand side of the expression is an instance of the left-hand side, or one of its descendants. When you ask:

Hash === {test1: "test1", test2: "test2"}

what you're really asking is this: "Is this hash literal an instance or descendant of the Hash class?" On the other hand, the reverse is not true, since the Hash class is not an instance or descendant of your hash literal.

More About Case Equality

On the other hand, the following works either way:

Hash.new === {}
{} === Hash.new

because both expressions are case-equivalent. Here's the same result using your data:

Hash[:test1, "test1", :test2, "test2"] === {:test1=>"test1", :test2=>"test2"}
#=> true

{:test1=>"test1", :test2=>"test2"} === Hash[:test1, "test1", :test2, "test2"]
#=> true

However, threequals isn't just a stand-in for Object#is_a?. It's really meant to be consumed by case/when statements, and Giles Bowkett says:

The === method exists for controlling how a case/when block will evaluate an object. It should never be used by humans. It is code written to be consumed by other code, specifically, by case and when.

like image 6
Todd A. Jacobs Avatar answered Nov 01 '22 01:11

Todd A. Jacobs