Home > Software design >  In Ruby how does it work when passing "self" when initialising a class?
In Ruby how does it work when passing "self" when initialising a class?

Time:12-09

I've come across the following solution to a problem and am struggling to understand the attach_tail! method. How exactly does this Knot.new(self) work? In a general sense, what does it to do pass self when you create a new instance of the class?

The idea of the programme is more extensive than this and essentially is about the head of a 'knot' moving around a grid and being followed by the tail with more methods inside the class that i havent included.

class Knot
  attr_reader :x, :y, :head, :tail

  def initialize(head=nil)
    @x = @y = 0     # Position at the start is 0,0
    @head = head    # Head is passed, but the default is nil
    @tail = nil     # Tail is nil to begin with
  end

  def attach_tail!
    @tail = Knot.new(self)   # Tail can then be added
  end

  def location = [x, y]
end

CodePudding user response:

There is nothing special about self nor about "initializing a class" here.

new is a method like any other method, and the object referenced by self is an object like any other object.

Instead of

Knot.new(self)

It could be

Knot.new(baz)

or

foo.bar(self)

or

foo.bar(baz)

You are simply calling a method on an object and passing another object as an argument. That's it.

CodePudding user response:

It might be easier to see this from the outside.

For demonstration purposes, let's briefly change attr_reader to attr_accessor in order to make all attributes settable from the outside:

class Knot
  attr_accessor :x, :y, :head, :tail

  # ...
end

With the above and a given knot a:

a = Knot.new

we could attach a tail to a via:

a.tail = Knot.new(a)

Knot.new(a) creates a new knot with a as its head. It then assigns that new knot to the tail of a.

Now, if you wanted to move that assignment from outside the object into the object, a would have to somehow pass itself as an argument to Knot.new. And this is exactly what self does – within instance methods, self refers to the current instance.

Outside a:

a.tail = Knot.new(a)

Inside a:

self.tail = Knot.new(self)

And without the tail= accessor, we'd assign to the instance variable directly:

@tail = Knot.new(self)

Which is exactly what attach_tail! does.

  • Related