Why Doesn't This Work If in Ruby Everything Is an Object

Why doesn't this work if in Ruby everything is an Object?

The way Ruby works is a combination of pass by value and pass by reference. In fact, Ruby uses pass by value with references.

You can read more in the following threads:

  • Pass by reference or pass by value
  • Pass by reference?

Some notable quotes:

Absolutely right: Ruby uses pass by value - with references.

irb(main):004:0> def foo(x) x = 10 end
=> nil
irb(main):005:0> def bar; x = 20; foo(x); x end
=> nil
irb(main):006:0> bar
=> 20
irb(main):007:0>

There is no standard way (i.e. other than involving eval and
metaprogramming magic) to make a variable in a calling scope point to
another object. And, btw, this is independent of the object that the
variable refers to. Immediate objects in Ruby seamlessly integrate with
the rest (different like POD's in Java for example) and from a Ruby
language perspective you don't see any difference (other than
performance maybe). This is one of the reasons why Ruby is so elegant.

and

When you pass an argument into a method, you are passing a
variable that points to a reference. In a way, it's a combination of
pass by value and pass by reference. What I mean is, you pass the
value of the variable in to the method, however the value of the
variable is always a reference to an object.

The difference between:

def my_method( a )
a.gsub!( /foo/, 'ruby' )
end

str = 'foo is awesome'
my_method( str ) #=> 'ruby is awesome'
str #=> 'ruby is awesome'

and:

def your_method( a )
a = a.gsub( /foo/, 'ruby' )
end

str = 'foo is awesome'
my_method( str ) #=> 'ruby is awesome'
str #=> 'foo is awesome'

is that in #my_method, you are calling #gsub! which changes the object
(a) in place. Since the 'str' variable (outside the method scope) and
the 'a' variable (inside the method scope) both have a "value" that is
a reference to the same object, the change to that object is reflected
in the 'str' variable after the method is called. In #your_method, you
call #gsub which does not modify the original object. Instead it
creates a new instance of String that contains the modifications. When
you assign that object to the 'a' variable, you are changing the value
of 'a' to be a reference to that new String instance. However, the
value of 'str' still contains a reference to the original (unmodified)
string object.

Whether a method changes the reference or the referenced object depends on the class type and method implementation.

string = "hello"

def changer(str)
str = "hi"
end

changer(string)
puts string
# => "hello"

string is not changed because the assignment on strings replaces the reference, not the referenced value.
I you want to modify the string in place, you need to use String#replace.

string = "hello"

def changer(str)
str.replace "hi"
end

changer(string)
puts string
# => "hi"

String is a common case where the most part of operations works on clones, not on the self instance.
For this reason, several methods have a bang version that executes the same operation in place.

str1 = "hello"
str2 = "hello"

str1.gsub("h", "H")
str2.gsub!("h", "H")

puts str1
# => "hello"
puts str2
# => "Hello"

Finally, to answer your original question, you cannot change a String. You can only assign a new value to it or wrap the string into a different mutable object and replace the internal reference.

$wrapper = Struct.new(:string).new
$wrapper.string = "String"

def changer(w)
w.string = 1
end

changer($wrapper)

puts $wrapper.string
# => 1

Does an if statement in Ruby call a particular object method?

The if should evaulate to true if the variable is anything other than nil or false (and will error if the variable isn't defined). I'm not sure that there's a way to override an object that's defined to return a nil or false (that isn't confusing to most Ruby programmers) but I'd be interested to hear from others.

What you can do is add a method to return a nil or false value and use that instead:

class MyObject
def foo?
false
end
end

obj = MyObject.new

if obj.foo?
puts "true"
else
puts "false"
end

Update: You can override the new method to return a boolean, rather than the object.

class MyObject
attr_reader :var

def initialize(*args)
args.each do |a|
puts a
end
end

def self.new(*args, &block)
super
false
end
end

my_object = MyObject.new(:a, :b)

if !my_object
puts 'Hello, world!'
end

my_object = MyObject.new

if !my_object
puts 'Hello, world!'
end

There might be any number of side effects with that, since you've basically converted the instance of the object to a boolean. It might be an interesting exploration though, but I'd probably stick with changing my assignment or doing a defined?, is_a?, nil? check or othewise.

Java and Ruby: everything is an object in OO?

No.

As far as values go, the "primitive types" (int, bool, float, etc.) in Java are not objects. In Ruby they are objects. (In some Ruby implementations fixnums are "value types" internally for performance, but externally they are treatable as "real" objects that have methods).

In addition, there are other things that are objects in Ruby that are not objects in Java such as classes. (Actually, Java exposes these as Class as well, but in a different sense.)

There are some things that are not objects in either language, such as variables and methods. (Although in Ruby it is easy to get an object that represents a given method.)

Anyway, I think the bigger picture is that the Object Oriented programming paradigm presents a way to group data and operations on said data. (This is generally done through instance methods, as in Java and Ruby, although it might also be done through multiple dispatch and other languages, like Haskell which is "non-OO", offer alternative approaches to this task.)

Often times the definition of "OO" also includes "inheritance", "encapsulation", "abstraction", and other silly textbook terms, but the usage and patterns of different "OO" languages can vary greatly and overlap those found in "non-OO" languages ;-)

Operators && and || are objects in ruby?

It depends on how you define "everything". I personally would never claim that each individual concept in ruby is an object. I suppose there isn't really a good definition to describe how ruby works. I think you just have to accept the way ruby does it, which will become plain as you use it.

If you want to see if something is an object, try assigning it to a variable, or calling a method on it. You'll get an error if you try to do that with an operator. A notable exception is methods, which aren't objects but return objects.

Note that the concept of an object is somewhat abstract. Two variables can point to the same object. Every object is represented by an object_id. You might think of an object_id like a location in memory. Or, you can think of an object as a house, and multiple address books can contain the house's address.

# point 2 variables to the same object
>> s = t = 's'
=> "s"
>> s.object_id
=> 70269794388360
>> t.object_id
=> 70269794388360

# get the object by id (for demonstration only; I don't recommend using this in application code)
>> ObjectSpace._id2ref(70269794388360)
=> "s"

# modifying the object. both variables "see" the change
>> s << '_'
=> "s_"
>> t
=> "s_"

Continuing the house analogy, appending to a string via << is like bringing a new chair into the house. Everyone who follows their address book to that house (using the address) will see that the house (object) has the new chair.

The ruby language designers did not see a reason to allow treating operators like && as objects. Can you see any reason to allow it?

Is everything an object in Python like Ruby?

DiveIntoPython - Everything Is an Object

Everything in Python is an object, and almost everything has attributes and methods. All functions have a built-in attribute __doc__, which returns the doc string defined in the function's source code. The sys module is an object which has (among other things) an attribute called path. And so forth.

Still, this begs the question. What is an object? Different programming languages define “object” in different ways. In some, it means that all objects must have attributes and methods; in others, it means that all objects are subclassable. In Python, the definition is looser; some objects have neither attributes nor methods (more on this in Chapter 3), and not all objects are subclassable (more on this in Chapter 5). But everything is an object in the sense that it can be assigned to a variable or passed as an argument to a function (more in this in Chapter 4).

Ruby Docs - To Ruby From Python

As with Python, in Ruby,... Everything is an object

So there you have it from Ruby's own website: in Python everything is an object.

Confused with objects in Ruby

Here's the cool thing, 100 is an object too. So a pointed to the constant object 100 and when you assigned b = a you assigned b to the pointer to the object 100 not to the pointer for a or even a value of 100 held by a.

To see this is true try this:

irb> puts 100.object_id
=> 201

Cool huh?

Here's a little explanation of the Ruby object model I wrote up a while back. It's not specific to your question but adds a little more knowledge on how the Ruby object model works:

When you create an instance of an object what you have created is a new object with a set of instance variables and a pointer to the class of the object (and a few other things like an object ID and a pointer to the superclass) but the methods themselves are not in the instance of the object. The class definition contains the list of methods and their code (and a pointer to its own class, a pointer to its superclass, and an object ID).

When you call a method on an instance Ruby looks up the class of the instance and looks in that class's method list for the method you called. If it doesn't find it then it looks in the class' superclass. If it doesn't find it there it looks in that class' superclass until it runs out of superclasses. Then it goes back to the first class and looks for a method_missing method. If it doesn't find one it goes to the superclass and so on till it gets to the root object where it's designed to raise an error.

Let's say for instance you have a class Person and you make an instance of the class with the variable bubba like this:

class Person
attr_accessor :dob, :name
def age
years = Time.now.year - @dob.year
puts "You are #{years} year#{"s" if years != 1} old"
end
def feed
puts "nom, nom, nom"
end
end
bubba = Person.new
bubba.name = "Bubba"
bubba.dob = Time.new(1983,9,26)

The class diagram would look something like this:
alt text

So what's happening when you create a static method, a class/module method? Well, remember that almost everything is an object in Ruby and a module definition is an instance of the class Class. Yep, that code you type out is actually an instance too, it's live code. When you create a class method by using def self.method_name you are creating a method in the instance of the object that is the class/module definition.

Great, so where's that class method being defined at you ask? It's being defined in an anonymous class (aka singleton, eigen, ghost class) that is created for exactly this reason.

Going back to our Person class what if we add a class method on the instance bubba like so:

def bubba.drive_pickup
puts "Yee-haw!"
end

That method gets put into a special singleton class created just for that instance and the singleton's superclass is now the Person class. This makes our method calling chain look like this:
alt text

Any other methods defined on the instance object bubba will also be put into that singleton class. There's never more than one singleton class per instance object.

So, to wrap it all up the reason why it doesn't work is the static methods in the modules are being defined in the singleton class for the instance of the module definition. When you include or extend from the module you are adding a pointer to the method table of the module but not the method table of the instance object of the singleton class for the module.

Think of it this way: If you create an instance x of type Z and an instance y of type Z should x know about y? No, not unless specifically told about it. So too your module that mixes in another module should not know about some other object that just happens to have that first module as its superclass.

For a much better explanation of the Ruby object model watch this awesome free video by the amazingly erudite Dave Thomas (no, not the guy from Wendy's):

http://scotland-on-rails.s3.amazonaws.com/2A04_DaveThomas-SOR.mp4

After watching that video I bought Dave Thomas's whole series on the Ruby object model from Pragmatic and it was well worth it.

P.S. Anyone please feel free to correct me on anything I forgot; like what's specifically in an object.

Determining type of an object in ruby

The proper way to determine the "type" of an object, which is a wobbly term in the Ruby world, is to call object.class.

Since classes can inherit from other classes, if you want to determine if an object is "of a particular type" you might call object.is_a?(ClassName) to see if object is of type ClassName or derived from it.

Normally type checking is not done in Ruby, but instead objects are assessed based on their ability to respond to particular methods, commonly called "Duck typing". In other words, if it responds to the methods you want, there's no reason to be particular about the type.

For example, object.is_a?(String) is too rigid since another class might implement methods that convert it into a string, or make it behave identically to how String behaves. object.respond_to?(:to_s) would be a better way to test that the object in question does what you want.

What happens when a method is used on an object created from a built in class?

Hence, when calling a method on an object you are actually "talking" to that object, inspecting and using its attributes that are stored in its instance variables. All good for now.

No, that is very much not what you are doing in an Object-Oriented Program. (Or really any well-designed program.)

What you are describing is a break of encapsulation, abstraction, and information hiding. You should never inspect and/or use another object's instance variables or any of its other private implementation details.

In Object-Orientation, all computation is performed by sending messages between objects. The only thing you can do is sending messages to objects and the only thing you can observe about an object is the responses to those messages.

Only the object itself can inspect and use its attributes and instance variables. No other object can, not even objects of the same type.

If you send an object a message and you get a response, the only thing you know is what is in that response. You don't know how the object created that response: did the object compute the answer on the fly? Was the answer already stored in an instance variable and the object just responded with that? Did the object delegate the problem to a different object? Did it print out the request, fax it to a temp agency in the Philippines, and have a worker compute the answer by hand with pen and paper? You don't know. You can't know. You mustn't know. That is at the very heart of Object-Orientation.

This is, BTW, exactly how messaging works in real-life. If you send someone a message asking "what is π²" and they answer with "9.8696044011", then you have no idea whether they computed this by hand, used a calculator, used their smart phone, looked it up, asked a friend, or hired someone to answer the question for them.

You can imagine objects as being little computers themselves: they have internal storage, RAM, HDD, SSD, etc. (instance variables), they have code running on them, the OS, the basic system libraries, etc. (methods), but one computer cannot read another computer's RAM (access its instance variables) or run its code (execute its methods). It can only send it a request over the network and look at the response.

So, in some sense, your question is meaningless: from the point of view of Object-Oriented Abstraction, is should be impossible to answer your question, because it should be impossible to know how an object is implemented internally.

It could use instance variables, or it could not. It could be implemented in Ruby, or it could be implemented in another programming language. It could be implemented as a standard Ruby object, or it could be implemented as some secret internal private part of the Ruby implementation.

In fact, it could even not exist at all! (For example, in many Ruby implementations small integers do not actually exist as objects at all. The Ruby implementation will just make it look like they do.)

My question is, when creating an object from a built in class (String, Array, Integer...), are we actually storing some information on some instance variables for that object during its creation?

[…] [W]hat happens when we call something like string.upcase, how does the #upcase method "work" on string? I guess that in order to return the string in uppercase, the string object previously declared has some instance variables attached to, and the instances methods work on those variables?

There is nothing in the Ruby Language Specification that says how the String#upcase method is implemented. The Ruby Language Specification only says what the result is, but it doesn't say anything about how the result is computed.

Note that this is not specific to Ruby. This is how pretty much every programming language works. The Specification says what the results should be, but the details of how to compute those results is left to the implementor. By leaving the decision about the internal implementation details up to the implementor, this frees the implementor to choose the most efficient, most performant implementation that makes sense for their particular implementation.

For example, in the Java platform, there are existing methods available for converting a string to upper case. Therefore, in an implementation like TruffleRuby, JRuby, or XRuby, which sits on top of the Java platform, it makes sense to just call the existing Java methods for converting strings to upper case. Why waste time implementing an algorithm for converting strings to upper case when somebody else has already done that for you? Likewise, in an implementation like IronRuby or Ruby.NET, which sit on top of the .NET platform, you can just use .NET's builtin methods for converting strings to upper case. In an implementation like Opal, you can just use ECMAScript's methods for converting strings to upper case. And so on.

Unfortunately, unlike many other programming languages, the Ruby Language Specification does not exist as a single document in a single place). Ruby does not have a single formal specification that defines what certain language constructs mean.

There are several resources, the sum of which can be considered kind of a specification for the Ruby programming language.

Some of these resources are:

  • The ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification – Note that the ISO Ruby Specification was written around 2009–2010 with the specific goal that all existing Ruby implementations at the time would easily be compliant. Since YARV only implements Ruby 1.9+ and MRI only implements Ruby 1.8 and lower, this means that the ISO Ruby Specification only contains features that are common to both Ruby 1.8 and Ruby 1.9. Also, the ISO Ruby Specification was specifically intended to be minimal and only contain the features that are absolutely required for writing Ruby programs. Because of that, it does for example only specify Strings very broadly (since they have changed significantly between Ruby 1.8 and Ruby 1.9). It obviously also does not specify features which were added after the ISO Ruby Specification was written, such as Ractors or Pattern Matching.
  • The Ruby Spec Suite aka ruby/spec – Note that the ruby/spec is unfortunately far from complete. However, I quite like it because it is written in Ruby instead of "ISO-standardese", which is much easier to read for a Rubyist, and it doubles as an executable conformance test suite.
  • The Ruby Programming Language by David Flanagan and Yukihiro 'matz' Matsumoto – This book was written by David Flanagan together with Ruby's creator matz to serve as a Language Reference for Ruby.
  • Programming Ruby by Dave Thomas, Andy Hunt, and Chad Fowler – This book was the first English book about Ruby and served as the standard introduction and description of Ruby for a long time. This book also first documented the Ruby core library and standard library, and the authors donated that documentation back to the community.
  • The Ruby Issue Tracking System, specifically, the Feature sub-tracker – However, please note that unfortunately, the community is really, really bad at distinguishing between Tickets about the Ruby Programming Language and Tickets about the YARV Ruby Implementation: they both get intermingled in the tracker.
  • The Meeting Logs of the Ruby Developer Meetings.
  • New features are often discussed on the mailing lists, in particular the ruby-core (English) and ruby-dev (Japanese) mailing lists.
  • The Ruby documentation – Again, be aware that this documentation is generated from the source code of YARV and does not distinguish between features of Ruby and features of YARV.
  • In the past, there were a couple of attempts of formalizing changes to the Ruby Specification, such as the Ruby Change Request (RCR) and Ruby Enhancement Proposal (REP) processes, both of which were unsuccessful.
  • If all else fails, you need to check the source code of the popular Ruby implementations to see what they actually do.

For example, this is what the ISO/IEC 30170:2012 Information technology — Programming languages — Ruby specification has to say about String#upcase:

15.2.10.5.42 String#upcase

upcase

  • Visibility: public
  • Behavior: The method returns a new direct instance of the class String which contains all the characters of the receiver, with all the lower-case characters replaced with the corresponding upper-case characters.

As you can see, there is no mention of instances variables or really any details at all about how the method is implemented. It only specifies the result.

If a Ruby implementor wants to use instance variables, they are allowed to use instances variables, if a Ruby implementor doesn't want to use instance variables, they are allowed to do that, too.

If you check the Ruby Spec Suite for String#upcase, you will find specifications like these (this is just an example, there are quite a few more):

describe "String#upcase" do
it "returns a copy of self with all lowercase letters upcased" do
"Hello".upcase.should == "HELLO"
"hello".upcase.should == "HELLO"
end

describe "full Unicode case mapping" do
it "works for all of Unicode with no option" do
"äöü".upcase.should == "ÄÖÜ"
end

it "updates string metadata" do
upcased = "aßet".upcase

upcased.should == "ASSET"
upcased.size.should == 5
upcased.bytesize.should == 5
upcased.ascii_only?.should be_true
end
end
end

Again, as you can see, the Spec only describes results but not mechanisms. And this is very much intentional.

The same is true for the Ruby-Doc documentation of String#upcase:

upcase(*options)string

Returns a string containing the upcased characters in self:

s = 'Hello World!' # => "Hello World!"
s.upcase # => "HELLO WORLD!"

The casing may be affected by the given options; see Case Mapping.

There is no mention of any particular mechanism here, nor in the linked documentation about Unicode Case Mapping.

All of this only tells us how String#upcase is specified and documented, though. But how is it actually implemented? Well, lucky for us, the majority of Ruby implementations are Free and Open Source Software, or at the very least make their source code available for study.

In Rubinius, you can find the implementation of String#upcase in core/string.rb lines 819–822 and it looks like this:

def upcase
str = dup
str.upcase! || str
end

It just delegates the work to String#upcase!, so let's look at that next, it is implemented right next to String#upcase in core/string.rb lines 824–843 and looks something like this (simplified and abridged):

def upcase!
return if @num_bytes == 0

ctype = Rubinius::CType

i = 0
while i < @num_bytes
c = @data[i]
if ctype.islower(c)
@data[i] = ctype.toupper!(c)
end
i += 1
end
end

So, as you can see, this is indeed just standard Ruby code using instance variables like @num_bytes which holds the length of the String in platform bytes and @data which is an Array of platform bytes holding the actual content of the String. It uses two helper methods from the Rubinius::CType library (a library for manipulating individual characters as byte-sized integers). The "actual" conversion to upper case is done by Rubinius::CType::toupper!, which is implemented in core/ctype.rb and is extremely simple (to the point of being simplistic):

def self.toupper!(num)
num - 32
end

Another very simple example is the implementation of String#upcase in Opal, which you can find in opal/corelib/string.rb and looks like this:

def upcase
`self.toUpperCase()`
end

Opal is an implementation of Ruby for the ECMAScript platform. Opal cleverly overloads the Kernel#` method, which is normally used to spawn a sub shell (which doesn't exist in ECMAScript) and execute commands in the platform's native command language (which on the ECMAScript platform arguably is ECMAScript). In Opal, Kernel#` is instead used to inject arbitrary ECMAScript code into Ruby.

So, all that `self.toUpperCase()` does, is call the String.prototype.toUpperCase method on self, which does work because of how the String class is defined in Opal:

class ::String < `String`

In other words, Opal implements Ruby's String class by simply inheriting from ECMAScript's String "class" (really the String Constructor function) and is therefore able to very easily and elegantly reuse all the work that has been done implementing Strings in ECMAScript.

Another very simple example is TruffleRuby. Its implementation of String#upcase can be found in src/main/ruby/truffleruby/core/string.rb and looks like this:

def upcase(*options)
s = Primitive.dup_as_string_instance(self)
s.upcase!(*options)
s
end

Similar to Rubinius, String#upcase just delegates to String#upcase!, which is not surprising since TruffleRuby's core library was originally forked from Rubinius's. This is what String#upcase! looks like:

def upcase!(*options)
mapped_options = Truffle::StringOperations.validate_case_mapping_options(options, false)
Primitive.string_upcase! self, mapped_options
end

The Truffle::StringOperations::valdiate_case_mapping_options helper method is not terribly interesting, it is just used to implement the rather complex rules for what the Case Mapping Options that you can pass to the various String methods are allowed to look like. The actual "meat" of TruffleRuby's implementation of String#upcase! is just this: Primitive.string_upcase! self, mapped_options.



Related Topics



Leave a reply



Submit