Power of Eloquence

Understanding Ruby Self (Part 1)

| Comments

When really working with scripting object-oriented programming languages such as Ruby, I’d find it’s important get yourself grounded in knowing full grasp of the concepts of class and/or object.

To recap these words, basic understanding required behind these two words is this.

In object-oriented programming, a class is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions, methods).

From memory of studying computer science several years ago in Java, I remembered along the lines that an object is an instance of the class. Thus the object carries all the initialization of state information within the classes. Many object-oriented programming languages therefore share this route and Ruby is no different.

But when I began learning Ruby and explored its constructs, I found a number of its surprising aspects which I do not fully comprehend - yet. I found them puzzling(and fascinating at the same time) that - in the Ruby world - everything is an object. Inside Ruby, I find there’s an Object class as well as Class class. Object is the root of the program’s hierachy while Ruby objects are instances of Class class. Yet both of these are still treated as objects?

How can this work?

I looked up the keyword ‘self’ and it’s said to grant you the access to the current object. The object that is receiving the current message. With this, Ruby is sending a message to the receiver of the object. So if you open up your irb console, you type the following.

Top Level Scope

2.1.2 :001 > self
=> main

This tells me there’s already a current Ruby object instance running at the top level scope, so when I rewrite it like so..

def top_level_self
   self
end

puts top_level_self
=> main

It produces the same output as the previous code block - because the top_level_self is already at the top-most level of the scope within the running thread of the program. Therefore any methods written/read outside of the code block will use default top-level scope object as the main receiver.

We have the class below.

class KnowMyselfBetter

    attr_accessor :myname

    def self
        @myname
    end

    def self.myname
        @myname
    end

    def self.myname=(some_name)
        @myname = some_name
    end

    def self.default_name
        self.myname = "class_type_name"
    end

    def default_name
        self.myname = "instance_type_name"
    end

end

You will see the following output.

puts KnowMyselfBetter.myname #=> (no name)

puts KnowMyselfBetter.default_name #=> class_type_name

puts KnowMyselfBetter.myname #=> now says 'class_type_name'

#Now make a new instance of KnowMyselfBetter class
m = KnowMyselfBetter.new

puts m.myname #=> (no name)

puts m.default_name #=> instance_type_name

puts m.myname #=> now says 'instance_type_name' as expected

So reading this far, on the surface, it looks though this is just another example of writing your instance methods and class methods in Ruby, much like how you do with other similar languages as like Java - using static keyword I used to do in Java, for eg.

public class KnowsMyselfBetter {

    private static String myname;

    public static String getMyName(){
        return myname;
    }

    public static String setMyName(nameValue){
        myname = nameValue;
    }

}

KnowMyselfBetter.getMyName()

KnowMyselfBetter.setMyName("Ruby")

But that’s not really so! As it turns out, Java’s static keyword has no bearing to what Ruby does with its self keyword because static languages like Java is used for making your methods behaving statically when gets dispatched during the runtime and will stay that way during its programming operating lifecycle. Ruby’s a dynamic language as well as being object-oriented language as it is, it’s more interested in creating objects dynamically in the runtime - this includes instance methods as well. By its very nature, it’s entitled to do so.

Thus, self is about the current context of the object’s scope, and will always change in any state of the program’s scope depending on how’s to be used.

So that begs the next question - How are they exactly used and what are their main purposes?

We’ll find them out in our next post, and identify their use cases.

Comments