But why does it really, REALLY mean that? Was there a reason for doing
this? Is it non-trivial to have ‘+=’ mean ‘append()’?
Drew
It’s just the way it is. In C++, the following are separate overloadable
operators: =, +, and +=. In Ruby, = is not overloadable, + is, and += is not
even an operator.
I think Ruby’s way makes sense. In C++ it is possible for + and += to be
semantically incompatible. Or for + to be valid and not +=.
If performance is what you’re worried about, inlining += is not the place to
start.
As already been pointed out, this is because in Ruby when a variable is
assigned to another variable, the new variable simply refers to the same
object that the old variable refers to:
a = AnObject.new
b = a # b really refers to the same, identical AnObject as a
Therefore, if ‘+=’ means ‘append()’, then what you will have is
b += anotherObj # a will also be a = a.append(anotherObj)
The only safe/natural way of having ‘+=’ to mean ‘append()’ is by changing
the semantic in Ruby by having the variable assignment operator to invoke
some copy method:
# Not a Ruby code
a = AnObject.new
b = a # b = a.copy()
b += anotherObj # b = b.append(anotherObj), a unchanged
But Ruby does not work that way; you have to use C++ if that is really the
intention.
Regards,
Bill
···
=========================================================================
“Mills Thomas (app1tam)” app1tam@ups.com wrote:
But why does it really, REALLY mean that? Was there a reason for doing
this? Is it non-trivial to have ‘+=’ mean ‘append()’?
It’s non-sensical. << exists only as Array#<<, String#<<, and IO#<<
and means three different things. Array#<< is the same as
Array#push, IO#<< is similar to IO#puts, and String#<< is the same
as String#concat. Do you wish to create language exceptions for
three classes? How would 1.append(2) work (to use your notation)?
Why should there be exceptions to the object/language model in this
case?
-austin
– Austin Ziegler, austin@halostatue.ca on 2002.10.23 at 12.00.16
···
On Thu, 24 Oct 2002 00:23:33 +0900, Mills Thomas (app1tam) wrote:
-----Original Message----- From: Hal E. Fulton
It’s a feature. The notation a+=b really, REALLY means a = a +
b. There is a + operator, but never a += operator, in Ruby (or
any other assignment).
But why does it really, REALLY mean that? Was there a reason for
doing this? Is it non-trivial to have ‘+=’ mean ‘append()’?
It’s fairly trivial to change the behavior, but the
overall impact on the language is nontrivial.
You wouldn’t want it to mean “append” for numbers,
right? What about the zillion other classes that
exist or might be defined?
Currently += simply is not an operator on
its own. To make it independent of + is a
major language change, IMO.
Right now it’s simple and regular, and unless
you’re counting milliseconds you don’t care
that an intermediate object is created.
Well, there are times you do care. See the
threads chapter in The Ruby Way.
Hal
···
----- Original Message -----
From: “Mills Thomas (app1tam)” app1tam@ups.com
To: “ruby-talk ML” ruby-talk@ruby-lang.org
Sent: Wednesday, October 23, 2002 10:23 AM
Subject: Re: Things That Newcomers to Ruby Should Know (10/16/02)
But why does it really, REALLY mean that? Was there a reason for doing
this? Is it non-trivial to have ‘+=’ mean ‘append()’?
Use Case:
…
begin
msgPrefix = "You have an error in line "
…
rescue
msg = msgPrefix
msg += lineNum
msg += ", which means that …"
end
There are other ways to code, of course. But in this case,
appending to msg would have the side effect of changing
msgPrefix, since they start by sharing a pointer to the same
object.
Very much a violation of least-surprise principle.
In my opinion, for any “reasonable” programmer, it is usually not the
milliseconds that causes concerns, but probably when the object is large
and/or complex. In that case then I think usually we tell them that Ruby
provides many methods that can modify the original object directly,
without the need of intermediate object (but of course we also warn them
about the aliasing/side-effects).
If a person has a C++ background, then probably the concept of creation of
intermediate object is troubling, because one of the many advices in C++
books is something like:
"When you pass an argument to a function, in general it is better to
pass it by reference instead of pass by value, because pass by value can
be much more expensive as it may involve the creation of an intermediate
object, while pass by reference will not." (To avoid modifying the
original object then the “const” type specifier is used.)
Therefore, a person with a C++ background, who is used to avoiding the
creation of unnecessary intermediate objects, will be surprised that Ruby
does it all the time in its ‘+=’ operator. (Furthermore, the creation
of equivalent intermediate objects may even be more “expensive” in Ruby
than in C++ in absolute terms.)
Therefore, this type of question is, in my opinion, usually not originated
by practicality concern as much as caused by the differences in “school of
thoughts” in the programming world. C++ is more about
(computer’s) performance, while Ruby is more about (programmer’s) fun.
If a person has a C++ background, then probably the concept of creation of
intermediate object is troubling, because one of the many advices in C++
books is something like:
"When you pass an argument to a function, in general it is better to
pass it by reference instead of pass by value, because pass by value can
be much more expensive as it may involve the creation of an intermediate
object, while pass by reference will not." (To avoid modifying the
original object then the “const” type specifier is used.)
Therefore, a person with a C++ background, who is used to avoiding the
creation of unnecessary intermediate objects, will be surprised that Ruby
does it all the time in its ‘+=’ operator. (Furthermore, the creation
of equivalent intermediate objects may even be more “expensive” in Ruby
than in C++ in absolute terms.)
I don’t think “a += ‘str’” (or whatever) is creating an intermediate
object though, at least not in the sense that I understand the term.
It’s just performing an assignment, not doing anything extra.
Therefore, this type of question is, in my opinion, usually not originated
by practicality concern as much as caused by the differences in “school of
thoughts” in the programming world. C++ is more about
(computer’s) performance, while Ruby is more about (programmer’s) fun.
I won’t argue with that though it’s important to remember that
there’s nothing secret or subterranean about += in Ruby. It’s just a
way of performing an assignment – so if that isn’t what one wants
(for performance or other reasons), one has all the information
necessary to decide not to use it.
David
···
On Thu, 24 Oct 2002, William Djaja Tjokroaminata wrote:
I don’t think “a += ‘str’” (or whatever) is creating an intermediate
object though, at least not in the sense that I understand the term.
It’s just performing an assignment, not doing anything extra.
Hi David,
Probably “intermediate” is not an exact terminology; maybe “new” object is
a better one? This can be shown by
a = 'str'
puts a.id # -> some number
a << 'str'
puts a.id # -> number unchanged (in-place modification)
a += 'str'
puts a.id # -> number changed (a new object is created)
I think people with C++ background are used to the concept or convention
that ‘+=’ means in-place modification while ‘= self + something’ means a
new object creation. I think that is how we usually control performance
in C++: we prefer to use ‘+=’ unless the use of ‘=’ is necessary. The
aliasing/side-effects to other variables is of no concern because usually
the ‘=’ operator is overloaded (but then if someone forgets to overload
the ‘=’ operator then it may create a bug… )
Therefore, a person with a C++ background, who is used to
avoiding the creation of unnecessary intermediate objects, will
be surprised that Ruby does it all the time in its ‘+=’
operator. (Furthermore, the creation of equivalent intermediate
objects may even be more “expensive” in Ruby than in C++ in
absolute terms.)
I don’t think “a += ‘str’” (or whatever) is creating an
intermediate
object though, at least not in the sense that I understand the
term.
It’s just performing an assignment, not doing anything extra.
It’s creating an intermediate object that then becomes the original
object, in a sense. I think that the C++ programmer – where
references are often used like “safe” or “pretty” pointers, would
expect the following code to print out the same Object#ID both times
– and it doesn’t. It doesn’t because you’re creating a composite
object (a + “bar”) and then making a refer to that object rather
than the original a.
a = "Foo"
puts "a.id: #{a.id}"
a += "bar"
puts "a.id: #{a.id}"
I can see where it might be confusing, but as long it’s made clear
that a += b is the same as a = a + b, then even C++ programmers
shouldn’t expect a to point to the same object any longer (because
‘+’ would likely create an intermediate object).
-austin
– Austin Ziegler, austin@halostatue.ca on 2002.10.24 at 12.59.45
Therefore, a person with a C++ background, who is used to
avoiding the creation of unnecessary intermediate objects, will
be surprised that Ruby does it all the time in its ‘+=’
operator. (Furthermore, the creation of equivalent intermediate
objects may even be more “expensive” in Ruby than in C++ in
absolute terms.)
I don’t think “a += ‘str’” (or whatever) is creating an
intermediate
object though, at least not in the sense that I understand the
term.
It’s just performing an assignment, not doing anything extra.
It’s creating an intermediate object that then becomes the original
object, in a sense. I think that the C++ programmer – where
I think that’s kind of a roundabout way to describe it though. I
would say: it’s creating a new object, and assigning a reference to
that object to a variable which previously held a reference to a
different object.
references are often used like “safe” or “pretty” pointers, would
expect the following code to print out the same Object#ID both times
– and it doesn’t. It doesn’t because you’re creating a composite
object (a + “bar”) and then making a refer to that object rather
than the original a.
Right – what I was saying was just that “intermediate object” didn’t
sound like the right term to me, just as when you say:
a = “Hello”
you’re just creating an object (which I would not consider an
intermediate object). I guess I think of intermediate object creation
as, for instance:
a = [1,2,3]
b = a.map {|x| x * 2} .map {|x| x * 3}
where there’s an anonymous array being created en route to the
eventual creation of the array referred to by ‘b’.
you’re just creating an object (which I would not consider an
intermediate object). I guess I think of intermediate object creation
as, for instance:
a = [1,2,3]
b = a.map {|x| x * 2} .map {|x| x * 3}
where there’s an anonymous array being created en route to the
eventual creation of the array referred to by ‘b’.
BTW, ONE or TWO intermediate objects?
So, a.map {|x| x*2} must be created, but right after the assignment will
this object be deleted?
Gergo
±[Kontra, Gergely @ Budapest University of Technology and Economics]-+
b = a.map {|x| x * 2} .map {|x| x * 3}
BTW, ONE or TWO intermediate objects?
So, a.map {|x| x*2} must be created, but right after the assignment will
this object be deleted?
ONE intermediate object and ONE assigned to b. this intermediate
object will be garbage coolected with all other ones. btw, seasoned ruby
programmers wrote: