Feature #14546
openHash#delete!
Description
Hash#delete currently returns nil if a given key is not found in the hash. It would be nice to have a way to check that the key was present in the hash. This can be accomplished with with a block, but it would be nice to have some sugar for this.
{ a: 'a' }.delete(:b) # => nil
{ a: 'a' }.delete(:b) { |key| raise KeyError, "key not found #{key}" } # => KeyError (key not found: b)
I'd like to propose a Hash#delete! method:
{ a: 'a' }.delete!(:a) # => 'a'
{ a: 'a' }.delete!(:b) # => KeyError (key not found: :b)
Files
Updated by nobu (Nobuyoshi Nakada) almost 7 years ago
Hash#delete
is destructive, so appending !
doesn't seem making sense.
Rather, a destructive version of Hash#fetch
feels better.
Updated by rringler (Ryan Ringler) almost 7 years ago
nobu (Nobuyoshi Nakada) wrote:
Hash#delete
is destructive, so appending!
doesn't seem making sense.
I'm as guilty of it as anyone, but as I understand !
does not mean destructive, but rather 'more dangerous', which I believe a possible exception qualifies for.
Updated by shevegen (Robert A. Heiler) almost 7 years ago
as I understand ! does not mean destructive, but rather
'more dangerous', which I believe a possible exception
qualifies for.
You may still have the issue of semantics.
For example, .fetch() semantic is different than .delete().
The way how I remember methods with a "!", even if this is
not the official one, is to think of the "!" as a "modify
in place" operation. If one thinks about it in this way
then .delete() already modifies in place so .delete!()
is not making a lot of sense. However had, please do not
think that I really mind either way - I am neutral on the
suggestion. Perhaps someone could mention it to matz
briefly in the next developer meeting since Ryan referred
to a comment from matz almost 10 years ago. :-)
Updated by marcandre (Marc-Andre Lafortune) almost 7 years ago
- Assignee set to matz (Yukihiro Matsumoto)
As Matz clearly stated, even if a long time ago, bang is not strictly for mutating versions of methods. Note that there is Process#exit!
(which is not a mutating version of Process#exit
). Rails also has many bang methods which aren't mutating, in particular ActiveRecord#save!
.
I'm in favor of delete!
.
Updated by duerst (Martin Dürst) almost 7 years ago
marcandre (Marc-Andre Lafortune) wrote:
As Matz clearly stated, even if a long time ago, bang is not strictly for mutating versions of methods. Note that there is
Process#exit!
(which is not a mutating version ofProcess#exit
). Rails also has many bang methods which aren't mutating, in particularActiveRecord#save!
.
It's clear that bang methods are not only for mutating versions of methods. However, it would be a bad idea to use a bang method in a context (such as delete) where it can be very easily mistaken as a mutating version (and by opposition, the non-bang method would be misunderstood as a non-mutating version). That's why I think it's a bad idea to use delete!
in the sense proposed above.
Updated by sawa (Tsuyoshi Sawada) almost 7 years ago
What is wrong with using fetch
?
{a: "a"}.fetch(:b) # => KeyError: key not found: :b
Updated by rringler (Ryan Ringler) almost 7 years ago
sawa (Tsuyoshi Sawada) wrote:
What is wrong with using
fetch
?{a: "a"}.fetch(:b) # => KeyError: key not found: :b
Hash#fetch is not mutative. This proposal is for a whiny version of #delete.
hsh = { a: 'a' }; hsh.delete!(:a); hsh # => {}
hsh = { a: 'a' }; hsh.delete!(:b); hsh # => KeyError (key not found: :b)
Updated by janosch-x (Janosch Müller) over 6 years ago
duerst (Martin Dürst) wrote:
it would be a bad idea to use a bang method in a context (such as delete) where it can be very easily mistaken as a mutating version (and by opposition, the non-bang method would be misunderstood as a non-mutating version).
I'm not sure that point holds in such a general way. E.g. I've never seen ActiveRecord::Base#destroy
being mistaken for a non-destructive version of #destroy!
.
In my opinion, the main reason why #delete!
feels confusing is that there are already #delete
and #delete!
implementations in Ruby that differ by destructiveness, e.g. on String. That is an unfortunate inconsistency when compared to Hash#delete
.
Maybe something like Hash#yank
could be introduced as an alias for delete and #yank!
as a whiny version. That could both serve the need stated by the OP and also undercut this existing inconsistency.
Updated by hsbt (Hiroshi SHIBATA) 9 months ago
- Status changed from Open to Assigned