Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Declaring an instance variable outside of `initialize` method

I have been taught to declare my instance variables with def initialize. I have been under the impression that I could declare instance variables only within my initialize methods.

Nevertheless, I declared an instance variable @foo outside my initialize method, and made it work as I intended:

class FooBar
    def initialize(bar)
        @bar = bar
    end

    def foo_as_instance_var
        @foo = @bar.split(' ')
        @foo
    end
end

x = "something wicked this way comes"
y = FooBar.new(x)
puts y.foo_as_instance_var

Why am I able to declare an instance variable outside of initialize method? Since I can declare instance variables in any method, is there a best practices rule I should follow, regarding where to declare instance variables (i.e., declare them within initialize) or does it not matter?

like image 931
foo Avatar asked Jan 15 '19 04:01

foo


3 Answers

I have been taught to declare my instance variables with def initialize

Since initialize is the first instance method call in an object's life cycle, you typically declare your instance variables right there in order to ensure properly initialized variables. It's also the first place I'd expect instance variables to be defined when reading code.

I have been under the impression that I could declare instance variables only within my initialize methods.

There's no such restriction. You can declare instance variable anywhere within your instance.

A common use is memoization:

class FooBar
  def foo
    @foo ||= expensive_operation
  end
end

On the first call, this would evaluate expensive_operation and assign the result to @foo. On subsequent calls, @foo is returned.

Another popular example is Rails which uses instance variables to pass data from the controller to its view:

class FooController < ApplicationController
  def index
    @foos = Foo.all
  end
end

is there a best practices rule I should follow, regarding where to declare instance variables

It depends on their purpose (see above examples). As a general rule, declare them in a way that avoids undefined variables (nil errors) and structure your code so it is easy to read / follow.

like image 82
Stefan Avatar answered Nov 15 '22 04:11

Stefan


Just to add to Stefan's excellent answer

I have been taught to declare my instance variables with def initialize

A common mistake that ruby newbies make is something like this:

class Person
  @name = "John"

  def introduce
    puts "Hi, my name is #{@name}"
  end
end

And then they wonder why their names are not printed. To make this work, one can set the variable @name in the initializer, just as the instruction says.

like image 23
Sergio Tulentsev Avatar answered Nov 15 '22 02:11

Sergio Tulentsev


Lets start with the biggest misnomer - in Ruby there is no separate step of declaring variables - Variables are declared as you set them.

What the difference? Look at Java for example:

public class Bicycle {

    private int cadence;
    private int gear;
    private int speed;

    public Bicycle(int startCadence, int startSpeed, int startGear) {
        gear = startGear;
        cadence = startCadence;
        speed = startSpeed;
    }
}

We have to declare all the instance variables before we set them in the initializer (Bicycle). The same code in Ruby reads:

class Bicycle
  def initialize(cadence, speed, gear)
    @cadence = cadence
    @speed = speed
    @gear = gear
  end
end

There is no declaration - only assignment. Ruby will even let you access instance variables which have not been set without error.

irb(main):003:0> @not_set
=> nil

You can't do that (generally) in languages where variables must be defined*.

I have been taught to declare my instance variables with def initialize. I have been under the impression that I could declare instance variables only within my initialize methods.

Nonsense. You can assign instance variables anywhere. Its commonly done in everything from setters and mutators (methods that alter an object) to factory methods (class methods that return an instance) or anywhere that you are altering the state of an object.

class Book 

  def initialize(title, author)
    @title = title
    self.author = author # calls the setter.
  end

  # A factory method
  def create_from_csv(filename)
    # ...
  end

  # A very contrived setter
  def author=(author)
    @author = "#{author.forename.upcase}. #{author.surname}"
  end

  # a mutator
  def out_of_print!
    @out_of_print = true
    @last_printed = Date.today
  end
end

However the initialize method is where you should handle initializing your objects (duuh) and is thus the obvious place to set initial values.

like image 25
max Avatar answered Nov 15 '22 02:11

max