Is there a way to count the amount of instances that get created as long as the program is running?
Something like
class Foo
#bar = 0
def initialize
#bar += 1
end
end
won't work (#bar is nil in initialize).
Can this be done somehow?
You should use a class variable instead of an instance variable:
class Foo
##count = 0
def initialize
##count += 1
end
def Foo.get_count
##count
end
end
foo1 = Foo.new
foo2 = Foo.new
foo3 = Foo.new
puts Foo.get_count
# => 3
Instance variables belong to objects (aka instances), that's why they are called instance variables after all. Your first #bar is an instance variable of Foo, your second #bar is an instance variable of the newly-created instance of Foo. Those are two completely different objects (they aren't even of the same class: the newly-created instance is of class Foo, whereas Foo is of class Class).
You obviously need to increment #bar in a method called on Foo, not in a method called on instances of Foo. So, can we think about a method that is a) called on Foo and b) called everytime an instance is created? What about new?
class Foo
#bar = 0
def self.new(*)
#bar += 1
super
end
end
Okay, technically speaking, this doesn't count the number of instances, only the number of times new was called. Sometimes, instances get created without calling new, e.g. when de-serializing. This should be the closest you can get without resorting to ugly hacks of the interpreter internals.
You might think you can override allocate instead (I thought so, too), but I just tested it and it doesn't work. Presumably, the default implementation of new doesn't call allocate via normal means but actually uses the interpreter internal implementation directly.
Related
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.
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.
I am trying to figure out if it is possible to pass a value between methods in a Ruby class.
I haven't found much on my own and figured I would ask the experts. Could it be done passed as a arg/parameter to another method as well?
class PassingValues
def initialize
#foo = 1
end
def one
#foo += 1
end
def two
#foo += 1
end
def three
p #foo
end
end
bar = PassingValues.new
If I wanted this to print out foo value of 3:
bar.three
If you want bar.three to print a 3 you will need to call before the one and two methods to ensure the variable is updated to the three so:
class PassingValues
def initialize
#foo = 1
end
def one
#foo += 1
end
def two
one
#foo += 1
end
def three
two
p #foo
end
end
Anyway this doesn't make sense as long as the methods will be eventually modifying the variable, so each time you call one of them the number will increase the amount expected.
Those are instance methods, not class methods. And #foo is already shared among them.
bar = PassingValues.new
bar.one
bar.two
bar.three
In this case #foo is an instance variable and it can be referenced (it is not passed here) in any method of the class.
When you call you create bar as an instance of the class using: PassingValues.new
it is initialized, and sets #foo to 1.
When you then call the method three using bar.three, you simply print out #foo, which is still equal to 1.
You can change your three method to increment #foo by 2, so it is now equal to 3, then print:
def three
#foo += 2
p #foo
end
I have a class, Foo. I want to be able to pass the constructor a Foo instance, foo and get the same instance back out.
In other words, I want this test to pass:
class Foo; end
foo = Foo.new
bar = Foo.new(foo)
assert_equal foo, bar
Anyone know how I can do that? I tried this:
class Foo
def initialize(arg = nil)
return arg if arg
end
end
foo = Foo.new
bar = Foo.new(foo)
assert_equal foo, bar # => fails
but it doesn't work.
Help?
EDIT
Because a number of people have asked for my rationale:
I'm doing rapid analysis of lots of data (many TB) and I am going to have a lot of instances of a lot of objects. For some of these objects, it doesn't make sense to have two different instances with the same data. For example, one such object is a "window" (as in temporal window) object that has two properties: start time and end time. I want to be able to use the constructor in any of these ways and get a window object back:
window = Window.new(time_a, time_b)
window = Window.new([time_a, time_b])
window = Window.new(seconds_since_epoch_a, seconds_since_epoch_b)
window = Window.new(window_obj)
window = Window.new(end => time_b, start => time_a)
...
Some other object that needs a window might be instantiated this way:
obj = SomeObj.new(data => my_data, window => window_arg)
I don't necessarily know what's in window_arg, and I don't really care -- it will accept any single argument that can be interpreted by the Window constructor. In the case of already having a Window instance, I'd rather just use that instance. But the job of interpreting that seems like a concern of the Window constructor. Anyway, as I mentioned I'm churning through many TB of data and creating lots of instances of things. If a window object gets passed around, I want it just to be recognized as a window object and used.
By definition, constructors are meant to return a newly created object of the class they are a member of, so, no you should not override this behavior.
Besides, in Ruby, new calls initialize somewhere within its method body, and its return value is ignored, so either way the value you return from initialize will not be returned from new.
With that said, I think that in your case, you might want to create a factory method that will return different Foo objects based on arguments passed to the factory method:
class Foo
def self.factory(arg = nil)
return arg if arg.kind_of? Foo
Foo.new
end
end
foo = Foo.factory
bar = Foo.factory(foo)
assert_equal foo, bar #passes
def Foo.new(arg=nil)
arg || super
end
initialize is called by new which ignores its return value. Basically the default new method looks like this (except that it's implemented in C, not in ruby):
class Class
def new(*args, &blk)
o = allocate
o.send(:initialize, *args, &blk)
o
end
end
So the newly allocated object is returned either way, no matter what you do in initialize. The only way to change that is overriding the new method, for example like this:
class Foo
def self.new(arg=nil)
if arg
return arg
else
super
end
end
end
However I'd strongly advise against this since it runs counter to many expectations that people have when calling new:
People expect new to return a new object. I mean it's even called new. If you want a method that does not always create a new object, you should probably call it something else.
At the very least people expect Foo.new to return a Foo object. Your code will return whatever the argument is. I.e. Foo.new(42) would return 42, an Integer, not a Foo object. So if you're going to do this, you should at the very least only return the given object, if it is a Foo object.
Does not work for:
class Some
def self.new( str )
SomeMore.new( str )
end
end
# the Some is parent of SomeMore
class SomeMore < Some
def initialize( str )
#str = str
end
end
For this particular use case, it might be better to use one of these approaches.
class Foo
def self.new(args=nil)
##obj ||= super(args)
end
end
class Foo
def self.new(args)
##obj = super(args)
end
def self.new
##obj
end
end
This allows you to have only a single object that gets created that can be used universally, but returns an object of the Foo class, making it fall more inline with standard expectations of a new method, as Jacob pointed out.
Class A
def foo
do s.t
end
end
class B
def initialize
#bar = Thread::new{
A::new
}
#Here I want to call A.foo in the thread #bar
end
end
bar = B::new
I want to start a new thread with the class A. How can I call the method foo from class B?
I think you are confused about your problem. Firstly, you say
I want to start a new thread with the class A
but it is unclear what you mean by that. You can't start a thread 'with' a class. Secondly, you say
Here I want to call A.foo in the thread #bar
but you're not inside the block that is being executed in the new Thread at that point. Even if you were, there is no class method 'foo' of class A, so A.foo will only result in a NoMethodError. Then you say you want to
call the method foo from class B?
even though the comment about calling foo is in an instance of B.
So, I'm assuming you mean the following:
Class A
def foo
end
end
class B
def initialize
#bar = Thread::new{
a = A::new
}
# Here I want to call a.foo
end
end
bar = B::new
Now, in that case, your problem is that the new instance of A that you created is local to the block that the thread #bar executes. It is not an instance variable of the Thread instance that you created and you cannot access any method of that instance. However, what you can do is create that instance beforehand and share it with the thread:
class B
def initialize
a = A.new
#bar = Thread::new {
do_stuff_with a
}
a.foo
end
This will work just fine. Of course, you run into concurrency hell and all problems generally associated with using threads. Beware.