3

Given this basic class in Ruby:

class TestClass
  def initialize(name)
    @name = name
  end
end

How do I then access the instance variable name directly from within the initialize method without creating a getter function? is this even possible? (i.e. using dot notation) or does the initialize method cease to exist once a class is instantiated, hence the need to define a getter method?

I think what I'm trying to ask is initialize a class or instance method?

1
  • 1
    initialize is a private instance method. After assigning the value of name to @name you can refer to @name within initialize. For example, if @name == "Suzie" .... Commented Apr 15, 2019 at 22:53

2 Answers 2

3

The "getter method" is defined so that you can use the variable from outside the class:

class TestClass
  attr_reader :name

  def initialize(name)
    @name = name
  end
end
# TestClass.new('Ben').name  # => 'Ben'

If you don't need to access it from outside the class, you can just use @name:

class TestClass
  def initialize(name)
    @name = name
  end

  def greet
    puts "Hello, %s" % @name
  end
end
# TestClass.new('Ben').greet # outputs: Hello, Ben

You can use the @name inside initialize:

class TestClass
  def initialize(name)
    @name = name
    puts "Name backwards: %s" % @name.reverse
  end
end
# TestClass.new('Ben') # outputs neB

Initialize is a special method, when you define initialize instance method, it is automatically marked private. The class method new calls it after creating an instance of your class.

Nothing stops you from calling private methods from inside the class:

class TestClass
  def initialize(name)
    @name = name
    puts "Name is now %s" % @name
  end

  def flip_name
    initialize(@name.reverse)
  end
end
# t = TestClass.new('Ben') # outputs "Name is now Ben"
# t.flip_name # outputs "Name is now neB"
# t.instance_variable_get(:@name) # => 'neB'

The flip_name method that calls initialize works just fine, but of course this is quite unconventional and almost never used, because it does not make much sense.

It's possible to call private methods from outside the class using send:

# t.send(:initialize, 'Bill') # outputs "Name is now Bill"
# t.instance_variable_get(:@name) # => 'Bill'

Without send, you get NoMethodError:

> t.initialize('Jack')
NoMethodError: private method `initialize' called for #<TestClass:0x00007fa2df8e4570>

Ruby 1.9 beta releases changed send to act like public_send does today, allowing access to only public methods and there was going to be funccall for calling private methods if you really want to, for unit testing purposes for example. I think it caused too much compatibility issues and the change was reverted.

So in conclusion, yes, you can call initialize again and it does not cease to exist, but it is almost never done because it makes very little sense. To access instance variables from inside the class, you use @ notation like @name, to access them from outside of the class, you define a getter.

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

2 Comments

Thanks for your extremely thorough and brilliant answer Kimmo. Could I just ask for additional context around 'why' the send method is required/necessary to access a private instance method such as initialize? I know you receive a NoMethodError otherwise, but could you explain what send method does that allows you to access the initialize method from outside the class. Thanks.
Ruby 1.9 was going to make send act like public_send which only allows access to public methods, there was supposed to be funccall for calling private methods if you really want to (for unit testing purposes perhaps?). I don't know why it was left that way.
3

Yes, there is a way. But it's not a traditional one. It's more like querying the object to know

TestClass.new("foo").instance_variable_get(:@name)
=> "foo"

The initialize method does not "cease to exsist". It's executed, that's it. What your method do, in your case, is that the variable is set.

6 Comments

I think the OP is just looking for @name.
I'm not sure @CarySwoveland. Let's see what the OP says
You can't call initialize directly. It's a special method. It's called when you call new on a class.
The initialize method doesn't even have a return value
@Ursus you can return from initialize, but the return value is not used for anything normally. send(:initialize) or calling it from inside the class will give the return value like any method.
|

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.