Project

General

Profile

Feature #6225

Hash#+

Added by trans (Thomas Sawyer) over 7 years ago. Updated almost 6 years ago.

Status:
Rejected
Priority:
Normal
Target version:
[ruby-core:43904]

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


Related issues

Has duplicate Ruby master - Feature #9778: Bring shortcut methods to HashRejected04/27/2014Actions

History

Updated by mame (Yusuke Endoh) over 7 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 7 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 7 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 7 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 7 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 7 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 7 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 7 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 7 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 7 years ago

Would it be better to use Hash#<< instead of Hash#+?

Updated by trans (Thomas Sawyer) over 7 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 7 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 + 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 alexeymuranov (Alexey Muranov) over 7 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) over 6 years ago

  • Target version changed from 2.0.0 to 2.6

Updated by zzak (Zachary Scott) almost 6 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) almost 6 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) almost 6 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) almost 6 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 use set.rb which provides Set#+.

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) almost 6 years ago

There is another proposition, but for #reverse_merge: #7739.

Another relevant proposal: #7738.

Updated by drbrain (Eric Hodel) almost 6 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) almost 6 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 charliesome (Charlie Somerville) almost 6 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 charliesome (Charlie Somerville) almost 6 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) almost 6 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) almost 6 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) almost 6 years ago

I think new method proposal should be a new ticket.

Updated by alexeymuranov (Alexey Muranov) almost 6 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) almost 6 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) almost 6 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) almost 6 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) about 5 years ago

Updated by nobu (Nobuyoshi Nakada) about 5 years ago

  • Related to deleted (Feature #9778: Bring shortcut methods to Hash)

Updated by nobu (Nobuyoshi Nakada) about 5 years ago

  • Has duplicate Feature #9778: Bring shortcut methods to Hash added

Also available in: Atom PDF