What is the difference between Methods and Attributes in Ruby?

43,678

Solution 1

Attributes are specific properties of an object. Methods are capabilities of an object.

In Ruby all instance variables (attributes) are private by default. It means you don't have access to them outside the scope of the instance itself. The only way to access the attribute is using an accessor method.

class Foo
  def initialize(color)
    @color = color
  end
end

class Bar
  def initialize(color)
    @color = color
  end

  def color
    @color
  end
end

class Baz
  def initialize(color)
    @color = color
  end

  def color
    @color
  end

  def color=(value)
    @color = value
  end
end

f = Foo.new("red")
f.color # NoMethodError: undefined method ‘color’

b = Bar.new("red")
b.color # => "red"
b.color = "yellow" # NoMethodError: undefined method `color=' 

z = Baz.new("red")
z.color # => "red"
z.color = "yellow"
z.color # => "yellow"

Because this is a really commmon behavior, Ruby provides some convenient method to define accessor methods: attr_accessor, attr_writer and attr_reader.

Solution 2

Attributes are just a shortcut. If you use attr_accessor to create an attribute, Ruby just declares an instance variable and creates getter and setter methods for you.

Since you asked for an example:

class Thing
    attr_accessor :my_property

    attr_reader :my_readable_property

    attr_writer :my_writable_property

    def do_stuff
        # does stuff
    end
end 

Here's how you'd use the class:

# Instantiate
thing = Thing.new

# Call the method do_stuff
thing.do_stuff

# You can read or write my_property
thing.my_property = "Whatever"
puts thing.my_property

# We only have a readable accessor for my_readable_property
puts thing.my_readable_property 

# And my_writable_propety has only the writable accessor
thing.my_writable_property = "Whatever"

Solution 3

Attributes are, strictly speaking, the instance variables of a class instance. In more general terms, attributes are usually declared using the attr_X type methods, while methods are simply declared as is.

A simple example might be:

attr_accessor :name
attr_reader :access_level

# Method
def truncate_name!
  @name = truncated_name
end

# Accessor-like method
def truncated_name
  @name and @name[0,14]
end

# Mutator-like method
def access_level=(value)
  @access_level = value && value.to_sym
end

The distinction between these two is somewhat arbitrary in Ruby since no direct access to them is specifically provided. This contrasts quite strongly with other languages such as C, or C++ and Java where access of an objects properties and calling methods is done through two different mechanisms. Java in particular has accessor/mutator methods that are spelled out as such, whereas in Ruby these are implied by name.

It is often the case, as in the example, where the difference between an "attribute accessor" and a utility method that provides data based on an attribute's value, such as truncated_name, is minor.

Solution 4

class MyClass
  attr_accessor :point

  def circle
    return @circle
  end

  def circle=(c)
    @circle = c
  end
end

An attribute is a property of the object. In this case, I use the attr_accessor class method to define the :point property along with an implicit getter and setter methods for point.

obj = MyClass.new
obj.point = 3
puts obj.point
> 3

The method 'circle' is an explicitly defined getter for the @circle instance variable. 'circle=' is an explicitly defined setter for the @circle instance variable.

Share:
43,678

Related videos on Youtube

collimarco
Author by

collimarco

Updated on July 09, 2022

Comments

  • collimarco
    collimarco almost 2 years

    Can you give me an example?

  • Aaron Rustad
    Aaron Rustad almost 15 years
    You can always access variable using Object.instance_variable_get(:@symbol), which circumvents the need to define accessors.
  • Simone Carletti
    Simone Carletti almost 15 years
    This is not really a good practice. ;) instance_variable_get should be reserved for metaprogramming stuff. It's like defining a method as private then accessing it with send(:method).