I want to create a class instance that has a value such that I can do something like puts a = Example.new(1) where a's value is specified in initialize.
I expect that this is a simple problem since all predefined Ruby classes allow this, but I'm unable to figure out how to do it for my classes.
Class#new and Return Values
Your example doesn't quite work because Ruby treats Class#new as a special case, and is expected to invoke the #initialize method and return an object. If it didn't, calling #new on a class would surprise a lot of people by returning the last evaluation of the initializer from your class, or from Object#new if it's otherwise undefined for your class. In either case, this would violate the principle of least surprise.
However, you can do what you want pretty easily by simply creating an accessor method and then chaining off of Example#new. For example, in Ruby 3.1.0:
class Example
attr_reader :int
def initialize(int) = (#int = int)
end
# prints `1` to STDOUT and assigns the value to *a*,
# but returns nil because you're using Kernel#puts
# which always returns nil
puts a = Example.new(1).int
# shows that the local variable *a* is set to the value
# returned by the Example#int accessor for the class'
# #int instance variable
a
#=> 1
To avoid the confusion of having a nil return value (even though this is expected with Kernel#puts, just change your puts statement to use Kernel#p instead:
p a = Example.new(2).int
#=> 2
Refactoring the Example Class for Older Rubies
If you're using an older Ruby than 3.0, you can't use an endless method or the improved handling for them in Ruby 3.1. The only difference is that rather than an inline method, you need to specify it with the standard def...end syntax, e.g.:
class Example
attr_reader :int
def initialize(int)
#int = int
end
end
Otherwise, the points above are valid as far back as any currently-supported Ruby version.
Related
To test, whether a constant (say: a class) is known at a certain point in the code, I can write for instance:
if defined? :String
or I can write
if self.class.const_defined? :String
Is there a situation where I these two ways of testing would make a difference? Note that I don't ask about the case where I have an explicit receiver, such as MyModule.const_defined? :Something, but only for the case where I want to test whether a certain constant (which in my case happens to be a constant denoting a class) is already defined.
First things first, defined? is a keyword which behaves a bit similar similar to a method. It receives the name of the thing (variable, constant, ...) to check. What makes this method different from all others is that the parser will not resolve the value of the given name but rather check directly for whether it is defined (hence the keyword property). To check if a constant is defined, you thus have to pass the actual name (rather than a Symbol):
if defined?(String)
The const_defined? on the oither hand is more regular. It expects a Symbol or String with the name of a constant and checks whether it is defined on the receiver.
Now as for the differences between the two (when used correctly): if you use them both within the context of an instance method to check for the existence of a constant, they work the same.
When running e.g. in a class definition (such that self is e.g. a class), you need to make sure to use the correct receiver for your const_defined method, e.g. if self.const_defined? :String.
Also, defined? can check for a lot more than just constants (e.g. methods, expressions, variables, ...)
If you want to use this to make sure you actually have the name of a constant at hand in a given variable, you need to use const_defined?. If you want to "statically" check whether an constant was defined, you can use defined?.
defined? is a keyword that will check if an expression exists in the current scope.
const_defined? is a method that will check if a constant exists through the ancestor chain of the receiver.
planet = "Earth"
class Experiment
def diff
""
end
def show
puts "defined" if defined?(diff)
puts "Earth not found" if !defined?(planet)
puts "String constant defined" if self.class.const_defined?(:String)
end
end
Experiment.new.show
#=> defined
#=> Earth not found
#=> String constant defined
p Experiment.ancestors #=> [Experiment, Object, Kernel, BasicObject]
p String.superclass #=> Object
Here's an example of situations where this will make a difference:
Using defined?(Nothing's printed)
class Lab
class Coco
end
end
class Experiment
def diff
""
end
def show
puts "defined" if defined?(Coco) #=> Nothing printed
end
end
Experiment.new.show
Using self.class.const_defined? (Something's printed)
class Lab
class Coco
end
end
class Experiment < Lab
def diff
""
end
def show
puts "defined" if self.class.const_defined? :Coco #=> defined
end
end
Experiment.new.show
p Experiment.ancestors #=> [Experiment, Lab, Object, Kernel, BasicObject] We find 'Lab' class in the ancestor chain.
To test, whether a constant (say: a class) is known at a certain point in the code, I can write for instance:
if defined? :String
or I can write
if self.class.const_defined? :String
Is there a situation where I these two ways of testing would make a difference?
These two really do two completely different things. The first tests whether the Symbol literal :String is defined. Obviously, a literal will always be defined, so this expression will always be true.
The second will check whether the constant String is defined, but not starting at the current constant lookup scope, instead starting at the class of self.
TL;DR
There may be cases where you can use them interchangeably, but one is a keyword and the other a method. In addition, the semantics and return values of the two are quite different.
Keywords vs. Methods
Among other things, one key difference is that Module#const_defined? is a method on a class or module that looks up constants in a class and its ancestors, while defined? is a keyword that determines whether its argument is currently known at the calling point in your code.
For example:
char = 'a'
char.const_defined?
#=> NoMethodError (undefined method `const_defined?' for "a":String)
defined? char
#=> "local-variable"
Exceptions vs. Return Values
If you're only concerned about constants, then the main difference is that you can use defined? to determine whether a constant is currently in scope without triggering a NoMethodError exception. For example:
defined? String
#=> "constant"
defined? FooBarBaz
#=> nil
As a bonus, defined? will tell what type of object you're passing as an argument (e.g. "constant"), while #const_defined? returns a truthy value.
Float.constants
#=> [:ROUNDS, :RADIX, :MANT_DIG, :DIG, :MIN_EXP, :MAX_EXP, :MIN_10_EXP, :MAX_10_EXP, :MIN, :MAX, :EPSILON, :INFINITY, :NAN]
defined? Float::NAN
#=> "constant"
Float.const_defined? :NAN
#=> true
As a rule of thumb, it's often considered best practice to reserve exceptions for handling something unexpected that may require your application to halt. Introspection or branching should generally rely on return values or Booleans, so defined? is usually a better choice if you aren't already expecting a given class to already be defined and available within the current scope.
Is there a situation where I these two ways of testing would make a difference?
const_defined? only checks the receiver and its ancestors, but it doesn't take the current module nesting into account:
module Foo
ABC = 123
class Bar
def self.test
p defined?(ABC) #=> "constant"
p const_defined?(:ABC) #=> false
end
end
end
In order to do so, you have to traverse Module.nesting:
module Foo
ABC = 123
class Bar
def self.test
p defined?(ABC) #=> "constant"
p Module.nesting.any? { |m| m.const_defined?(:ABC) } #=> true
end
end
end
Given this script
def hash
puts "why?"
end
x = {}
x[[1,2]] = 42
It outputs the following
why?
/tmp/a.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/a.rb:6:in `<main>'
It seems that the hash function defned in the script is overriding Array#hash in that case. Since the return value of my hash method is nil and not an Integer, it throws an exception. The following script seems to confirm this
puts [1,2,3].hash
def hash
puts "why?"
end
puts [1,2,3].hash
The output is
-4165381473644269435
why?
/tmp/b.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError)
from /tmp/b.rb:6:in `<main>'
I tried looking into the Ruby source code but could not figure out why this happens. Is this behavior documented?
You're not overriding Array#hash, you're shadowing Kernel#hash by creating Object#hash:
puts method(:hash)
def hash
puts "why?"
end
puts method(:hash)
That prints:
#<Method: Object(Kernel)#hash>
#<Method: Object#hash>
Fix it so we can see more:
def hash
puts "why?"
super
end
x = {}
x[[1,2]] = 42
Now the output is:
why?
why?
And no error. Try it with x[[1,2,3,4,5,6,7]] = 42 and you'll instead see why? printed seven times. Once for each array element, since the array's hash method uses the hashes of its elements. And Integer#hash doesn't exist, it inherits its hash method from Object/Kernel, so yours gets used.
This is due to a kind of hack in Ruby top level. Have you ever wondered how this works?
def foo
end
p self
foo
class Bar
def test
p self
foo
end
end
Bar.new.test # no error
How are two totally different objects (main and a Bar) able to call foo like it's a private method call? The reason is because... it is a private method call.
When you define a method at the top level of your Ruby script, it gets included (via Object) in every object. That's why you can call top-level methods like they are global functions.
But why does this break only hash and not other common methods? def to_s;end won't break to_s, for example. The reason is because hash is recursive: most* class implementations ultimately call down to Object#hash for their implementations. By redefining that base case, you break it globally. For other methods like to_s you won't see a global change because it's way up the inheritance chain and doesn't get invoked.
* the only objects this doesn't break are a few literals that probably have hard-coded hash values e.g. [] {} "" true etc.
I would like to extend the functionality of variables in Ruby. The reason is I am working on something similar of a type system or value checker (this sounds a bit crazy but the whole idea is to long to explain, just the reason I would like to extend default variables).
I have read that in Ruby, everything is an object; so variables are objects. And Ruby is supposed to be quite liberal concerning what can be changed via meta-programming.
Is there some kind of 'Class' associated with local variables that I could extend?
I would like to associate a string-variable for each variable that holds a string representation of a type. Further I would like to intercept variable assignments and execute a method each time a new value is assigned to a variable. This is so I can check, if the new value is correct according to the type (stored as string in the Variable).
If local variables in Ruby are defined as object of a class, I can extend that class or modify it via a ruby mixin.
The workaround would be to create a new class for my Variables (and not use the build in local variables of Ruby). This class can have a value attribute, a attribute (stored as string) for the type and a get- and set-method. This way I can solve my problem, but I would like to extend the built in variables in ruby, if that is possible.
current work in progress
class Fixnum
attr_accessor :tp
#tp
def mytype ( type )
#tp = type
end
def typecheck
#call typechecker
puts "checked"
end
end
Test Code:
a = 3
a.mytype("nat")
puts a.tp
a.typecheck
There are still two problems.
First, I think it is not possible to add a new constructor to Fixnum. Second, I would like to intercept the variable access, i.e. "b = a" calls the method 'typecheck' of a. But this would require something similar to Aspect Oriented Programming and I am not sure if this can be solved with Ruby's meta-programming facilitates.
I have read that in Ruby, everything is an object
That depends on your definition of "object" and every-"thing". "Object" can mean "entity that can be manipulated by the program" (which I will call object from now on), or "value that is a member of the object system" (which I will call Object from now on).
In Ruby, everything that can be manipulated by the program (i.e. every object) is also an Object, i.e. an instance of a class. This is unlike Java, for example, where primitives can be manipulated by the program (i.e. are objects in that sense of the word), but aren't Objects. In Ruby, this distinction doesn't exist: every object is an Object and every Object is also an object.
However, there are things in the language, which cannot be manipulated by the program and which aren't instances of a class, i.e. they are neither object s nor Objects. These are, for example, methods, variables, syntax, parameter lists, arguments lists, keywords.
Note: you can use Ruby's reflection API to give you an object that represents a method or a parameter list, but that object is only a proxy, it is not the real thing.
So, when we say "everything is an object", what we really mean is that "every object is an Object", i.e. that everything which can be manipulated by the program is also a member of the object system, or in other words, there are no values outside of the object system (unlike primitives in Java). We do not mean that everything that exists in the language can also be manipulated at runtime by the program.
so variables are objects
No, unfortunately, they are neither object s nor Objects.
This is also clearly stated in the Ruby Language Specification (emphasis added by me):
6.2 Variables
6.2.1 General description
A variable is denoted by a name, and refers to an object, which is called the value of the variable.
A variable itself is not an object.
In the book The Ruby Programming Language by Matz and David Flanagan it says on page 2:
every value is an object
Note, it doesn't say every-thing, only every value.
See also the question Is variable is object in ruby?
There are a couple things you can do. For starters, all (or very nearly all) Ruby classes (including "primitives" such as numbers) support a to_s method which returns a string representation of the object. For numbers, to_s will just return the string representation of that number (e.g., "42" for 42). The string value returned for other classes will vary. The nice thing is that you can override a class's methods via "monkey patching". Here's an extremely contrived example:
class Array
def to_s
return "An array of size #{self.size}."
end
end
a = [1, 2, 3, 4]
puts a.to_s
# => "An array of size 4."
For your other question regarding executing a method every time a variable's value is set, the way to handle this is to always interact with the variable through its accessor methods. This way you can implement custom code inside a property's getter and setter methods (or simply call another method from inside the accessor). Like this:
class MyClass
# Use the default getter for var.
attr_reader :var
def initialize
#var = 1
end
# Custom setter for var.
def var= v
#var = v
puts "var changed to #{v}"
end
end
mc = MyClass.new
mc.var = 9
# => "var chaged to 9"
You could do something like this, but it only works for globals:
$type_checked = {:$a => String, :$b => Array}
$type_checked.keys.each do |var|
trace_var(var) do |obj|
puts "hey, don't assign #{var} to a #{obj.class}" unless $type_checked[var] == obj.class
#or raise an Error
end
end
$a = 1
$a = "a"
$b = 1
#output:
#hey, don't assign $a to a Fixnum
#hey, don't assign $b to a Fixnum
But this clearly goes against the grain of the language.
for instance in python it is possible to assign a method to a variable:
class MyClass
def myMethod(self):
return "Hi"
x = MyClass()
method = x.myMethod
print method() # prints Hi
I know this should be possible in Ruby, but I don't know what's the syntax.
You need to grab the method by using method with the method’s name as an argument. This will return you an instance of type Method, which can be called with call().
class MyClass
def myMethod
"Hi"
end
end
x = MyClass.new
m = x.method(:myMethod)
# => #<Method: MyClass#myMethod>
puts m.call
# You can also do m[] instead of m.call()
Note that any arguments would need to be added to the call method.
In many practical cases, however, there is no need to have the method itself saved to a variable in Ruby; if you just want to dynamically call a method (i.e. send a message to an object) and there is no need to save the method, you could also use the send (or __send__ method in case of name clashes).
x = MyClass.new
puts x.send :myMethod # also possible with a string: m.send "myMethod"
# "Hi"
Any arguments should follow the method name:
puts x.send(:myMethod, arg1, arg2)
To use it like this is probably more Ruby-like, as the concept of Method classes is not as prominent as it is in Python. In Python, you can always think of a two step mechanism when doing something like a_string.split(); first you grab the method with a_string.split and then you call it (either implicitly with () or explicitly with __call__()). So, cutting that two-step mechanism is rather natural to do.
Ruby is more based on message passing and to actually get a method class in Ruby, you’ll have to do some more work, because in some way, the method object will have to be constructed for you at that point. So, unless you really need some Methods object in Ruby, you should rather stick to the message passing abstraction and simply use send.
I think you are looking for Proc or lambda block
x = Proc.new { return "Hello World" }
puts x.call
x = lambda { return "Hello World" }
puts x.call
I would read this short post - there is a slight but significant difference in the way the methods behave
http://samdanielson.com/2007/3/19/proc-new-vs-lambda-in-ruby
I'm thinking in:
class X
def new()
#a = 1
end
def m( other )
#a == other.#a
end
end
x = X.new()
y = X.new()
x.m( y )
But it doesn't works.
The error message is:
syntax error, unexpected tIVAR
How can I compare two private attributes from the same class then?
There have already been several good answers to your immediate problem, but I have noticed some other pieces of your code that warrant a comment. (Most of them trivial, though.)
Here's four trivial ones, all of them related to coding style:
Indentation: you are mixing 4 spaces for indentation and 5 spaces. It is generally better to stick to just one style of indentation, and in Ruby that is generally 2 spaces.
If a method doesn't take any parameters, it is customary to leave off the parantheses in the method definition.
Likewise, if you send a message without arguments, the parantheses are left off.
No whitespace after an opening paranthesis and before a closing one, except in blocks.
Anyway, that's just the small stuff. The big stuff is this:
def new
#a = 1
end
This does not do what you think it does! This defines an instance method called X#new and not a class method called X.new!
What you are calling here:
x = X.new
is a class method called new, which you have inherited from the Class class. So, you never call your new method, which means #a = 1 never gets executed, which means #a is always undefined, which means it will always evaluate to nil which means the #a of self and the #a of other will always be the same which means m will always be true!
What you probably want to do is provide a constructor, except Ruby doesn't have constructors. Ruby only uses factory methods.
The method you really wanted to override is the instance method initialize. Now you are probably asking yourself: "why do I have to override an instance method called initialize when I'm actually calling a class method called new?"
Well, object construction in Ruby works like this: object construction is split into two phases, allocation and initialization. Allocation is done by a public class method called allocate, which is defined as an instance method of class Class and is generally never overriden. It just allocates the memory space for the object and sets up a few pointers, however, the object is not really usable at this point.
That's where the initializer comes in: it is an instance method called initialize, which sets up the object's internal state and brings it into a consistent, fully defined state which can be used by other objects.
So, in order to fully create a new object, what you need to do is this:
x = X.allocate
x.initialize
[Note: Objective-C programmers may recognize this.]
However, because it is too easy to forget to call initialize and as a general rule an object should be fully valid after construction, there is a convenience factory method called Class#new, which does all that work for you and looks something like this:
class Class
def new(*args, &block)
obj = alloc
obj.initialize(*args, &block)
return obj
end
end
[Note: actually, initialize is private, so reflection has to be used to circumvent the access restrictions like this: obj.send(:initialize, *args, &block)]
Lastly, let me explain what's going wrong in your m method. (The others have already explained how to solve it.)
In Ruby, there is no way (note: in Ruby, "there is no way" actually translates to "there is always a way involving reflection") to access an instance variable from outside the instance. That's why it's called an instance variable after all, because it belongs to the instance. This is a legacy from Smalltalk: in Smalltalk there are no visibility restrictions, all methods are public. Thus, instance variables are the only way to do encapsulation in Smalltalk, and, after all, encapsulation is one of the pillars of OO. In Ruby, there are visibility restrictions (as we have seen above, for example), so it is not strictly necessary to hide instance variables for that reason. There is another reason, however: the Uniform Access Principle.
The UAP states that how to use a feature should be independent from how the feature is implemented. So, accessing a feature should always be the same, i.e. uniform. The reason for this is that the author of the feature is free to change how the feature works internally, without breaking the users of the feature. In other words, it's basic modularity.
This means for example that getting the size of a collection should always be the same, regardless of whether the size is stored in a variable, computed dynamically every time, lazily computed the first time and then stored in a variable, memoized or whatever. Sounds obvious, but e.g. Java gets this wrong:
obj.size # stored in a field
vs.
obj.getSize() # computed
Ruby takes the easy way out. In Ruby, there is only one way to use a feature: sending a message. Since there is only one way, access is trivially uniform.
So, to make a long story short: you simply can't access another instance's instance variable. you can only interact with that instance via message sending. Which means that the other object has to either provide you with a method (in this case at least of protected visibility) to access its instance variable, or you have to violate that object's encapsulation (and thus lose Uniform Access, increase coupling and risk future breakage) by using reflection (in this case instance_variable_get).
Here it is, in all its glory:
#!/usr/bin/env ruby
class X
def initialize(a=1)
#a = a
end
def m(other)
#a == other.a
end
protected
attr_reader :a
end
require 'test/unit'
class TestX < Test::Unit::TestCase
def test_that_m_evaluates_to_true_when_passed_two_empty_xs
x, y = X.new, X.new
assert x.m(y)
end
def test_that_m_evaluates_to_true_when_passed_two_xs_with_equal_attributes
assert X.new('foo').m(X.new('foo'))
end
end
Or alternatively:
class X
def m(other)
#a == other.instance_variable_get(:#a)
end
end
Which one of those two you chose is a matter of personly taste, I would say. The Set class in the standard library uses the reflection version, although it uses instance_eval instead:
class X
def m(other)
#a == other.instance_eval { #a }
end
end
(I have no idea why. Maybe instance_variable_get simply didn't exist when Set was written. Ruby is going to be 17 years old in February, some of the stuff in the stdlib is from the very early days.)
There are several methods
Getter:
class X
attr_reader :a
def m( other )
a == other.a
end
end
instance_eval:
class X
def m( other )
#a == other.instance_eval { #a }
end
end
instance_variable_get:
class X
def m( other )
#a == other.instance_variable_get :#a
end
end
I don't think ruby has a concept of "friend" or "protected" access, and even "private" is easily hacked around. Using a getter creates a read-only property, and instance_eval means you have to know the name of the instance variable, so the connotation is similar.
If you don't use the instance_eval option (as #jleedev posted), and choose to use a getter method, you can still keep it protected
If you want a protected method in Ruby, just do the following to create a getter that can only be read from objects of the same class:
class X
def new()
#a = 1
end
def m( other )
#a == other.a
end
protected
def a
#a
end
end
x = X.new()
y = X.new()
x.m( y ) # Returns true
x.a # Throws error
Not sure, but this might help:
Outside of the class, it's a little bit harder:
# Doesn't work:
irb -> a.#foo
SyntaxError: compile error
(irb):9: syntax error, unexpected tIVAR
from (irb):9
# But you can access it this way:
irb -> a.instance_variable_get(:#foo)
=> []
http://whynotwiki.com/Ruby_/_Variables_and_constants#Variable_scope.2Faccessibility