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
Related
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.
Some classes like Integer able to create a instance by
Integer(1) #=> 1
It seems the class name works as method name.
How can I create a method like this and when should I use it instead of define a initialize method?
Integer is a Kernel method. In fact, it is defined as Kernel.Integer.
You can simply create a new method that acts as initializer for your custom class:
class Foo
def initialize(arg)
#arg = arg
end
end
def Foo(arg)
Foo.new(arg)
end
Foo("hello")
# => #<Foo:0x007fa7140a0e20 #arg="hello">
However, you should avoid to pollute the main namespace with such methods. Integer (and a few others) exists because the Integer class has no initializer.
Integer.new(1)
# => NoMethodError: undefined method `new' for Integer:Class
Integer can be considered a factory method: it attempts to convert the input into an Integer, and returns the most appropriate concrete class:
Integer(1).class
# => Fixnum
Integer(1000 ** 1000).class
# => Bignum
Unless you have a real reason to create a similar initializer, I'd just avoid it. You can easily create static methods attached to your class that converts the input into an instance.
It’s not a class, it’s a method (Kernel#Integer) that begins with a capital letter.
def Foo(x = 1)
"bar to the #{x}!"
end
Foo(10) #=> "bar to the 10!"
It can co-exist with a constant of the same name as well:
module Foo; end
Foo.new #=> #<Foo:0x007ffcdb5151f0>
Foo() #=> "bar to the 1!"
Generally, though, it’s thought that creating methods that begin with a capital letter is a bad idea and confusing.
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.
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.
In this example from The Ruby Programming Language (p.270), I'm confused why the instance_eval method on the last line of the sample code defines a class method called String.empty.
Don't you use class_eval to define a class method and instance_eval when you want to define an instance method?
o.instance_eval("#x") # Return the value of o's instance variable #x
# Define an instance method len of String to return string length
String.class_eval("def len; size; end")
# Here's another way to do that
# The quoted code behaves just as if it was inside "class String" and "end"
String.class_eval("alias len size")
# Use instance_eval to define class method String.empty
# Note that quotes within quotes get a little tricky...
String.instance_eval("def empty; ''; end")
Don't you use class_eval to define a
class method and instance_eval when
you want to define an instance method?
Unfortunately, it is not as straightforward as that.
First take a closer look at what the examples of class_eval are doing. class_eval is a method which comes from Ruby's module class so can be called on any class or module. When you use String.class_eval you are evaluating the given code in the context of the class. i.e. when you write String.class_eval("def len; size; end") it's exactly like you reopened the class and typed the code passed to class_eval e.g.
class String
def len
size
end
end
Thus to add a class method using class_eval you would write String.class_eval("def self.empty; ''; end") which has the same effect as:
class String
def self.empty
''
end
end
instance_eval is defined in Ruby's Object class so is available on any Ruby object. In the general case it can be used to add a method to a specific instance. e.g. if we have a String str and say:
str.instance_eval("def special; size; end")
Then this will alias special to size just for str but not for any other String object:
irb(main):019:0> "other".special
NoMethodError: undefined method `special' for "other":String
from (irb):19
To understand what is going on with String.instance_eval remember that the class String is itself an object (an instance of the class Class) and that there is such a singleton instance object of every class defined. When you use String.instance_eval you are evaluating the given code in the context of the String instance object. i.e. it is equivalent to reopening String's metaclass and typing the code passed e.g.
class String
class << self
def empty
''
end
end
end
This is the general theme:
Use ClassName.instance_eval to define
singleton methods.
Use ClassName.class_eval to define
instance methods.
This post has a very neat explanation, give it a shot...