Feature #6225
closedHash#+
Added by trans (Thomas Sawyer) over 12 years ago. Updated over 11 years ago.
Description
Strings and Arrays can be combined with #+. I don't see any reason not to allow Hashes to do so as well.
class Hash
alias :+ :merge
end
Updated by mame (Yusuke Endoh) over 12 years ago
- Status changed from Open to Assigned
- Assignee set to matz (Yukihiro Matsumoto)
Both String#+ and Array#+ delete no information, but
Hash#merge deletes duplicate fields.
I have heard it is the reason, if I recall.
--
Yusuke Endoh mame@tsg.ne.jp
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 12 years ago
This argument really doesn't buy me. Groovy allows: [key1: 'value1', another: 1] + [key2: 'value2', another: 2] == [key1: 'value1', another: 2, key2: 'value2']
.
I think this is pretty readable as +
is also used to denotate unions. I don't think anyone would expect any behavior different from that.
Maybe someone could argue that the result could also mean [key1: 'value1', another: [1, 2], key2: 'value2']
but I think that would be really strange.
Updated by shyouhei (Shyouhei Urabe) over 12 years ago
I object. No binary operations shall be called +
unless the operation is symmetric.
For historical reasons there are some asymmetric +
s in Ruby, but that is not a indulgence for you to add more.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 12 years ago
In other words you don't like that {a: 1} + {a: 2} != {a: 2} + {a: 1}
But I really think programming is different from mathematics and I don't think that the fact that a + b != b + a
would be enough reason for avoiding the convenient operator por "b merged to a" (a + b
).
Not that I really do care that much about this feature request as I don't see any problem on writing a.merge(b)
anyway... I just don't see any problems either for having "a + b == a.merge(b)
".
Updated by trans (Thomas Sawyer) over 12 years ago
No binary operations shall be called
+
unless the operation is symmetric.
Why?
Also what do you mean by symmetric? Do you mean commutative? I point out that neither Array#+
or String#+
is really commutative either because order is significant.
Also, I don't know why you say "indulgence". It's a simple convenience as a means of writing concise, yet readable, code.
Updated by shyouhei (Shyouhei Urabe) over 12 years ago
Sorry for my bad English, I didn't intend to attack you.
Anyway there has been a long discussion around +
s in programming languages. For instance Perl uses dot to concatenate strings and avoid +
s to concatenate strings and/or arrays. I see they are much more mature than us in this area. Functional languages like Haskell also avoid defining +
onto non-abelian groups.
Updated by duerst (Martin Dürst) over 12 years ago
In common sense, *
is also commutative. But of course, for matrix multiplication, it's not.
Also, +
is used in many fields of mathematics. I'm not a mathematician, but I very strongly doubt that it's commutative in all these cases. (see e.g. http://arxiv.org/abs/1003.2081 for an example)
What's much more important is whether the +
for Hash fits the general image a Ruby programmer has for +
. I'm not exactly sure about this, but the parallel with Array
is not too bad.
Updated by matz (Yukihiro Matsumoto) over 12 years ago
I myself do not care whether + to be symmetric or not. I care about key conflict.
Since conflicting cause value lost, I am not positive about making + alias to #merge.
Matz.
Updated by naruse (Yui NARUSE) over 12 years ago
shyouhei (Shyouhei Urabe) wrote:
Anyway there has been a long discussion around
+
s in programming languages. For instance Perl uses dot to concatenate strings and avoid+
s to concatenate strings and/or arrays. I see they are much more mature than us in this area. Functional languages like Haskell also avoid defining+
onto non-abelian groups.
On Perl, it is because for
perl -e'print "1" + "2"' #=> 3
perl -e'print "1" . "2"' #=> 12
Not because of symmetry.
Updated by jacksonwillis (Jackson Willis) over 12 years ago
Would it be better to use Hash#<<
instead of Hash#+
?
Updated by trans (Thomas Sawyer) over 12 years ago
@jacksonwillis (Jackson Willis) #<<
makes sense as an alias for #update
, not #merge
. However I use Hash#<<
with this meaning:
def <<(array)
raise if array.size != 2
self[array.first] = array.last
end
There are historical reasons for that definition. But the two can be combined:
def <<(object)
case object
when Array
raise if object.size != 2
self[object.first] = object.last
else
update(object)
end
end
Updated by alexeymuranov (Alexey Muranov) over 12 years ago
Martin, in math, it is common to use *
for both commutative and non-commutative operations but +
for only commutative.
But i am more in favor of Matz's argument, because i didn't bother myself about the fact that string addition is non-commutative.
duerst (Martin Dürst) wrote:
In common sense,
*
is also commutative. But of course, for matrix multiplication, it's not.Also,
+
is used in many fields of mathematics. I'm not a mathematician, but I very strongly doubt that it's commutative in all these cases. (see e.g. http://arxiv.org/abs/1003.2081 for an example)What's much more important is whether the
+
forHash
fits the general image a Ruby programmer has for+
. I'm not exactly sure about this, but the parallel withArray
is not too bad.
Updated by alexeymuranov (Alexey Muranov) over 12 years ago
How about Hash#|
for Hash#reverse_merge
, and Hash#|=
for Hash#reverse_merge!
from Rails? (Instead of #+
for #merge
.)
I would like to give an algebraic counterpart to Matz's objection: #merge
is not injective in the first argument, nor in the second: a.merge(b) == a.merge(c)
does not imply b == c
, but most uses of #+
are injective in each of the arguments.
I know that Set#+
is already an exception to this rule. It seems that it is equivalent to Set#|
, isn't it? However, this could be more of a poor definition of Set#+
than a justification to allow Hash#+
to be a synonym for #merge
. I was just looking through "Lectures on ergodic theory" by P. Halmos, and there the +
for sets is used to denote the symmetric difference (as i would expect).
Edited 2013-01-24.
Updated by naruse (Yui NARUSE) about 12 years ago
- Target version changed from 2.0.0 to 2.6
Updated by zzak (zzak _) over 11 years ago
To put an end to the bikeshedding, and because I'd like this ticket to get a resolution:
The original request was to alias Hash#+
to Hash#merge
.
matz, if you can make a decision on this alias it would be appreciated!
To all other requests for Hash
, aliases and other methods please open a new ticket.
Updated by alexch (Alex Chaffee) over 11 years ago
Operator overloading is for convenience and to "least surprise". Since +
puts two numbers together, and +
puts two strings together, and +
puts two arrays together, +
should also put two hashes together -- in the way that makes the most sense for each type.
Updated by mame (Yusuke Endoh) over 11 years ago
zzak (Zachary Scott) wrote:
matz, if you can make a decision on this alias it would be appreciated!
matz explicitly said that he was not positive:
https://bugs.ruby-lang.org/issues/6225#note-8
So it is reasonable to look for other aliases.
BTW, I don't think that Hash#merge
is so frequently-used operation enough to have such a short notation.
I guess we may want it only when the values is not important, that is, when the hash is used like a set. In this case, we can use set.rb
which provides Set#+
.
Yusuke Endoh mame@tsg.ne.jp
Updated by jimweirich (Jim Weirich) over 11 years ago
mame (Yusuke Endoh) wrote:
BTW, I don't think that
Hash#merge
is so frequently-used operation enough to have such a short notation.
I guess we may want it only when the values is not important, that is, when the hash is used like a set. In this case, we can useset.rb
which providesSet#+
.
I use Hash#merge
a lot in a Rails project to manage valid attributes for testing scenarios. E.g. valid_default_attributes.merge(overriding_attributes)
.
-- Jim Weirich
Updated by alexeymuranov (Alexey Muranov) over 11 years ago
Updated by drbrain (Eric Hodel) over 11 years ago
At DevelopersMeeting20130809 matz said:
17:26 charliesome: So it's rejected? 17:29 matz: I guess so. 17:29 matz: I still concern about merge is not a mere addition
So if the original reporter still wishes to make this a feature please make a slide with a short justification and a few examples for the next meeting.
Updated by trans (Thomas Sawyer) over 11 years ago
So if the original reporter...
That would be me, but I am not going to make a slide. Some one else can if they like. Personally I think it's obvious. #merge
is one of the most commonly used methods of Hash, so having an operator for it, if at all possible, is a no-brainer in my opinion. Given the options, what other operator even comes close in meaning more so than #+
? So merge is not commutative. Big deal. Technically neither is String#+
.
Updated by Anonymous over 11 years ago
I think what matz means by "not a mere addition" is that in the cases of String#+
and Array#+
, both operands are wholly represented by the result.
In Hash#merge, the return value might not be made up of whole of both operands. So it's not really an addition. IMO Hash#|
might be appropriate, but I don't want to enter into a bikesheddy argument here.
Updated by Anonymous over 11 years ago
- Status changed from Assigned to Rejected
Also, since this specific feature (Hash#+) has been rejected by matz, I'm marking this ticket as rejected.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
I agree that the operation not being an addition is not a big deal. No one would expect it from a Hash. Groovy does have this operator working exactly as a merge and I don't see anyone complaining about it. But I don't see any problems either with calling it #|
. I would be fine with either "hash + another_hash
" or "hash | another_hash
" as an alias for hash.merge(another_hash)
.
As a side note, yesterday I missed a method to perform Array#|
in a way that work directly in the array (like #|!
if it was possible). I had a code similar to this:
dependencies = Thread.current[:_my_app_dependencies]
dependencies |= new_dependencies # won't work as expected, of course, since I wanted to store it under Thread.current[:_my_app_dependencies]
But as I said, this is just an aside note, not related to this ticket.
Updated by rosenfeld (Rodrigo Rosenfeld Rosas) over 11 years ago
Charlie, any chances to reopen this ticket so that Matz could evaluate the usage of using |
instead of +
?
Updated by nobu (Nobuyoshi Nakada) over 11 years ago
I think new method proposal should be a new ticket.
Updated by alexeymuranov (Alexey Muranov) over 11 years ago
A use of Hash#|
is proposed in #7739.
There is however a typo in the proposal: it should be
{ :a => 1, :b => 2 } | { :b => 1, :c => 2 } # => { :a => 1, :b => 2, :c => 2 }
Updated by alexeymuranov (Alexey Muranov) over 11 years ago
Just a thought about Hash#+
: maybe it can be used for merging only hashes with disjoint sets of keys, and return nil
otherwise?
Updated by matz (Yukihiro Matsumoto) over 11 years ago
I can imagine that would cause serious confusion among users. Raising exception might be better (but only just).
Matz.
Updated by sikachu (Prem Sichanugrist) over 11 years ago
I think this operator is really doesn't fit for Hash operation. While in a glance it might make sense, using #merge
like what we're doing right now actually make more sense when you see the code. You're merging two hashes (dictionaries) together, not adding one hash (dictionary) to the other.
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Related to Feature #9778: Bring shortcut methods to Hash added
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Related to deleted (Feature #9778: Bring shortcut methods to Hash)
Updated by nobu (Nobuyoshi Nakada) over 10 years ago
- Has duplicate Feature #9778: Bring shortcut methods to Hash added
Updated by shyouhei (Shyouhei Urabe) almost 4 years ago
- Has duplicate Feature #17384: shorthand of Hash#merge added