Ruby's class expression---how is it different from `Class.new`? [duplicate] - ruby

What is difference between class and Class.new & module and Module.new?
I know that:
Class.new/Module.new create an anonymous class/module. When we assign it to constant for the first time it becomes name of that class/module. class/module do this automatically.
When we want to inherit, we can pass an argument: Class.new(ancestor). When we don't specify an ancestor, it is set to the Object. class use this syntax: class A < Ancestor
Class.new returns an object. class A returns nil. Same goes for modules.
Did I miss something?

The interesting point that you missed between class keyword and Class::new is - Class::new accepts block. So when you will be creating a class object using Class::new you can also access to the surrounding variables. Because block is closure. But this is not possible, when you will be creating a class using the keyword class. Because class creates a brand new scope which has no knowledge about the outside world. Let me give you some examples.
Here I am creating a class using keyword class :
count = 2
class Foo
puts count
end
# undefined local variable or method `count' for Foo:Class (NameError)
Here one using Class.new :
count = 2
Foo = Class.new do |c|
puts count
end
# >> 2
The same difference goes with keyword module and Module::new.

Class.new returns an object. class A returns nil. Same goes for modules.
That's wrong. A class/module definition returns the value of the last expression evaluated inside of the class/module body:
class Foo
42
end
# => 42
Typically, the last expression evaluated inside of a class/module body will be a method definition expression, which in current versions of Ruby returns a Symbol denoting the name of the method:
class Foo
def bar; end
end
# => :bar
In older versions of Ruby, the return value of a method definition expression was implementation-defined. Rubinius returned a CompiledMethod object for the method in question, whereas YARV and most others simply returned nil.

Related

To which object are top-level methods assigned in Ruby? [duplicate]

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

Why do I get an undefined local variable or method error when using a constant, but not when using a method?

How come if I have a class like:
class Thing
def number
10
end
end
And I inherit from it like this:
class OtherThing < Thing
CONSTANT = number / 2
end
I get undefined local variable or method 'number' when I try to instantiate the class, but if I do this:
class OtherThing < Thing
def method_instead_of_constant
number / 2
end
end
It works?
EDIT
I'm not necessarily looking for a hack to make this work, but an understanding as to why it doesn't. mudasobwa's answer below helped the most; constants are assigned at the class level, not on instances.
You need a class method to achieve the functionality you are looking for:
class Thing
# ⇓⇓⇓⇓ HERE
def self.number
10
end
end
class OtherThing < Thing
CONSTANT = number / 2
end
CONSTANT assignment is happening on the class level, hence it has an access to class methods of Thing, but not to the instance methods of it.
On the other hand, you might instantiate Thing and then call the instance method on it:
class Thing
def number
10
end
end
class OtherThing < Thing
# ⇓⇓⇓⇓⇓⇓⇓⇓⇓ HERE
CONSTANT = Thing.new.number / 2
end
Because number is an instance method on Thing. The scope of the class definition of OtherThing is an instance of Class, which means it isn't an instance of Thing or an instance of OtherThing at definition.
That said, you shouldn't be defining constants by executing methods. You could presumably have a calculated class variable that you call freeze on to prevent editing post-startup, but even that's not a very common pattern.
Because of scope.
Methods calls are evaluated based on the dynamic scope and distinguish between class and instance scope. Constants are resolved in lexical scope and do not distinguish between class and instance scope like methods do.
class A
# expressions are evaluated in scope of class A
def m
# expressions are evaluated in scope of an instance of A
return 42
end
end
Class and instance are not the same.
A
a = A.new
A.class # => Class
a.class # => A
A.respond_to?(:m) # => false
a.respond_to?(:m) # => true
A.m # => raises NoMethodError
a.m # => 42
Hence in the class body you cannot call instance methods.
Constants however are looked up using lexical scope, that is the surrounding context of classes and modules in the source file.
module M
# can access global constants and those defined in M
class A
# can access global constants and those defined in M or A
def m
# can access global constants and those defined in M or A
end
end
end
You can inspect the current constant lookup path with Module.nesting
I'm not necessarily looking for a hack to make this work, but and [sic]
understanding as to why it doesn't.
Here's the error message:
undefined local variable or method 'number'
When the Ruby interpreter sees number it looks for a local variable or a method named number. In the context of a method, the interpreter reads number as self.number. So this line:
CONSTANT = number / 2
is actually considered as:
CONSTANT = self.number / 2
So what's self?
Well that depends on where you've defined it (explicitly or implicitly). Within a class block, self is the class itself i.e. OtherThing. Since OtherThing nor any of its ancestors has a class-method number defined, nor does there exist a variable number, Ruby throws the error message.
self defined within an instance method definition is the current object. But this is awfully abstract without examples and some more theory. Other relevant topics are Singleton-Classes and Inheritance. If you like books, then I recommend The Well-Grounded Rubyist 2nd Ed, Chapter 5 by David A. Black. On second thoughts, read/study the whole book.

Local variables in `class` definition scope versus `def` method scope

Here, I create a local variable in class scope:
class MyClass
x = 1
puts x
end
It prints 1 even if I don't create any instances of MyClass.
I want to use x in some method:
class MyClass
x = 1
def method
puts x
end
end
m = MyClass.new
m.method
And I can't. Why? I get that class definition creates a scope, but why is it not accessible in the method? Isn't scope of the method inside the scope of the class?
I can imagine that this is related to creation of a class. Since any class is an object of Class, maybe the scope of MyClass is the scope of some Class method, and the way of coupling methods of MyClass to that instance makes their scope completely different.
It also seems to me that I can't just create a scope with {} (like in C) or something like do..end. Am I correct?
Scope of a method is not inside the class. Each method has its own entirely new scope.
New scopes are created whenever you use the class, module, and def keywords. Using brackets, as in C, does not create a new scope, and in fact you cannot arbitrarily group lines of code using brackets. The brackets (or do...end) around a Ruby block create a block-level scope, where variables previously created in the surrounding scope are available, but variables created within the block scope do not escape into the surrounding scope afterward.
Instance methods share the scope of their instance variables with other instances methods. An instance variable defined in the scope of a class definition is available in class-level singleton methods, but not in instance methods of the class.
Illustration:
class Foo
x = 1 # available only here
#y = 2 # class-wide value
def self.class_x
#x # never set; nil value
end
def self.class_y
#y # class-wide value
end
def initialize(z)
x = 3 # available only here
#z = z # value for this instance only
end
def instance_x
#x # never set; nil
end
def instance_y
#y # never set; nil
end
def instance_z
#z # value for this instance only
end
end
Foo.class_x # => nil
Foo.class_y # => 2
Foo.new(0).instance_x # => nil
Foo.new(0).instance_y # => nil
foo3 = Foo.new(3)
foo4 = Foo.new(4)
foo3.instance_z # => 3
foo4.instance_z # => 4
You can access class-level instance variables from within instances using the class-level getter. Continuing the example above:
class Foo
def get_class_y
self.class.class_y
end
end
foo = Foo.new(0)
foo.get_class_y # => 2
There exists in Ruby the notion of a "class variable," which uses the ## sigil. In practice, there is almost never a reasonable use case for this language construct. Typically the goal can be better achieved using a class-level instance variable, as shown here.
Here, I create a local variable in class scope:
class MyClass
x = 1
puts x
end
It prints 1 even if I don't create any instances of MyClass.
Correct. The class definition body is executed when it is read. It's just code like any other code, there is nothing special about class definition bodies.
Ask yourself: how would methods like attr_reader/attr_writer/attr_accessor, alias_method, public/protected/private work otherwise? Heck, how would def work otherwise if it didn't get executed when the class is defined? (After all, def is just an expression like any other expression!)
That's why you can do stuff like this:
class FileReader
if operating_system == :windows
def blah; end
else
def blubb; end
end
end
I want to use x in some method:
class MyClass
x = 1
def method
puts x
end
end
m = MyClass.new
m.method
And I can't. Why? I get that class definition creates a scope, but why is it not accessible in the method? Isn't scope of the method inside the scope of the class?
No, it is not. There are 4 scopes in Ruby: script scope, module/class definition scope, method definition scope, and block/lambda scope. Only blocks/lambdas nest, all the others create new scopes.
I can imagine that this is related to creation of a class. Since any class is an object of Class, maybe the scope of MyClass is the scope of some Class method, and the way of coupling methods of MyClass to that instance makes their scope completely different.
Honestly, I don't fully understand what you are saying, but no, class definition scope is not method definition scope, class definition scope is class definition scope, and method definition scope is method definition scope.
It also seems to me that I can't just create a scope with {} (like in C) or something like do..end. Am I correct?
Like I said above: there are 4 scopes in Ruby. There is nothing like block scope in C. (The Ruby concept of "block" is something completely different than the C concept of "block.") The closest thing you can get is a JavaScript-inspired immediately-invoked lambda-literal, something like this:
foo = 1
-> {
bar = 2
foo + bar
}.()
# => 3
bar
# NameError
In general, that is not necessary in Ruby. In well-factored code, methods will be so small, that keeping track of local variables and their scopes and lifetimes is really not a big deal.
So just creating a class without any instances will lead to something
actually executing in runtime (even allocating may be)? That is very
not like C++. –
Check out this code:
Dog = Class.new do
attr_accessor :name
def initialize(name)
#name = name
end
end
If you execute that code, there won't be any output, but something still happened. For instance, a global variable named Dog was created, and it has a value. Here's the proof:
Dog = Class.new do
attr_accessor :name
def initialize(name)
#name = name
end
end
dog = Dog.new("Ralph")
puts dog.name
--output:--
Ralph
The assignment to the Dog constant above is equivalent to writing:
class Dog
...
...
end
And, in fact, ruby steps through each line inside the class definition and executes each line--unless the line of code is inside a def. The def is created but the code inside a def doesn't execute until the def is called.
A very common line you will see inside a class definition is:
attr_accessor :name
...which can be rewritten as:
attr_accessor(:name)
...which makes it obvious that it's a method call. Ruby executes that line--and calls the method--when you run a file containing the class definition. The attr_accessor method then dynamically creates and inserts a getter and a setter method into the class. At runtime. Yeah, this ain't C++ land anymore--welcome to NeverNever Land.
I get that class definition creates a scope, but why is it not
accessible in the method?
Because that is the way Matz decided things should be: a def creates a new scope, blocking visibility of variables outside the def. However, there are ways to open up the scope gates, so to speak: blocks can see the variables defined in the surrounding scope. Check out define_method():
class MyClass
x = 1
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
The block is everything between do...end. In ruby, a block is a closure, which means that when a block is created, it captures the variables in the surrounding scope, and carries those variables with it until the the block is executed. A block is like an anonymous function, which gets passed to a method as an argument.
Note that if you use the Class.new trick, you can open two scope gates:
x = 1
MyClass = Class.new do
define_method(:do_stuff) do
puts x
end
end
m = MyClass.new
m.do_stuff
--output:--
1
Generally, ruby allows a programmer to do whatever they want, rules be damned.

Difference between creating a Class regularly and using Class.new

I can create a class using a constant name with class keyword:
class MyClass1; end
I can also create a class with Class.new and assign that to a constant or a variable:
MyClass2 = Class.new do; end
myClass3 = Class.new do; end
but I cannot create a class using class keyword with a name that begins in lowercase:
class myclass4; end # => Error
Is there a fundamental difference between these four? Isn't myclass3 a regular class?
The first method (class MyClass; end) is an explicit part of the language syntax (in that class is a keyword), and the class’s name must be a constant.
The second method (Class.new) is just a normal method call, and returns an anonymous instance of Class. This anonymous instance can then be treated like any other object.
Other than that, there are no differences between the two methods. Note that you can still assign the first type into a non-constant, but it must also first be assigned into a constant:
class MyClass; end
my_class = MyClass
Similar to Andrew Marshall's answer, but also different.
Think of it this way:
The class Foo ... syntax does more than defining a class; in addition to defining a class, it necessarily names it when called for the first time, and a class name must be a constant. Note that, in principle, a class can be nameless (see #3).
On the other hand, assignment can be done to a variable or a constant. There is no restriction to that.
A purer way to create a class is to use Class.new. Using this syntax, you do not have to name it. So it is okay to assign it to a variable:
foo = Class.new
# => #<Class:0x007f36b23159a8>
Only when it is assigned to a constant for the first time does it get named:
Foo = foo
# => Foo

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