Clinton J
Clinton J

Reputation: 2123

Access an instance variable from child classes

I'm trying to access a datamember of a parent class from a child class. I am not sure how to call it. I have found a lot of info about accessing class variables but not instance variables from a child class. Here is my code:

class Shape

    @var = "woohoo"

    def initialize ()

    end

    def area ()

    end

end


class Rectangle < Shape

    @length
    @width

    def initialize ( l,w )
        @length = l
        @width = w
    end

    def area ()
      print @var
      return @length * @width
    end

end

I get an error trying to print @var. I tried parent.@var, Shape.@var, and a number of other combinations that I'd expect from other languages. What is the correct way to print (and if possible change) that variable within an instance of the child class?

EDIT: I want individual instances of the child class to replace the 'woohoo' string with their own unique strings.

Thanks!

Upvotes: 3

Views: 10830

Answers (2)

7stud
7stud

Reputation: 48589

I'm trying to access a datamember of a parent class from a child class. I am not sure how to call it. I have found a lot of info about accessing class variables but not instance variables from a child class. Here is my code:

class Shape
  @var = "woohoo"

That variable is known as a class instance variable, and the reason people use a class instance variable instead of a class variable, i.e. an @@variable, is precisely so that child classes cannot access it. Because class instance variables are the way class variables work in other languages, @@variables are not used much in ruby because their behavior is surprising if you come from another language that has class variables.

Your use case apparently calls for a class variable to be accessible in the child class, so have at it with an @@variable.

EDIT: I want individual instances of the child class to replace the 'woohoo' string with their own unique strings.

You can use class instance variables for that:

class Shape
  @var = "shapehoo"

  class <<self
    attr_accessor :var
  end

  def display_class_instance_var
    puts Shape.var
  end

end

class Rectangle < Shape
  @var = "recthoo"

  def display_class_instance_var
    puts Rectangle.var
  end
end

class Circle < Shape
  @var = "circlehoo"

  def display_class_instance_var
    puts Circle.var
  end
end

Shape.new.display_class_instance_var
Rectangle.new.display_class_instance_var
Circle.new.display_class_instance_var
Rectangle.new.display_class_instance_var
Shape.new.display_class_instance_var

--output:--
shapehoo
recthoo
circlehoo
recthoo
shapehoo

As with regular instance variables, class instance variables are private, so you have to provide accessor methods if you want to access them. The accessors need to be in the class's singleton class, which you can open using the syntax:

class <<self

end

Added:

About this code:

class Rectangle < Shape

    @length
    @width

    def initialize ( l,w )
        @length = l
        @width = w
    end

In your initialize() method, you are not setting the @length, @width variables you declared above the initialize method. In ruby, @variables attach themselves to whatever object is self at the time the @variables are created. Here is what your code looks like with some more detail:

class Rectangle < Shape
    #self=Rectangle class
    @length
    @width

    def initialize ( l,w )
        #self=a new instance of the Rectangle class created by initialize
        @length = l
        @width = w
    end

As a result, the @variables created in initialize() attach themselves to the new instance, while the @variables declared above initialize() attach themselves to the Rectangle class, which means they are completely different variables.

Upvotes: 6

Lukas Baliak
Lukas Baliak

Reputation: 2869

You can use "super" to call parent class initialize block and define instance variable "@var". In that case you can modify value of this instance variable for another instance. Like this:

class Shape
  def initialize ()
    @var = "woohoo"
  end
end

class Rectangle < Shape
  def initialize(l, w)
    @length = l
    @width = w
    super()
  end

  def area()
    print @var
    return @length * @width
  end

  def var=(new_value)
    @var = new_value
  end
end

a = Rectangle.new(1,1)
a.area
# => woohoo1
a.var = "kaboom"
a.area
# => kaboom1

b = Rectangle.new(2,2)
b.area
# => woohoo4

Or ofc you can use attr_accessor

class Shape
  def initialize
    @var = "woohoo"
  end
end

class Rectangle < Shape

  attr_accessor :var
  def initialize(l, w)
    @length, @width = l, w
    super()
  end

  def area()
    print @var
    return @length * @width
  end
end

a = Rectangle.new(1,1)
a.area
# => woohoo1
a.var = "kaboom"
a.area
# => kaboom1

b = Rectangle.new(2,2)
b.area
# => woohoo4

Upvotes: 4

Related Questions