user7184349
user7184349

Reputation:

Ruby object vs. hash

Code snippet below returns an object.

class Person
  def initialize(name, gender)
    @name = name
    @gender = gender
  end
end
x = Person.new("Dan", "M")
=> #<Person:0x007f6f96600560 @name="Dan", @gender="M">

Upvotes: 5

Views: 9892

Answers (2)

Eric Duminil
Eric Duminil

Reputation: 54303

Object → Hash

From the excellent book "Ruby under the microscope" by Pat Shaughnessy :

Every Ruby object is the combination of a class pointer and an array of instance variables.

Here's a somewhat longer description :

A user-defined Ruby object is represented by a structure called an RObject, and is referred to by a pointer called VALUE.

Inside RObject, there is another structure called RBasic, which all Ruby values will have.

Aside from the RBasic structure, RObject also contains numiv, a count of how many instance variables the object has, ivptr, a pointer to an array of values of the instance variables, and iv_index_tbl, which is a pointer to a hash table stored in the object’s associated RClass structure that maps the name/identity of each instance variable to its position in the ivtpr array.

From any Ruby object, it's possible to extract a hash of instance variables :

class Object
  def instance_variables_hash
    Hash[instance_variables.map { |name| [name, instance_variable_get(name)] } ]
  end
end

With your example :

x.instance_variables_hash
=> {:@name=>"Dan", :@gender=>"M"}

Hash → Object ?

But you couldn't possibly create x back from this hash, because you're missing a crucial piece of information : what class is x an instance of?

So for example, you wouldn't know the methods that you can send to x :

class Dog
  def initialize(name, gender)
    @name = name
    @gender = gender
  end

  def bark
    puts "WOOF"
  end
end

person = Person.new("Dan", "M")
dog    = Dog.new("Dan", "M")

p person.instance_variables_hash
# {:@name=>"Dan", :@gender=>"M"}
p dog.instance_variables_hash == person.instance_variables_hash
# true
person.bark
# undefined method `bark' for #<Person:0x007fb3b20ed658 @name="Dan", @gender="M">

object_id

To get the object_id out of the inspect string :

"0x007f6f96600560".sub('0x','').to_i(16)/2
#=> 70058620486320

And back :

"0x" + (70058620486320 * 2).to_s(16).rjust(14,'0')
#=> "0x007f6f96600560"

Upvotes: 8

anquegi
anquegi

Reputation: 11542

Of course, some times you can use objects and hashes for the same thing. Storing key value pair ob objects like this:

[3] pry(main)> class Person
  def initialize(name, gender)
    @name = name
    @gender = gender
  end
end

[3] pry(main)* => :initialize

[4] pry(main)> x = Person.new("Dan", "M")
=> #<Person:0x00000003708098 @gender="M", @name="Dan">


[13] pry(main)> y = Person.new("Peter", "M")
=> #<Person:0x0000000391fca0 @gender="M", @name="Peter">


[22] pry(main)> z = {name: "Maria", gender: "F"}
=> {:name=>"Maria", :gender=>"F"}

But this objects really doesn't get all the power of an object oriente programming language from the definitions of an class/object and hash:

Ruby is a perfect Object Oriented Programming Language. The features of the object-oriented programming language include:

Data Encapsulation:

Data Abstraction:

Polymorphism:

Inheritance:

These features have been discussed in Object Oriented Ruby.

An object-oriented program involves classes and objects. A class is the blueprint from which individual objects are created. In object-oriented terms, we say that your bicycle is an instance of the class of objects known as bicycles.

Take the example of any vehicle. It comprises wheels, horsepower, and fuel or gas tank capacity. These characteristics form the data members of the class Vehicle. You can differentiate one vehicle from the other with the help of these characteristics.

A vehicle can also have certain functions, such as halting, driving, and speeding. Even these functions form the data members of the class Vehicle. You can, therefore, define a class as a combination of characteristics and functions.

and a hash:

A Hash is a collection of key-value pairs like this: "employee" => "salary". It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index.

So for store data I recommend you a Hash.

On the other hand, as showed in a comment the number that appers in the object representation is the object id, but with few operations added:

1) bitwise left shift:

5 << 1  # gives 10

2) passed to hexadeimal

(10).to_s(16)

"a"

pry(main)> x = Person.new("Dan", "M")
=> #<Person:0x00000003708098 @gender="M", @name="Dan">
[5] pry(main)> x.object_id
=> 28852300
[8] pry(main)> (x.object_id << 1 ).to_s(16)
=> "3708098"

finally in ruby you can get the hash representation of an object like this:

x.instance_variables.each {|var| hash[var.to_s.delete("@")] = x.instance_variable_get(var) }

Upvotes: 3

Related Questions