Meaning of self keyword in ruby [duplicate] - ruby

From what I understand about self, it refers to the current instance of the class.
Isn't this the default behaviour at all times anyways? For example, isn't
self.var_one = method(args)
equivalent to
var_one = method(args)
If so, what is the use of self?

There are several important uses, most of which are basically to disambiguate between instance methods, class methods, and variables.
First, this is the best way to define class methods:
class Foo
def self.bar
"class method bar"
end
def bar
"instance method bar"
end
end
Foo.bar #returns "class method bar"
foo = Foo.new
foo.bar #returns "instance method bar"
Also, within instance methods self refers to the instance, within class methods it refers to the class, and it can always be used to distinguish from local variables.
class Bar
def self.foo
"foo!"
end
def baz
"baz!"
end
def self.success
foo #looks for variable foo, doesn't find one, looks for class method foo, finds it, returns "foo!"
end
def self.fail
baz #looks for variable baz, doesn't find one, looks for class method baz, doesn't find one, raises exception
end
def instance_success
baz #looks for variable baz, doesn't find one, looks for instance method baz, finds it, returns "baz!"
end
def instance_fail
foo #looks for variable foo, doesn't find one, looks for instance method foo, doesn't find one, raises exception
end
def local_variable
baz = "is my favorite method"
baz #looks for variable baz, finds it, returns "is my favorite method"
end
def disambiguate
baz = " is my favorite method"
self.baz + baz #looks for instance method baz, finds it, looks for local variable baz, finds it, returns "baz! is my favorite method"
end
end
So, in the end, you can avoid using self in many cases, but it's often helpful to use it to make sure that you don't inadvertently create naming conflicts later on. Sometimes those can create bugs that are very hard to find. In the end it's often a matter of personal style.
As noted in the comments, one more really important thing:
In a class, if you have a method like this:
def bar=(string)
...
end
And in another method you call:
def other_method
bar = "abcd"
end
It isn't going to call your bar= method, it's going to create a local variable bar. So, in this case you use self to tell Ruby not to create a local variable:
def other_method
self.bar = "abcd"
end
The same thing applies if you want to take an argument with the name of a method:
def example
...
end
def other_thing(example)
self.example(example)
end
If you left off self Ruby would assume you meant the local variable with the same name.
So, in general, self in method names is used to distinguish between class and instance variables, and everywhere else you use it when Ruby needs help distinguishing between method calls and local variables or local variable assignment.
I hope that makes sense.

In most cases self.foo is indeed redundant because you can just write foo for the same effect, but in this case it is not and the self is required.
var_one = method(args) will create a local variable called var_one, it will not call any method or do anything else to self.
self.var_one = method(args) will call the method var_one= on self with the argument method(args).
Another case where the use of self is non-optional would be if you want to pass it as an argument to a method, i.e. some_method(self) - you can't do that without the self keyword.

One other use of self is to declare class methods (similar to static methods in Java).
class foo
def self.bar
#do class related stuff here
end
end
That being said, you could also have used def foo.bar instead for the method signature.

Here's an example:
def run miles
self.miles = miles
end
In this case self will help. In most cases self is redundant.

Related

Namespace collision with top-level methods

I have the following Ruby namespace problem:
I have a number of top-level methods in a "library", among these I have a get_name(param) method.
The problem is that I want to use this get_name(param) method inside a class that has its own get_name() method (without param!).
Of course this results in a problem as the 2 methods are different and the new one in the class overrides the top-level one.
Is there a way to do something like this:
def get_name(param)
puts param
end
class Foo
def get_name()
puts "name"
end
def bar()
self.get_name() #should work and print name, i.e. it uses the get_name method of Foo
get_name("abc") #should work and print abc, i.e. it uses the top-level method
end
end
I would like to know if there is an easy way to achieve this without having to alter the name or scope of the top-level methods. (The goal is to have those available without modification as global methods, but still be able to call instance methods of Foo without errors.
If the library methods are really top-level methods and are not part of any class or module, then, they will get defined as private methods of Object class.
You can do following to invoke it:
def bar()
self.get_name()
Object.send(:get_name, "abc") # Will print "abc" to console
end
The so called "top level method" is only a method of main object, which is only an Object. If you want that method to be able to be called (almost) anywhere, you should make it a kernel method.
module Kernel
def get_name(param)
puts param
end
end
Note that Kernel is almost at the tail of any classes ancestors chain (before BasicObject), which means almost all the objects are a Kernel. So in your Foo class, you can override it like this:
class Foo
def get_name(*args)
return super if args.any?
puts 'name'
end
end
Edit
If you can't make those top level methods kernel methods, you can store the main object in a constant or a global variable, and call those top level methods on it.
$main = self
class Foo
def get_name(*args)
return $main.send(:get_name, *args) if args.any?
puts 'name'
end
end
First off: there is no such thing as a "top-level method". There is exactly one kind of method in Ruby: instance methods.
The method you are referring to is a private instance method of Object. Since Object is a superclass of almost any other class (excluding Object and its superclasses), if you are sure that there are no other methods with the same name somewhere else in the inheritance hierarchy, you could use Method#super_method to get access to the method and then call it:
def get_name(param)
puts param
end
class Foo
def get_name
puts 'name'
end
def bar
get_name #should work and print name, i.e. it uses the get_name method of Foo
method(:get_name).super_method.('abc') #should work and print abc, i.e. it uses the top-level method
end
end
Foo.new.bar
# name
# abc
Alternatively, if you don't know whether there are any other methods by the same name within the inheritance hierarchy, you could grab a reference to the UnboundMethod directly from Object and then bind and call it:
class Foo
def bar
get_name #should work and print name, i.e. it uses the get_name method of Foo
Object.instance_method(:get_name).bind(self).('abc') #should work and print abc, i.e. it uses the top-level method
end
end
Foo.new.bar
# name
# abc

Why are setter methods not used in initialization?

Recently I've been reading "Practical Object Oriented Design in Ruby", and I noticed one of the best practices was to use accessor methods instead of directly grabbing the #instance_variable. For example:
class Foo
attr_accessor :bar
def initialize(my_argument)
#bar = my_argument
end
# bad
# def lorem_ipsum
# #bar * 999
# end
# good
def lorem_ipsum
bar * 999
end
end
It makes sense to keep things DRY, and, in case I need to process #bar somehow before actually grabbing its value. However, I noticed that the initialize method sets the value of the #bar instance variable directly:
class Foo
attr_accessor :bar
def initialize(my_argument)
#bar = my_argument #<-- why isn't self.bar = my_argument used here?
end
Is there a reason for this? Shouldn't the setter method be used instead of directly using the = operator to set the value of the instance variable?
You're right, it would make much more sense to do
class Foo
attr_accessor :bar
def initialize(my_argument)
self.bar = my_argument
end
end
Arguments differ as to whether you should respect encapsulation within the object itself or not, but if you believe in that, then, yes, you should do this.
The initializer SETS the value upon initialization. The accessor lets you access (read/write) via the symbol after the object is already instantiated.
This post might help you understand:
What is attr_accessor in Ruby?
Actually, the setter can be used in initialize the same as in other methods, but setter cannot be used without a receiver.
I think you can use a_foo.bar= or self.bar=, but cannot use bar= without a receiver, because, in the later case, bar will be treated as a local variable rather than a setter method:
class Song
attr_accessor :name
def initialize(name)
self.name = name
end
def test_setter1(value)
#name = value
end
def test_setter2(value)
name = value #name is local variable
end
end
s = Song.new("Mike")
p s
s.test_setter1("John")
p s
s.test_setter2("Rosy")
p s
This results in:
#<Song:0x23a50b8 #name="Mike">
#<Song:0x23a50b8 #name="John">
#<Song:0x23a50b8 #name="John">
While you can use the setter in the initialization as shown in #uncutstone's answer, you cannot use it as you've proposed in the comment in your code.
The problem is that Ruby would interpret:
bar = my_argument
as an assignment to the bar local variable rather than an invocation of the bar= method.
This is discussed rather extensively in "Why do Ruby setters need "self." qualification within the class?".

Ruby initialize and self

I found an interesting problem: http://rubeque.com/problems/fixing-bad-code-the-wrong-way/solutions
Generally we have a simple class (notice that we don't have attr_accessor here):
class Foo
def itnialize(name)
self.foo = name
end
def set_bar
self.bar = 'it will fail..'
end
end
I thought that ruby will raise no method error when I call Foo.new but it passes without any problems. The code will fail when I try Foo.new.bar
How is it possible and how to access Foo.new.foo variable?
You have a typo and have miss-spelt initialize as itnialize so it won't be being called - so no error.
It looks like you're trying to create an instance variable - to do so you need, somewhere, to define it with the # prefix. So you might do:
def initialize(name)
#foo = name
end
which would then mean you are able to access #foo inside the class.
self.foo can only ever refer to a method foo, so you need to define that method if you want to call it, either explicitly or by using one of the attr variants.
However, in this case, you could just do
def set_bar
#bar = 'it will succeed!'
end

When an instance method calls a class method, I have to use self.class_method?

I'm getting an error so I guess I have to reference a class method from inside of an instance method with self.class_method_name, but why is that?
Shouldn't it resolve this by itself? Confused.
def self.blah(string)
..
end
def some_method()
some_thing = blah("hello")
end
If you have
# This won't work
class Foo
def self.blah(string)
puts "self.blah called with a string of #{string}"
end
def some_method
# This won't work
self.blah("hello")
end
end
foo = Foo.new
foo.some_method
It won't work, because it'll look for the instance method Foo#blah. Instead, you're looking for Foo.bar.
To make some_method call Foo.bar, you have to make some_method refer to the Foo class, and then call blah on it.
class Foo
def self.blah(string)
puts "self.blah called with a string of #{string}"
end
def some_method
# This will work
self.class.blah("hello")
end
end
foo = Foo.new
foo.some_method
The reason you have def self.blah to define the method, but self.class.blah to call the method, is that in the former, self refers to the Foo class, while in the latter, self refers to the foo object, so you need self.class to refer to the Foo class.
It may be easier to think of self as part of the method name, that way it's clear that you never defined a blah method, you defined only a self.blah method. (To clarify: the previous sentence shouldn't be thought of too much, so please don't read into it, as it's not how things are actually working, just a sort of "layman's terms" attempt at describing why it doesn't work.)
Also, what if you had defined a blah instance method in addition to the class method? If calling blah was enough to access the class method, how would you call the instance method?
Finally, there really isn't any such thing as a class method in Ruby, "class methods" are really methods of the singleton class.

When to use 'self' in Ruby

This method:
def format_stations_and_date
from_station.titelize! if from_station.respond_to?(:titleize!)
to_station.titleize! if to_station.respond_to?(:titleize!)
if date.respond_to?(:to_date)
date = date.to_date
end
end
Fails with this error when date is nil:
NoMethodError (You have a nil object when you didn't expect it!
The error occurred while evaluating nil.to_date):
app/models/schedule.rb:87:in `format_stations_and_date'
app/controllers/schedules_controller.rb:15:in `show'
However, if I change date = date.to_date to self.date = self.date.to_date, the method works correctly.
What's going on? In general, when do I have to write self?
Edit: It's not related to the question, but please note that there is no "titleize!" method.
Whenever you want to invoke a setter method on self, you have to write self.foo = bar. If you just write foo = bar, the ruby parser recognizes that as a variable assignment and thinks of foo as a local variable from now on. For the parser to realize, that you want to invoke a setter method, and not assign a local variable, you have to write obj.foo = bar, so if the object is self, self.foo = bar
You disambiguiate between the instance method name and a local variable using self (it is allowed to have both with the same name in the same scope). In other words, there will be a method name resolution only if there is no local or block variable of the same name in scope. Behold:
class Foo
attr_accessor :boo
def do_boo
boo = 123
puts "Locvar: #{boo} Method: #{self.boo}"
end
end
Foo.new.do_boo
Here's why: imagine you have a module which implements a method. This method assigns something to it's internal local variable
"foo" which is used for some computation. If you skip the "self" part, the method will make a "foo=" method call on the object
whose class includes the module, which was not the intention of the author and can be downright disastrous.
class Foo
def bar=(new_value_of_bar)
set_off_nukes(new_value_of_bar / 3)
end
end
module InnocentModule # written by a different author elsewhere
def do_useful_stuff
...
bar = Math.sin(something) # we're dead
end
end
Foo.send(:include, InnocentModule)
Another crucial part where you have to use self is when invoking the Object#class method, because simply saying "class" means a class keyword for Ruby.

Resources