2

I want to create an empty array as a class instance variable in Ruby. However, my current method does not seem to work.

Here is my code:

class Something 
    @something = []
    def dosomething
        s = 5
        @something << s
    end
end

When I call the function, it gives me an undefined method traceback. However, if I do something similar with class variables, i.e.:

class Something
    @@something = []
    def dosomething
        s = 5
        @@something << s
    end
end

This works perfectly.

I know I can use the initialize method to actually create an empty list for @something, but is there another way of doing this without using the initialize method? And why does this work for class variables?

EDIT: Fixed typo

2
  • "without using the initialize method" - is there any reason to avoid initialize? Commented May 3, 2016 at 8:56
  • Your question is clear that you want to initialize a class instance variable, not an instance variable, not a class variable. Yet you assigned the greenie to an answer that makes no reference to class instance variables. Why? btw, some Rubiests never use class variables, always opting for class instance variables instead. Commented May 3, 2016 at 18:10

4 Answers 4

6

You need to use initialize as a constructor as below code and is there any reason why not to use initialize/constructor. And please fix a typo error in class definition Class Something to class Something no camel case or first letter capitalize while in class

class Something 
      def initialize
        @something = Array.new
      end
      def dosomething
        s = 5
        @something << s
      end
    end

class variable @@ are available to the whole class scope. so they are working in the code and if you want to use instance variable @ you need to initialize it as above. The instance variable is share with instance/objects of a class

for more details visit the link Ruby initialize method

Sign up to request clarification or add additional context in comments.

7 Comments

Generally [] is preferable to Array.new unless you're doing something that involves passing arguments to new like Array.new(10).
Yes, and in above case there was no use of argument sending :) so i prefer Array.new..
That's your personal preference, but the majority of Ruby style guides frown on it as needless clutter.
Class variables are not global variables. Global variables are available to any object in the Ruby object space. @@ variables are available only to the class in which they are defined, and their subclasses.
Yes, Thank you Keith Bennet Updated
|
2

At first you have a typo. Change Classto class. Next I suggest to use the initialize method. While creating a new object this is the perfect place to initialize instance variables.

class Something
  @@my_class_variable = [1]

  def initialize
    @something = []
  end

  def dosomething
    s = 5
    @something << s
  end

  def self.get_my_class_variable
    @@my_class_variable
  end
end

Your script will be read and executed from top to bottom and after this, you can access the class Something. While the parser reads your script/class/module you can define class variables (@@), execute mixins and extend the class with other modules. This is why you can define a class variable, but you can not define an instance variable. Because actually you have no instance object from your class. You only have a class object. In ruby everything is an object. And your class object has a defined class variable now:

Something.get_my_class_variable
# => [1]

Now you can create an instance from your class. With Something.new the initialize method will be invoked and your instance variable will be defined.

something = Something.new
something.dosomething
# => [5]

Later, if you are familar with this you can define getter and setter methods with attr_reader, attr_writer and attr_accessor for instance objects or cattr_reader, cattr_writer and cattr_accessor for class objects. For example:

class Something
  attr_reader :my_something

  def initialize
    @my_something = []
  end

  def dosomething
    s = 5
    @my_something << s
  end
end

something = Something.new
something.my_something
# => []
something.dosomething
# => [5]
something.my_something
# => [5]

2 Comments

Alright thanks for that. Do you know why my code works for class variables though?
@Shwunky Because that's how class variables work. Class variables are intended to be used in the class context (rather than an instance context) and so Ruby provides a way for you to initialize them when you create a class.
0

Your problem in trying to access @something in your instance method is that, in the scope of instance methods, @ variables refer to instance variables, and your @something is a class instance variable.

@ variables are instance variables of the instance that is self when they are created. When @something was created, self was the class Something, not an instance of Something, which would be the case inside an instance method.

How then to access a class instance variable in an instance method? Like regular instance variables, this must be done via a method, as in attr_accessor. One way to do this is to use class << self to tell the Ruby interpreter that the enclosed code should be evaluated with the class (and not the instance) as self:

class C

  @foo = 'hello'

  class << self
    attr_accessor :foo  # this will be a class method
  end

  def test_foo  # this is, of course, an instance method
    puts self.class.foo  # or puts C.foo
  end
end

We can show that this works in irb:

2.3.0 :005 > C.foo
 => "hello"
2.3.0 :006 > C.new.test_foo
hello

Comments

0

You have correctly created a class instance variable, @something, and initialized it to an empty array. There are two ways for instances to obtain or change the value of that variable. One is to use the methods Object#instance_variable_get and Object#instance_variable_set (invoked on the class):

class Something
  @something = [] 
  def dosomething
    s = 5
    self.class.instance_variable_get(:@something) << s
  end
end

sthg = Something.new
sthg.dosomething     

Something.instance_variable_get(:@something)
   #=> 5

The other way is to create an accessor for the variable. There are several ways to do that. My preference is the following:

Something.singleton_class.send(:attr_accessor, :something)
Something.something #=> [5]

In your dosomething method you would write:

self.class.something << s

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.