Hey guys I am new to Ruby. I have a question: Do methods have to be always inside classes?
Technically they are aways defined inside a class, but this doesn't mean you always need to open a class to define a method.
Here is what might look like a top-level function in other languages:
def foo
puts self
puts self.class
end
If we simply call foo, we'll get:
main
Object
This actually defined a private instance method in the Object class. We see that self in the top-level scope is a special object called main.
On the other hand, we can try to call this method on other stuff:
'bar'.foo #!> private method `foo' called for "bar":String (NoMethodError)
This errorred out as foo is private. We can use a special method called send to invoke private methods:
'bar'.send :foo
Gets us:
bar
String
We can also define methods in the so-called singleton classes. You can think of them as classes with only a single instance. For example:
foo = 'foo'
def foo.bar
puts 'baz'
end
foo.bar # => baz
'quix'.bar # !> undefined method `bar' for "quix":String
'foo'.bar # !> undefined method `bar' for "foo":String
puts (foo.singleton_class.instance_methods - Object.instance_methods).first
# => bar
Here the bar method was defined on the singleton class of foo. Note that even another string with the same contents is still a difference instance, hence it doesn't have the bar method.
Hey guys I am new to Ruby. I have a question: Do methods have to be always inside classes?
No.
Methods have to be always inside modules. (Class are modules, too.)
Example:
module Foo
def bar; end
end
There is no class here.
Related
This question already has answers here:
Ruby what class gets a method when there is no explicit receiver?
(2 answers)
Closed 7 months ago.
In Ruby every method is assigned to an object (right?). Ruby provides a lot of "built in" methods and gives the ability to the user to create "user defined" methods.
Built in methods are all defined in a class like String, Integer, Array and so on. Built in methods are all invoked placing a dot after an object followed by the method call.
string = "example"
string = string.reverse
However, when I define a method with the syntax
def method_name (args)
#body
end
to which object is this method assigned? And why when I have to call a method that I have defined I don't use the "dot syntax" but I just write its name and pass it some arguments without applying it to an object, like this:
method_name args
In Ruby every method is assigned to an object (right?)
Incorrect. In Ruby, methods are assigned to modules (including classes). When you call a method on an object, Ruby runtime searches for the method along the object's class's ancestor chain (the object's singleton class -> the object's class ->
the superclass -> superclass's superclass -> ... -> BasicObject). If the method is found, it is bound to the object and gets called, otherwise the Ruby runtime searches for a special method called method_missing and bind it to the current object and calls it.
to which object is this method assigned?
It's assigned to the class Object, as a private instance method.
def foo
:foo
end
Object.private_instance_methods.grep(/foo/)
#=> [:foo]
I guess Ruby does this in order to make top-level "functions" look global.
class A
def self.a
foo
end
def a
foo
end
end
A.a #=> :foo
A.new.a #=> :foo
There is top-level object in Ruby -- main
def method_name(args)
# body
end
self
# => main
self.methods.grep(/method_name/)
# => [:method_name]
main is an instance of Object. Any methods defined in main become instance methods of Object
Object.private_instance_methods.grep(/method_name/)
# => [:method_name]
This makes them available everywhere (because all classes are descendants of Object), meaning that we can call the method without a receiver inside classes
For example
def foo
puts "foo"
end
class X
def y
foo
end
end
# will print foo
X.new.y
# will raise private method `foo' called for #<X:0x000055e406a0f060> (NoMethodError)
# to reproduce don't use irb, just usual file
X.new.foo
Read more
What does it mean in the ruby language to create an instance variable outside of a class?
e.g:
def my_method:
#animal = "cat"
end
I've also seen it written outside of a method, like this:
#foo = "bar"
Is this just sugar syntax?
thanks!
what it means to create instance of variable outside class in ruby?
Instance variables have nothing to do with classes. They belong to objects, i.e. instances, that's why they are called "instance" variables.
def my_method
#animal = "cat"
end
This does not create an instance variable. It creates a method named my_method, which when you call it assigns to the instance variable named #animal.
There is nothing special about this. When you call this method, it will assign to the #animal instance variable of whatever object you call this method on, just like any other method that assigns an instance variable.
For example here:
class Foo
def my_method
#animal = 'cat'
end
end
foo = Foo.new
bar = Foo.new
If you call foo.my_method, it will assign to the instance variable #animal of foo, if you call bar.my_method, it will assign to the instance variable #animal of bar.
There is actually nothing different between those two examples as far as the instance variable is concerned.
The only interesting question is "Which class is the method defined in?" But that has nothing to do with instance variables.
Methods defined on the top-level become private instance methods of Object.
#foo = "bar"
Again, this is no different than any other assignment to an instance variable. This assigns to the instance variable named #foo of whatever object self is at the moment.
From an instance variable standpoint, there is absolutely nothing special about this. #foo = 'bar' always means "assign to the instance variable named #foo of whatever object self is at the moment". There is nothing else it can mean.
The only interesting question is: "What is self at this point?" But that has nothing to do with instance variables.
At the top-level, self is always the anonymous object commonly called main in the Ruby community.
is just sugar sintaxe?
No, this is not syntactic sugar for anything. It's just an assignment like any other assignment. There is absolutely nothing special about it.
If you do this on the command line:
% ruby -e "puts self; puts self.class"
main
Object
You'll see at the top-level scope (not inside a class or module), you'll be in the scope of an instance of Object called main.
What you already know about using instance variables and defining methods etc are the same for main as it is for class and module.
class Foo
end
foo_main = Foo.new # create instance of `Foo`
class Foo
self # then, inside scope of class `Foo`
# => Foo
def foo # define instance method for class `Foo`
puts "foo"
end
end
foo_main.foo # calls method on an instance of `Foo`
# => foo
# at the top level, it's as if the Ruby runtime has already done something
# like "Object.new" and then put you "inside" the created instance
my_main = self # inside scope of `main` already
# => main
def bar # define instance method for class `Object`
puts "bar"
end
# below are all equivalent
my_main.bar
self.bar
bar # implied `self` is main, an instance of `Object`
You may have noticed:
inside Foo, self returns Foo, a class
at top-level, self returns main, an instance of class Object
Although it seems like they're two different things, what makes Ruby work the way it does is they're actually the same! More specifically, it's:
inside Foo, self returns Foo, an instance of class Class
at top-level, self returns main, an instance of class Object
I'm trying to understand why I can't call methods defined on the singleton class from within the open class but I can from the actual class.
Can someone explain why the first example fails and the second one doesn't?
class One
class << self
def one; end
one
end
end
NameError (undefined local variable or method 'one' for #<Class:One>)
class Two
class << self
def one; end
end
self.one
end
=> nil
Your example is more confusing than it needs to be. It doesn't require a singleton class at all:
class Foo
def bar; end
bar # NameError
end
Foo.new.bar
Here, we have a class Foo with an instance method bar. A singleton class is still just a class, so this is actually the exact same example as yours.
def without an explicit definee defines an instance method of the closest lexically enclosing class definition, in this case Foo. A message send without an explicit receiver like bar sends the message to self. Inside the class definition body, self is the class itself.
So, def bar defines an instance method in Foo, i.e. a method you can call on instances of Foo.
bar inside the class definition body sends a message to self, which is Foo. Since Foo is not an instance of itself, it does not have a method named bar, ergo, the method call fails.
This works exactly the same with a singleton class, since it is still just a class.
You made the wrong assumption about where the method belongs to, in the first place. The call to the instance method one from inside class context should not succeed. In your first snippet, you try to call method one from the singleton class of the singleton class of One (because it’s called from singleton_class context).
Example with normal class / instance methods to clarify:
class One
def self.one()
puts :class
end
def one
puts :instance
end
one()
end
#⇒ class
So, the expected behavior would be to raise NameError. Now the answer is simple: it raises NameError because this method does not exist.
Suppose I have the following simple class:
class C
p self # => C
def self.foo
puts "foo"
end
def bar
puts "bar"
end
end
p C.foo # => "foo"
p C.bar # => "`<main>': undefined method `bar' for C:Class (NoMethodError)"
I know that self.foo defines foo to be an instance method inside the singleton class of C.
Why does the second method not get defined inside the singleton class of C like the first one? self is still C when this method is defined.
It works similarly to message sends and constant lookup:
The general format of a message send is foo.bar, which sends the message bar to foo. If you leave out foo, the message will be sent to the default receiver (which is self).
The general format of a constant lookup is Foo::Bar, which looks up the constant Bar in the module Foo. If you leave out Foo, the constant will be looked up in the default constant context (or cref).
The general format of a method definition is def foo.bar, which defines the method bar in the singleton class of foo. If you leave out foo, the method will be defined in the default definition context (or default definee):
At the top-level, the default definee is Object. (Also, the methods become private.)
Within a module declaration body, the default definee is self (and not self's singleton class, like you assumed!)
Within a method body, the default definee is the syntactically enclosing module. (Put another way: def doesn't change the default definee.)
instance_eval changes the default definee to the receiver's singleton class
class_eval changes the default definee to the receiver
it's a convention of the ruby language. (conceptually you can think of this like you think about static methods in Java. they are not associated with any instance of the class but with the class itself)
bar is going to be a method on objects instantiated from C.
self.bar is going to be a method on C itself.
What's interesting in Ruby is that C class itself is an object (so the class definition that you can use to build objects is an object itself). That's where the self comes from (i.e. define this on myself vs define this from objects that will be built using me as a blueprint) Read more on this: Ruby craziness: Class vs Object?
given
module Foo
def bar
puts "foobar"
end
end
I can do
String.extend(Foo)
and as a consequence do
String.bar # => "foobar"
Why doesnt this work?:
a = String.new
a.bar # => NoMethodError: undefined method `bar' for "":String
Is it because 'a' is now and instance and .extend only works against class methods? Why does it lose the 'new' functionality I have given String via .extend?
Ruby allows you to add methods from a Module to a Class in two ways: extend and include.
Using the module you gave:
module Foo
def bar
puts "foobar"
end
end
With extend the methods are added as class methods, and can be called directly on the class object itself:
class Bar
extend Foo
end
Bar.bar # => "foobar"
Alternatively, you can call it outside of the class scope:
class Bar
end
Bar.extend Foo
Bar.bar # => "foobar"
include is slightly different. It will add the methods as instance methods. They are only callable on an instance of the class:
class Bar
include Foo
end
Bar.bar # NoMethodError
a = Bar.new
a.bar # => "foobar"
The key difference was that we first had to make an instance a, before we could call the instance method.
As sepp2k noted, extend is can be called on any Object, not just Class objects. For example, you can go:
class Bar
end
a = Bar.new
a.extend Foo
a.bar # => "foobar"
However, bar will only be added to the single instance a. If we create a new instance, it you will not be able to call it.
b = Bar.new
b.bar # => MethodNotFoundError
In Ruby, class String is an object, and by doing String.extend(Foo), you create a singleton class for the String class object and include the module Foo in it (that means that you are adding class methods to the String class object, and so can call String.bar). Full stop.
a.bar doesn't work because there's no instance method bar.
No, you haven't given new to String via extend.
The Object#extend method adds to the receiver the methods defined by the argument module.
You have to remember that the String class is itself an object (of type Class) and so when you call "extend" with it as the receiver, that class object (String) itself gets the new method.
So in your first example, String.extend(Foo), adds to the String class instance the function "bar". That is, "bar" is now an instance method of the shadow class (aka Singleton class), so the object String (which is a class) now has the method "bar". This has roughly the same effect as adding a class method to the String class (e.g. def String.bar; puts 'foobar'; end), so it has no effect on instances of type String.