Project

General

Profile

Bug #13102

Confusing method name: Set#delete?

Added by kaikuchn (Kai Kuchenbecker) over 2 years ago. Updated over 2 years ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:78970]

Description

Greetings,

a colleague of mine who recently started to learn Ruby managed to greatly confuse me today when he used Set#delete? which he claimed would delete an item from a set.
Reading the documentation I suspect the method was meant to be named delete! as it behaves similiar to Array#uniq! and such methods.

If this is not a mistake, I'd still suggest to change the method name since I think it is very surprising for a method ending in a question mark to have a side effect.

Best regards,
Kai

History

Updated by kaikuchn (Kai Kuchenbecker) over 2 years ago

PS: This has been in the stdlib since at least 1.8.7 according to the docs.

Updated by kaikuchn (Kai Kuchenbecker) over 2 years ago

Ryan Davis wrote:

http://ruby-doc.org/stdlib-2.4.0/libdoc/set/rdoc/Set.html#method-i-delete-3F

Compare to regular delete, which always returns self...

Exactly, it is the duality we all know from methods such as Array's #uniq and #uniq!, #select and #select!, #flatten and #flatten! or String's #chomp and #chomp! etc.
It is the more dangerous version of Set#delete so, I'm pretty sure it should have a bang.

Updated by sos4nt (Stefan Schüßler) over 2 years ago

Kai Kuchenbecker wrote:

I think it is very surprising for a method ending in a question mark to have a side effect.

Indeed, that also applies to Set#add?.

It is the more dangerous version of Set#delete so, I'm pretty sure it should have a bang.

Not really, Set#delete also modifies the receiver.

The actual difference is that Set#delete always returns self, whereas Set#delete? only returns self if the element existed in the set, and nil otherwise.

it is the duality we all know from methods such as Array's #uniq and #uniq!, [...]

Not quite. If a class has a method with and without ! (e.g. uniq / uniq!), then the bang-method usually modifies the receiver (often returning nil to indicate "no changes") and and the non-bang method returns a new object.

If we had both, Set#delete and Set#delete!, I would expect the non-bang method to return a new set and the band method to modify the receiver.

That would be consistent but it would also break backwards compatibility.

Updated by kaikuchn (Kai Kuchenbecker) over 2 years ago

Stefan Schüßler wrote:

Not really, Set#delete also modifies the receiver.

The actual difference is that Set#delete always returns self, whereas Set#delete? only returns self if the element existed in the set, and nil otherwise.

it is the duality we all know from methods such as Array's #uniq and #uniq!, [...]

Not quite. If a class has a method with and without ! (e.g. uniq / uniq!), then the bang-method usually modifies the receiver (often returning nil to indicate "no changes") and and the non-bang method returns a new object.

If we had both, Set#delete and Set#delete!, I would expect the non-bang method to return a new set and the band method to modify the receiver.

That would be consistent but it would also break backwards compatibility.

Let me point you to this explanation on the use of bang in ruby method names: https://www.ruby-forum.com/topic/176830#773946
It is perpetually misunderstood for bang to mean that it "changes the receiver", it doesn't! You will see why I chose my wording as I did when you read the linked post written by Matz back in 2009.

However, you are right to point out that Set#delete does change the receiver, which means I wrongly stated that we have the duality we know from Array#uniq(!) and others. However, my main point still stands, it is weird to have Set#delete? delete an item from a set.

Updated by sos4nt (Stefan Schüßler) over 2 years ago

I was referring to the use of bang method names in the Ruby core library:

[...] In ruby core library the dangerous method implies that when a method ends with a bang (!), it indicates that unlike its non-bang equivalent, permanently modifies its receiver. Almost always, ruby core library will have a non-bang counterpart (method name which does NOT end with !) of every bang method (method name which does end with !) that does not modify the receiver. This convention is typically true for ruby core library but may or may not hold true for other ruby libraries.

Also available in: Atom PDF