4

In ruby, Array#delete(obj) will search and remove the specified object from the array. However, may be I'm missing something here but I found the returning value --- the obj itself --- is quite strange and a even a little bit useless.

My humble opinion is that in consistent with methods like sort/sort! and map/map! there should be two methods, e.g. delete/delete!, where

ary.delete(obj) -> new array, with obj removed
ary.delete!(obj) -> ary (after removing obj from ary)

For several reasons, first being that current delete is non-pure, and it should warn the programmer about that just like many other methods in Array (in fact the entire delete_??? family has this issue, they are quite dangerous methods!), second being that returning the obj is much less chainable than returning the new array, for example, if delete were like the above one I described, then I can do multiple deletions in one statement, or I can do something else after deletion:

ary = [1,2,2,2,3,3,3,4]
ary.delete(2).delete(3)      #=> [1,4], equivalent to "ary - [2,3]"
ary.delete(2).map{|x|x**2"}  #=> [1,9,9,9,16]

which is elegant and easy to read.

So I guess my question is: is this a deliberate design out of some reason, or is it just a heritage of the language?

2
  • Related: stackoverflow.com/a/26533811/1301972 Commented Nov 2, 2014 at 1:58
  • Array#delelte_if may do what you want: a=[1,2,3]; a.delete_if { |e| e==2 } => [1,3]; a=>[1,3] or [1,2,3].delete_if { |e| e==2 }.map { |e| e**2 } => [1, 9]. On the other hand, if arr.delete(3)... is often quite handy, and rather nicer than sz=arr.size; if sz-arr.delete.size > 0... (i.e., if delete returned the resulting array) . I don't think you can evaluate a method's spec in isolation of those of other methods. The Ruby language monks are pretty sharp and usually have a good reason for what they do. Commented Nov 2, 2014 at 3:35

3 Answers 3

4

If you already know that delete is always dangerous, there is no need to add a bang ! to further notice that it is dangerous. That is why it does not have it. Other methods like map may or may not be dangerous; that is why they have versions with and without the bang.

As for why it returns the extracted element, it provides access to information that is cumbersome to refer to if it were not designed like that. The original array after modification can easily be referred to by accessing the receiver, but the extracted element is not easily accessible.

Perhaps, you might be comparing this to methods that add elements, like push or unshift. These methods add elements irrespective of what elements the receiver array has, so returning the added element would be always the same as the argument passed, and you know it, so it is not helpful to return the added elements. Therefore, the modified array is returned, which is more helpful. For delete, whether the element is extracted depends on whether the receiver array has it, and you don't know that, so it is useful to have it as a return value.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you. Your answer is quite helpful. :)
0

For anyone who might be asking the same question, I think I understand it a little bit more now so I might as well share my approach to this question.

So the short answer is that ruby is not a language originally designed for functional programming, neither does it put purity of methods to its priority.

On the other hand, for my particular applications described in my question, we do have alternatives. The - method can be used as a pure alternative of delete in most situations, for example, the code in my question can be implemented like this:

ary = [1,2,2,2,3,3,3,4]
ary.-([2]).-([3])         #=> [1,4], or simply ary.-([2,3])
ary.-([2]).map{|x|x**2"}  #=> [1,9,9,9,16]

and you can happily get all the benefits from the purity of -. For delete_if, I guess in most situations select (with return value negated) could be a not-so-great pure candidate.

As for why delete family was designed like this, I think it's more of a difference in point of view. They are supposed to be more of shorthands for commonly needed non-pure procedures than to be juxtaposed with functional-flavored select, map, etc.

Comments

0

I’ve wondered some of these same things myself. What I’ve largely concluded is that the method simply has a misleading name that carries with it false expectations. Those false expectations are what trigger our curiosity as to why the method works like it does. Bottom line—I think it’s a super useful method that we wouldn’t be questioning if it had a name like “swipe_at” or “steal_at”.

Anyway, another alternative we have is values_at(*args) which is functionally the opposite of delete_at in that you specify what you want to keep and then you get the modified array (as opposed to specifying what you want to remove and then getting the removed item).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.