2

Hey guys I am new to Ruby. I have a question: Do methods have to be always inside classes?

mantot123
  • 103
  • 1
  • 5
  • @greenhunt2003 : You **are** always in some class, even if you don't define one explicitly. You can see this by i.e. running `ruby -e 'puts self.class'`. – user1934428 Jul 21 '20 at 08:21
  • 2
    @user1934428 nitpicking, but: you are always in the context of an object. That object doesn't have to be a class. (`main` is an instance of `Object`, not `Class`) – Stefan Jul 21 '20 at 08:29
  • @Stefan : Absolutely correct! Thanks for pointing it out. The same applies if we explicitly [add a method to an instance of some class](https://stackoverflow.com/questions/1887845/add-method-to-an-instanced-object). – user1934428 Jul 21 '20 at 08:42
  • 2
    @Stefan: More nitpicking: There are *three* different implicit contexts in Ruby. For the purposes of method *lookup* (and a couple of other things such as ivar lookup), you are indeed always in the context of an *object*. But for the purposes of method *definition*, you are always in the context of a *module*. And for the purposes of constant lookup, you are always in the context of … whatever you want to call what constants are looked up in. And then of course, there is local variable lookup, where you are always in the context of a *lexical scope*. – Jörg W Mittag Jul 21 '20 at 10:35
  • @JörgWMittag: It's always a pleasure to read your comments. Have you ever thought of writing a book in general, and a Ruby book in particular? – Eric Duminil Jul 21 '20 at 21:01

2 Answers2

2

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.

ndnenkov
  • 35,425
  • 9
  • 72
  • 104
  • 2
    A more common example is a _class method_, e.g. `def String.foo` – it's also just an instance method created in the class' singleton class. – Stefan Jul 21 '20 at 08:34
  • @Stefan yep, that's the best example and also it says that there is no true class methods in Ruby as in other languages as it always bound to an object. – Rajagopalan Jul 21 '20 at 09:00
  • https://ruby-doc.org/core-2.7.1/Kernel.html#method-i-puts isn't defined in a class, though. See Jörg's answer. – Eric Duminil Jul 21 '20 at 10:42
2

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.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653