Today I came across the strange ruby syntax in the Rational class:
Rational(a,b)
(Notice the absence of the .new()portion compared to the normal Ruby syntax). What does this mean, precisely, compared to the normal new syntax? More importantly, how do I implement something like this in my own code, and why would I implement something like this? Specifically for the Rational class, why is this syntax used instead of the normal instantiation? And why is the new method private in the rational class? (And how/why would I do this in my own ruby code?)
Thanks in advance for your answers, especially since I've asked so many questions.
All you have to do is declare a global function with the same name as your class. And that is what rational.rb does:
def Rational(a, b = 1)
if a.kind_of?(Rational) && b == 1
a
else
Rational.reduce(a, b)
end
end
to make the constructor private:
private :initialize
and similarly for the new method:
private_class_method :new
I suppose Rational.new could be kept public and made to do what Rational() does, but having a method that turns its arguments into instances is consistent with Array(), String(), etc. It's a familiar pattern that's easy to implement and understand.
The method Rational() is actually an instance method defined outside of the class Rational. It therefore becomes an instance method of whatever object loads the library 'rational' (normally main:Object) in the same way that 'puts' does, for example.
By convention this method is normally a constructor for the class of the same name.
Related
As mentioned in this answer, in Ruby 2.1 or later, this code:
class SimpleTest
private
define_method :foo do
42
end
end
will define foo as a private method of SimpleTest instances. (In Ruby 2.0 and earlier it won't be private.) However, I'm looking to do something a little less trivial. I would like to define a DSL that classes can extend, and would like the methods that the DSL defines internally to respect the private/protected visibility of the calling context. That may not be clear, so here's an example:
module Dsl
def has_a(name)
define_method name do
42
end
end
end
class Test
extend Dsl
private
has_a :thing
end
As written, that code will define a public thing method on Test instances. Instead, I would like has_a to be able to reflect on the method visibility where it was called (private in this case), and define thing under that same method visibility.
I'm not familiar with Ruby's C source code, but I took a quick look and found this function which seems like it might do what I want, but I don't think it's accessible from Ruby. (It seems to only be used here.) I also looked up the documentation for define_method (since the first example works as desired) here and it seems like the noex variable declared and set here:
int noex = NOEX_PUBLIC;
const NODE *cref = rb_vm_cref_in_context(mod, mod);
if (cref) {
noex = (int)cref->nd_visi;
}
could be the value I want, but again I don't know how I would get that in Ruby, or even if it would be able to reflect back on the calling scope (in Test). Assuming I had the visibility, then I could simply call private name (or protected name) after the define_method call inside has_a if it wasn't called in a public context.
Thoughts? Is there any way to do this, or am I out of luck?
I think this question has a similar answer to what you are looking for: https://stackoverflow.com/a/28075865/5129208
It looks like the author of that made a custom module to get the behavior you're after.
With strings one can do this:
a = "hello"
a.upcase!
p a #=> "HELLO"
But how would I write my own method like that?
Something like (although that doesn't work obviously):
class MyClass
def positify!
self = [0, self].max
end
end
I know there are some tricks one can use on String but what if I'm trying to do something like this for Object?
Many classes are immutable (e.g. Numeric, Symbol, ...), so have no method allowing you to change their value.
On the other hand, any Object can have instance variables and these can be modified.
There is an easy way to delegate the behavior to a known object (say 42) and be able to change, later on, to another object, using SimpleDelegator. In the example below, quacks_like_an_int behaves like an Integer:
require 'delegate'
quacks_like_an_int = SimpleDelegator.new(42)
quacks_like_an_int.round(-1) # => 40
quacks_like_an_int.__setobj__(666)
quacks_like_an_int.round(-1) # => 670
You can use it to design a class too, for example:
require 'delegate'
class MutableInteger < SimpleDelegator
def plus_plus!
__setobj__(self + 1)
self
end
def positify!
__setobj__(0) if self < 0
self
end
end
i = MutableInteger.new(-42)
i.plus_plus! # => -41
i.positify! # => 0
Well, the upcase! method doesn't change the object identity, it only changes its internal structure (s.object_id == s.upcase!.object_id).
On the other hand, numbers are immutable objects and therefore, you can't change their value without changing their identity. AFAIK, there's no way for an object to self-change its identity, but, of course, you may implement positify! method that changes properties of its object - and this would be an analogue of what upcase! does for strings.
Assignment, or binding of local variables (using the = operator) is built-in to the core language and there is no way to override or customize it. You could run a preprocessor over your Ruby code which would convert your own, custom syntax to valid Ruby, though. You could also pass a Binding in to a custom method, which could redefine variables dynamically. This wouldn't achieve the effect you are looking for, though.
Understand that self = could never work, because when you say a = "string"; a = "another string" you are not modifying any objects; you are rebinding a local variable to a different object. Inside your custom method, you are in a different scope, and any local variables which you bind will only exist in that scope; it won't have any effect on the scope which you called the method from.
You cannot change self to point to anything other than its current object. You can make changes to instance variables, such as in the case string which is changing the underlying characters to upper case.
As pointed out in this answer:
Ruby and modifying self for a Float instance
There is a trick mentioned here that is a work around, which is to write you class as a wrapper around the other object. Then your wrapper class can replace the wrapped object at will. I'm hesitant on saying this is a good idea though.
Suppose you write a class Sup and I decide to extend it to Sub < Sup. Not only do I need to understand your published interface, but I also need to understand your private fields. Witness this failure:
class Sup
def initialize
#privateField = "from sup"
end
def getX
return #privateField
end
end
class Sub < Sup
def initialize
super()
#privateField = "i really hope Sup does not use this field"
end
end
obj = Sub.new
print obj.getX # prints "i really hope Sup does not use this field"
The question is, what is the right way to tackle this problem? It seems a subclass should be able to use whatever fields it wants without messing up the superclass.
EDIT: The equivalent example in Java returns "from Sup", which is the answer this should produce as well.
Instance variables have nothing to do with inheritance, they are created on first usage, not by some defining mechanism, therefore there is no special access control for them in language and they can not be shadowed.
Not only do I need to understand your
published interface, but I also need
to understand your private fields.
Actually this is an "official" position. Excerpt from "The Ruby Programming Language" book (where Matz is one of the authors):
... this is another reason why it is only safe to extend Ruby
classes when you are familiar with
(and in control of) the implementation
of the superclass.
If you don't know it inside and out you're on your own. Sad but true.
Don't subclass it!
Use composition instead of inheritance.
Edit: Rather than MyObject subclassing ExistingObject, see if my_object having an instance variable referring to existing_object would be more appropriate.
Instance variables belong to instances (ie objects). They're not determined by the classes themselves.
unlike java/C#, in ruby private variables are always visible to the inheriting classes. There is no way to hide the private variables.
Ruby and Java don't treat 'private' property the same way. In Ruby if you mark something as private it only means that it can't be called with receiver, i.e.:
class Sub
private
def foo; end
end
sub.foo => error accessing private method with caller
but you can always access it if you change who is self like:
sub.instance_eval { foo } #instance_eval changes self to receiver, 'sub' in this example
Conclusion: Don't rely that you can hide or protect something from outer space! Or with great power comes great responsibility!
EDIT:
Yes, I know question was for fields but it's the same thing. You can always do:
sub.instance_eval { #my_private_field = 'something else' }
puts sub.instance_eval { #my_private_field }
I am studying the ruby object model and have some questions. I understand the idea that an object only stores instance variables, and methods are stored in the class, which an object has a reference to. I also understand the idea of 'self' -- what it is, how it changes, etc.
However, what I don't understand is the notion that 'classes are objects.' Is there a good, intuitive explanation anywhere?
(BTW: I'm using Ruby Object Model and Metaprogramming and Metaprogramming Ruby as my two resources. If anybody can suggest something else, that would be helpful.)
Thanks.
It means precisely what it sounds like — classes are objects. Specifically, they are instances of the class Class, which is itself a subclass of the class Module, which in turn is a subclass of Object, just like every other class in Ruby. Like any other object in Ruby, a class can respond to messages, have its own instance variables, etc.
As a practical example, let's take private.
class Person
attr_accessor :name, :height
private
attr_accessor :weight
end
This gives instances of Person public methods to access the person's name and height, but the accessors for the person's weight are private. BUTBUTBUT — rather than being a keyword like in most languages, private is an ordinary method of the Module class. If we wanted, we could redefine it to do something different for a particular class hierarchy.
class RichardStallman
def self.private(*args)
puts "NO! INFORMATION WAS MEANT TO BE FREE!"
end
end
Here's my shot at one.
In Ruby, classes are objects. Usually they have class Class. For example, let's consider the class Foo.
class Foo
end
Doubtless you've seen this before, and it's not terribly exciting. But we could also have defined Foo this way:
Foo = Class.new
Just as you'd create a new Foo by calling Foo.new, you can create a new Class by calling Class.new. Then you give that class the name Foo by assigning it, just like any other variable. That's all there is to it.
The notion of "classes are objects" ( as I understand it ) implies that anything you can do with an object, you can do it with a class.
This differs from other programming languages where the class and the class definition are special artifacts different from objects and often unaccessible to the runtime.
For instance in Ruby, you can modify any object at runtime, since classes are also objects you can modify the class it self and add methods at runtime, delete methods, or add and delete attributes at runtime.
For instance:
$ irb
>> x = Object.new
=> #<Object:0x1011ce560>
>> x.to_s
=> "#<Object:0x1011ce560>"
>> undef to_s
=> nil
>> x.to_s
NoMethodError: undefined method `to_s' for #<Object:0x1011ce560>
from (irb):4
>>
That's not possible on other programming languages where a distinction between objects and classes is made.
note: Probably you should understand basic Ruby concepts before going to meta programming as it may be confusing, that what I would do.
Look at this article, you may find it helpful:
The Ruby Object Model - Structure and Semantics
Personally I learned a lot about the Ruby object model by reading about the Smalltalk one (e.g. in the Squeak documentation). And depending on how fluent you are in C, the MRI sources are quite approachable and yield the most definite answers.
When you think of it, it's completely logical for new to be a function, right? A function which creates and returns a new object. (Unlike most of other languages where new is some kind of operator or a language construct.)
Pushing it further, even more logical for this function new is that it should be a method, if we are talking about an OO language. Whose method? A method of an object, just a little bit different sort of an object that we can call "class".
So, looking it that way, classes are just special kinds of objects, objects that, among other peculiarities, have method new and know how to create other objects based on their own image.
what I don't understand is the notion that 'classes are objects.' Is there a good, intuitive explanation anywhere?
An answer to SO thread `Visual representation of Ruby Object Model' links to an excellent video on the subject.
Assuming the following:
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
Why is it better to use the 'self.' rather than an instance variable '#salt'?
Using self.salt = will cause the salt= method to be used, if defined. This is useful for ensuring any error checking / transformations inside the salt= method are used. However, it means there must be an explicit salt= method (possibly created by attr_accessor, for example), and this isn't necessarily a good idea.
Summary: use self.salt = if you have a custom salt= method; use #salt = if you know exactly what you want #salt to be, or if you don't have a custom salt= method.
Final note: I'd probably write it like this (in my opinion it's a little clearer)
def create_new_salt
#salt = "#{object_id}#{rand}"
end
EDIT: thanks to #Chuck's comments on another answer, I've modified this to remove the self.-free code - it was wrong.
Besides Peter's great answer, I usually signal in Ruby that I'm using attr_accessor by using self.attr= and self.attr instead of #attr.
Edit: Without "self.", you're creating a local variable. Yikes.
Further to Peter's answer:
Another interesting point is that self.salt= can be invoked even if the salt= method is private. This is an exception to the normal Ruby rule that a private method can not be invoked with an explicit receiver.