Greetings,
Geert.
That's beside the point, for two reasons:
1) Geert's question is regarding the lack of symmetry between the
presence of Array#reject! but absence of Array#select!.[1]
2) Geert is interested in in-place mutators (Array#reject!,
Array#select!). Enumerable#partition returns two new Arrays; it is not
an in-place mutator.
As far as work-arounds, this would probably be closest:
class Array
def select!
self.reject! { |e| not yield e }
end
end
But I'm sure Geert is already aware of this (or a better version).
Geert's question, to which I would like an answer as well, is this:
Is there a reason Array#select! doesn't exist in the core?
Jacob Fugal
On Thu, 6 Oct 2005, Jacob Fugal wrote:
> Is there a reason Array#select! doesn't exist in the core?
It seems like a strange concept to me. I don't associate
destructiveness with selecting. I guess there would also be find_all!
which seems even stranger :-)
I know one *can* implement it (i.e., I'm not saying I don't know what
it means). I just don't think that in-place removal of items follows
naturally as a ! version of selecting.
David
--
David A. Black
dbl...@wobblini.net
Well, maybe select! isn't the right name for it. But as a concept,
including the converse of reject! in the core would make sense, at
least to me. Maybe with a name like Array#keep!, telling ruby which
elements you want to keep and discarding the rest.
Jacob Fugal
In message "Re: select! not present but reject! is"
on Thu, 6 Oct 2005 06:47:35 +0900, "David A. Black" <dbl...@wobblini.net> writes:
|> Is there a reason Array#select! doesn't exist in the core?
|
|It seems like a strange concept to me. I don't associate
|destructiveness with selecting. I guess there would also be find_all!
|which seems even stranger :-)
That is a reason. For the same reason, we didn't implement map!, but
certain number of native speakers persuade me it was not unnatural.
Now we have map! in Array class. Same thing could happen on select!.
matz.
You don't watch enough reality television. The fun of selecting
winners on this week's episode is rejecting everyone else. I also
don't think of reject as non-destructive, but there it is.
I think the exclamation paradigm overrides the subjective connotation
of select and reject. Regardless of whether or not someone uses it in
their own code, I doubt anyone would be confused by the meaning.
Select and reject are perfect compliments. I have, on several
occasions, tried to use select!, but had to rewrite them with reject!
instead (not a difficult transition).
As for find_all!, that's just hard to read (and hard to distinguish
from find_all with many fonts), so I would never use it. Then again,
find_all (regardless of its relationship to select and reject) comes
off as an extension of find, and the correlating find! method would be
silly (although fitting with the reality television metaphor).
> That is a reason. For the same reason, we didn't implement map!, but
> certain number of native speakers persuade me it was not unnatural.
> Now we have map! in Array class. Same thing could happen on select!.
I'll cast my vote for Array#select!, natively speaking.
--
Rob (rambling with large words)
On Fri, 7 Oct 2005, Rob Rypka wrote:
> I think the exclamation paradigm overrides the subjective connotation
> of select and reject. Regardless of whether or not someone uses it in
> their own code, I doubt anyone would be confused by the meaning.
I'm still not feeling a "dangerous version of select". It seems such
a benign operation :-)
> Select and reject are perfect compliments. I have, on several
> occasions, tried to use select!, but had to rewrite them with reject!
> instead (not a difficult transition).
>
> As for find_all!, that's just hard to read (and hard to distinguish
> from find_all with many fonts), so I would never use it. Then again,
> find_all (regardless of its relationship to select and reject) comes
It's a synonym for select; they call the same method. That's a pretty
hard relationship to disregard :-)
> off as an extension of find, and the correlating find! method would be
> silly (although fitting with the reality television metaphor).
In the middle of writing this I finally got a handle on what bothers
me about select! as (I think) it's being discussed: it's backwards.
If you select! elements from an array (dangerous/destructive select),
those elements should be *removed* from the array. It's like
selecting people from the audience to come onto the stage: they are
removed from the audience. The audience is not reduced to being just
them.
At the same time, the return value of select! should be an array of
the selected items. The ! part would mean: they've been *permanently
selected* (withdrawn from the array).
Here's a whole little testbed for this. In this form it would make
some sense, though I'm still not happy about the find_all! thing....
class Array
def select!
yes,no = partition {|e| yield(e) }
replace(no)
yes
end
end
a = [1,2,3,4]
b = a.reject! {|e| e > 2 }
p a
p b
a = [1,2,3,4]
b = a.select! {|e| e > 2 }
p a
p b
# Output:
[1, 2]
[1, 2]
[1, 2]
[3, 4]
Hmm, I'd disagree. After all, we're sending the message to the array
aren't we? I look at it like John the Innocent Array has five apples,
two shiny and three dull. I come along, as the wise programmer, and
say to Johnny, "Johnny, shiny apples are good. You only need to keep
those ones." In Ruby:
johnny = []
2.times { johnny << ShinyApple.new }
3.times { johnny << DullApple.new }
# ... later ...
johnny.select! { |a| a.shiny? }
An alternate way to tell this to Johnny would be, "Johnny, shiny
apples are good. You should get rid of any others." In Ruby:
johnny.reject! { |a| not a.shiny? }
However, negating the positive condition (a.shiny?) isn't very
readable. Syntactically, it is really as easy as "not ( condition )",
but if condition is long, it may be confusing to try and keep track of
the ands/ors in condition and then mentally negate it all. Not to
mention that reject! { not } is a double negative, and we all know how
bad those can be (/me temporarily flashes back to second grade...
shudder). Or we can apply DeMorgan's to try and get rid of the not,
but that often muddles the semantics of the condition.
In short, select! is just the converse of reject!, and there's no good
reason not to include it under that context.
Jacob Fugal
On Fri, 7 Oct 2005, Jacob Fugal wrote:
> On 10/6/05, David A. Black <dbl...@wobblini.net> wrote:
>> ...
>>
>> In the middle of writing this I finally got a handle on what bothers
>> me about select! as (I think) it's being discussed: it's backwards.
>>
>> If you select! elements from an array (dangerous/destructive select),
>> those elements should be *removed* from the array. It's like
>> selecting people from the audience to come onto the stage: they are
>> removed from the audience. The audience is not reduced to being just
>> them.
>
> Hmm, I'd disagree. After all, we're sending the message to the array
> aren't we?
That's true across the board, though; it's not a determinant of what
happens when we send a message.
> I look at it like John the Innocent Array has five apples,
> two shiny and three dull. I come along, as the wise programmer, and
> say to Johnny, "Johnny, shiny apples are good. You only need to keep
> those ones." In Ruby:
>
> johnny = []
> 2.times { johnny << ShinyApple.new }
> 3.times { johnny << DullApple.new }
>
> # ... later ...
>
> johnny.select! { |a| a.shiny? }
Or you could look at it as: "Give me (permanently) all your shiny
apples!"
my_apples = johnny.select! {|a| a.shiny? }
So now my_apples has them, and johnny doesn't. Mind you, I'm not
eager to see my version in the language either. I don't like the bang
method not returning the receiver. But I don't like the semantics, in
this case, when it does. (And the find_all! thing is a further sign
that this method was not meant to have a bang version.)
I think there's been talk in the past of delete_unless. delete_if is
not quite the same as reject! (one of them returns nil if nothing's
found; the other returns an array, I believe).
But the exclamation mark (to me) says, "Do this to yourself, Mr.
Array." When you tell the array to reject!, it throws away the
matches and says, "Here's my state now, what next?" or "Whoops, I
didn't do anything." I think the same should be applicable for
select.
> Or you could look at it as: "Give me (permanently) all your shiny
> apples!"
>
> my_apples = johnny.select! {|a| a.shiny? }
>
> So now my_apples has them, and johnny doesn't. Mind you, I'm not
> eager to see my version in the language either. I don't like the bang
> method not returning the receiver. But I don't like the semantics, in
> this case, when it does. (And the find_all! thing is a further sign
> that this method was not meant to have a bang version.)
Well, I think we should have a Array#gimme and Array#gimme! to
differentiate from select!. Then you would have your functionality,
while select! would say (as I think it should), "select these
(permanently)."
By your logic, reject! is also wrong. johnny.reject! should reject
the items, and then give them to you, which is the same as your
select!. That's not what it does, though...
Regarding find_all!, Just because they're synonyms, doesn't mean they
have to both have the !. If everyone instantly associates select and
find_all together because they're synonyms, why have them both? I
don't think they do. People see 'find' and they think, "But I want to
find everything, not just one," and then they come upon find_all.
With select and reject, it says, "pick these," and "pick everything
but these." Just because they end up meaning the same thing, doesn't
mean they have the same connotations.
find and find_all are the benign operations. select and reject are more risque.
> I think there's been talk in the past of delete_unless. delete_if is
> not quite the same as reject! (one of them returns nil if nothing's
> found; the other returns an array, I believe).
I believe you are correct (about reject! and delete_if, I don't know
about the others).
In all honesty, I don't care what it's called, but reject! feels like
it should have an opposite.
--
Rob (Pontificating at a Late Hour)
I vote for Array#winnow
On Fri, 7 Oct 2005, Rob Rypka wrote:
> By your logic, reject! is also wrong. johnny.reject! should reject
> the items, and then give them to you, which is the same as your
> select!. That's not what it does, though...
See my previous post -- it shows the difference (between reject! and
my sense of select!), which is in the return values.
> In all honesty, I don't care what it's called, but reject! feels like
> it should have an opposite.
Similarly (in case it's unclear), I have no underlying objection to
the idea of a reject! opposite :-)
And that's where it confuses me. select and reject are complements, so
why couldn't it be expected that select! and reject! be complements as
well? Changing the semantics of select from converse of reject without
bang to synonym for reject (differing only in return value) with bang
makes no sense at all to me.
> > In all honesty, I don't care what it's called, but reject! feels like
> > it should have an opposite.
>
> Similarly (in case it's unclear), I have no underlying objection to
> the idea of a reject! opposite :-)
At least we're all agreed on that. :)
I just fail to see why select should lose it's complementary
relationship with reject when a bang is added. I suggest we retain
that relationship and let select! and reject! remain complementary.
With select and reject we have the following tautology[1]:
def test(ary)
selected = ary.select { |e| yield e }
rejected = ary.reject { |e| yield e }
rebuilt = selected + rejected
(rebuilt - ary).empty? and (ary - rebuilt).empty?
end
I propose select! and reject! should have a similar tautology:
def test(ary)
selected = ary.dup.select! { |e| yield e }
rejected = ary.dup.reject! { |e| yield e }
rebuilt = selected + rejected
(rebuilt - ary).empty? and (ary - rebuilt).empty?
end
Jacob Fugal
On Fri, 7 Oct 2005, Jacob Fugal wrote:
> On 10/7/05, David A. Black <dbl...@wobblini.net> wrote:
>> Hi --
>>
>> On Fri, 7 Oct 2005, Rob Rypka wrote:
>>
>>> By your logic, reject! is also wrong. johnny.reject! should reject
>>> the items, and then give them to you, which is the same as your
>>> select!. That's not what it does, though...
>>
>> See my previous post -- it shows the difference (between reject! and
>> my sense of select!), which is in the return values.
>
> And that's where it confuses me. select and reject are complements, so
> why couldn't it be expected that select! and reject! be complements as
> well? Changing the semantics of select from converse of reject without
> bang to synonym for reject (differing only in return value) with bang
> makes no sense at all to me.
I completely understand, and I'm the first to admit I've failed to
convey clearly what it is that makes me not feel that the
complementariness carries over to the bang versions, or why I like
"select" for culling elements that pass a test but don't like
"select!" for replacing the array's contents with elements that pass a
test. So I'll have to leave it at that, except that if a brilliant
explanatory model comes to me I'll share it :-)
The english words "select" and "reject" are not opposites. "reject"
and "keep" might be, as someone else suggested.
Going back, say you have a box of apples, some of which are shiny, the
rest of which are dull. You don't want the dull ones. If you say:
apple_box.reject! {|apple| apple.dull?}
..it sounds like you want to reject, or throw out, any dull apples,
leaving only the shiny ones. The opposite would be:
apple_box.keep! {|apple| apple.shiny?}
..because you want to keep only the shiny ones. "keep" implies that
the rest are not kept, and are thrown out.
On the other hand, if you said:
apple_box.select! {|apple| apple.shiny?}
It implies that you want to keep both; you remove the selected ones
from the box, and leave the unselected ones behind.
Note that your tautology (as written) for select!/reject! works for
this version also. "select!" would return an array of the values
removed from the apple_box.
Also, I'm not really advocating any action here. I'm just suggesting
that it would be a little weird for "select!" to be the exact opposite
of "reject!", since the Ruby definitions wouldn't stand up to the
English ones.
cheers,
Mark
Funny thing is, it was me that suggested 'keep!'. :) But my argument
isn't that "select" and "reject" are necessarily opposites in English,
but that the *existing* non-bang versions of "select" and "reject" in
Ruby *are*.
> Going back, say you have a box of apples, some of which are shiny, the
> rest of which are dull. You don't want the dull ones. If you say:
>
> apple_box.reject! {|apple| apple.dull?}
>
> ...it sounds like you want to reject, or throw out, any dull apples,
> leaving only the shiny ones. The opposite would be:
>
> apple_box.keep! {|apple| apple.shiny?}
>
> ...because you want to keep only the shiny ones. "keep" implies that
> the rest are not kept, and are thrown out.
>
> On the other hand, if you said:
>
> apple_box.select! {|apple| apple.shiny?}
>
> It implies that you want to keep both; you remove the selected ones
> from the box, and leave the unselected ones behind.
The English usage of "select" could imply that, and I think that's
what bothers David as well. But, again, my goal isn't consistency with
English (although some of my previous posts in this thread may have
appeared that way), but rather consistency within Ruby. "select" and
"reject" are already direct opposites, so in my mind "select!" and
"reject!" should also be direct opposites.
> Note that your tautology (as written) for select!/reject! works for
> this version also. "select!" would return an array of the values
> removed from the apple_box.
Yes, but this is actually incidental and buggy. I'm of the camp which
prefers any bang method should return either self (for chaining) or
nil. I wouldn't want select!/reject! to return either the selected or
rejected elements. Rather, my example should have been:
def test( ary )
(selected = ary.dup).select! { |e| yield e }
(rejected = ary.dup).reject! { |e| yield e }
rebuilt = selected + rejected
(rebuilt - ary).empty? and (ary - rebuilt).empty?
end
Under David's interpretation of "select!", this function would rarely
return true, whereas I would expect it to always return true.
> Also, I'm not really advocating any action here. I'm just suggesting
> that it would be a little weird for "select!" to be the exact opposite
> of "reject!", since the Ruby definitions wouldn't stand up to the
> English ones.
I'll concede that, but IMNSHO consistency between the non-bang and
bang versions seems more important.
Jacob Fugal
select and reject (without the exclamation marks) are Ruby opposites,
though. Nobody seems opposed to that.
If I had two methods, Array#foo and Array#foo!, I would expect the
definition of foo! to be:
"Same as Array#foo, but modifies the receiver in place."
Sometimes, the above leads to another (near) synonym (like delete_if
and reject!), but the The return value should be the receiver,
instead of a new array. To me, foo! doesn't mean finding a new
meaning of the foo operation in a way that would be destructive, it
means immediacy to the receiver (which in turn implies destruction).
"Select these elements, but alter your contents and return yourself,
instead of someone new."
Anyways, there seems to be enough opposition to select! that Matz
probably isn't going to add it. I give up the fight (even though I
still believe I'm right). I'm going to have to learn to live with
reject!ion (but not select!ion).
Aside: I second the vote for Array#winnow :-)
--
Rob
Jacob and others are free to continue the fight in my pseudo-absense :-)
--
Rob
The most important thing, though, is that every method name be
appropriate. If select! ("dangerous select") is the best way to
communicate the "delete unless..." process, then it's right. If not,
then not. It's reasonable to expect that a/b == a!/b! -- but the
existence of a, b, and a! doesn't mean that b! is a good method name
for the inverse of a!.
On Sat, 8 Oct 2005, Rob Rypka wrote:
> On 10/7/05, Mark Hubbart <discor...@gmail.com> wrote:
>> Also, I'm not really advocating any action here. I'm just suggesting
>> that it would be a little weird for "select!" to be the exact opposite
>> of "reject!", since the Ruby definitions wouldn't stand up to the
>> English ones.
>
> select and reject (without the exclamation marks) are Ruby opposites,
> though. Nobody seems opposed to that.
I hadn't thought we were talking about them. They seem OK to me,
though I could imagine reject actually being an in-place operation
even without the !.
> If I had two methods, Array#foo and Array#foo!, I would expect the
> definition of foo! to be:
>
> "Same as Array#foo, but modifies the receiver in place."
See below about !, but also: I question what "select a subarray from
an array, in place" means. It sounds to me like the selected subarray
is *removed* from the array. Replacing the array with the selected
subarray seems to me to be a second transaction, not a select
operation per se.
> Sometimes, the above leads to another (near) synonym (like delete_if
> and reject!), but the The return value should be the receiver,
> instead of a new array. To me, foo! doesn't mean finding a new
> meaning of the foo operation in a way that would be destructive, it
> means immediacy to the receiver (which in turn implies destruction).
> "Select these elements, but alter your contents and return yourself,
> instead of someone new."
The ! doesn't mean that a method modifies the receiver in place,
though, but rather that this is a "dangerous" version of the method
and should be used carefully. The "danger" often has to do with
in-place change, but ! itself doesn't mean that.
We can agree on this, I suppose. Though I, personally, would like
select! to be the opposite of reject!, I don't need it -- as long as
there is *something* that's the opposite of reject!. Maybe keep!,
retain!, keep_only!, restrict! (or winnow!).
Most of my resistance was to the idea of having select!, but with a
function that wasn't converse to reject!. Reading more carefully
through past posts, I see now that you didn't mean select! should
exist with the alternate meaning, but that the possible alternate
meaning makes select! a bad naming choice. I don't quite agree on
that, but in the name of civility, we can just drop select! from the
discussion altogether and begin thinking of other names for the
converse of reject!. Sound good? :)
Jacob Fugal
On 10/7/05, David A. Black <dbl...@wobblini.net> wrote:
> I hadn't thought we were talking about them. They seem OK to me,
> though I could imagine reject actually being an in-place operation
> even without the !.
I had tried (and failed) to make this point earlier.
> The ! doesn't mean that a method modifies the receiver in place,
> though, but rather that this is a "dangerous" version of the method
> and should be used carefully. The "danger" often has to do with
> in-place change, but ! itself doesn't mean that.
I stand (somewhat) corrected. I had assumed some things based on
Pickaxe and my own delusional perspective into this world.
Before now, I had never been able to find information on the bang,
because I hadn't yet reduced my search results to replies from Matz.
Here's the relevant quote from [ruby-talk:02331]:
"Unlike Scheme, not all change-in-place functions are named with
exclamation mark. In Ruby, exclamation mark means `MORE dangerous',
or `may cause surprise' than non-bang counterpart, i.g. in-place
modification by `gsub!' may let you surprise, comparing copying
`gsub'."
I'm not trying to be mean by nit-picking a non-native speaker's
English, I'd like some clarification. I knew that methods existed
that modified the object without !, but their names were pretty clear
(e.g., delete_if). I thought the ! was there to imply modification of
the receiver, which could lead to unexpected results if used on a
function argument.
Are there any ! methods that don't modify the receiver? Are there any
! methods that do not have normal "non-dangerous" counterparts?
I can't think of anything that would not modify the object, but be
considered "dangerous," unless it's going to cause your sysadmin to
come to your office and beat you with a shovel.
Then again, the proposed select! seems to have caused you surprise, so
I think the name still fits :-)
I think select! is the right name for a proposed companion to reject!,
but others don't, so I'm open. It's funny how I seem to argue most
about things that don't really matter to me (like the name of this
method).
--
Rob
> Are there any ! methods that don't modify the receiver?
exit!
(Kind of an edge case, eh ;-)
Regards,
Bill
Perhaps not, but in this case, inconsistency would be unforgivable.
You should be able to predict how a method will work based on your
knowledge of how other, similar methods work.
In this case it's absolutely clear.
arr = (1..10).to_a
arr.map! { |n| n*n } # -> arr == [1,4,9,...,100]; self is returned
arr = (1..10).to_a
arr.reject! { |n| n % 3 == 0 } # -> arr == [1,2,4,5,7,8]; self is
returned
arr = (1..10).to_a
arr.select! { |n| n % 2 == 0 } # -> arr == [1,3,5,7,9]; self is
returned
It's a no-brainer. Consistency is paramount!
Cheers,
Gavin
On Sat, 8 Oct 2005, Gavin Sinclair wrote:
> David A. Black wrote:
>> On Sat, 8 Oct 2005, Jacob Fugal wrote:
>>
>>> On 10/7/05, Mark Hubbart <discor...@gmail.com> wrote:
>>>
>>>> Also, I'm not really advocating any action here. I'm just suggesting
>>>> that it would be a little weird for "select!" to be the exact opposite
>>>> of "reject!", since the Ruby definitions wouldn't stand up to the
>>>> English ones.
>>>
>>> I'll concede that, but IMNSHO consistency between the non-bang and
>>> bang versions seems more important.
>>
>> The most important thing, though, is that every method name be
>> appropriate. If select! ("dangerous select") is the best way to
>> communicate the "delete unless..." process, then it's right. If not,
>> then not. It's reasonable to expect that a/b == a!/b! -- but the
>> existence of a, b, and a! doesn't mean that b! is a good method name
>> for the inverse of a!.
>
> Perhaps not, but in this case, inconsistency would be unforgivable.
As I've said repeatedly, I am *not* suggesting that Ruby adopt a
select! method that does something other than the opposite of reject!.
I am suggesting that Ruby *not* adopt a select! method at all, because
select! is (in my view) a bad name for a method that does the opposite
of reject!, and having it do anything else would be confusing.
> You should be able to predict how a method will work based on your
> knowledge of how other, similar methods work.
>
> In this case it's absolutely clear.
See earlier in thread -- there's been a lot of discussion and
disagreement.
> arr = (1..10).to_a
> arr.select! { |n| n % 2 == 0 } # -> arr == [1,3,5,7,9]; self is
> returned
>
> It's a no-brainer. Consistency is paramount!
Your select! works exactly like reject!. That might be a bit too much
consistency :-)
> > arr = (1..10).to_a
> > arr.select! { |n| n % 2 == 0 } # -> arr == [1,3,5,7,9]; self is
> > returned
> >
> > It's a no-brainer. Consistency is paramount!
>
> Your select! works exactly like reject!. That might be a bit too much
> consistency :-)
Ah, you can never have too much consistency... :)
Gavin
> The ! doesn't mean that a method modifies the receiver in place,
> though, but rather that this is a "dangerous" version of the method
> and should be used carefully. The "danger" often has to do with
> in-place change, but ! itself doesn't mean that.
True, but the large majority of ! methods are simply in-place
equivalents of their non-bang friends:
---Instance
methods------------------------------------------------------------
Hash#merge!
hsh.merge!(other_hash) => hsh
hsh.update(other_hash) => hsh
hsh.merge!(other_hash){|key, oldval, newval| block} => hsh
hsh.update(other_hash){|key, oldval, newval| block} => hsh
------------------------------------------------------------------------
Adds the contents of _other_hash_ to _hsh_, overwriting entries
with duplicate keys with those from _other_hash_.
h1 = { "a" => 100, "b" => 200 }
h2 = { "b" => 254, "c" => 300 }
h1.merge!(h2) #=> {"a"=>100, "b"=>254, "c"=>300}
----------------------------------------------------------- Hash#reject!
hsh.reject! {| key, value | block } -> hsh or nil
------------------------------------------------------------------------
Equivalent to +Hash#delete_if+, but returns +nil+ if no changes
were made.
------------------------------------------------------------ Array#uniq!
array.uniq! -> array or nil
------------------------------------------------------------------------
Removes duplicate elements from _self_. Returns +nil+ if no changes
are made (that is, no duplicates are found).
a = [ "a", "a", "b", "b", "c" ]
a.uniq! #=> ["a", "b", "c"]
b = [ "a", "b", "c" ]
b.uniq! #=> nil
----------------------------------------------------------- Array#slice!
array.slice!(index) -> obj or nil
array.slice!(start, length) -> sub_array or nil
array.slice!(range) -> sub_array or nil
------------------------------------------------------------------------
Deletes the element(s) given by an index (optionally with a length)
or by a range. Returns the deleted object, subarray, or +nil+ if
the index is out of range. Equivalent to:
def slice!(*args)
result = self[*args]
self[*args] = nil
result
end
a = [ "a", "b", "c" ]
a.slice!(1) #=> "b"
a #=> ["a", "c"]
a.slice!(-1) #=> "c"
a #=> ["a"]
a.slice!(100) #=> nil
a #=> ["a"]
------------------------------------------------------------ Array#sort!
array.sort! -> array
array.sort! {| a,b | block } -> array
------------------------------------------------------------------------
Sorts _self_. Comparisons for the sort will be done using the +<=>+
operator or using an optional code block. The block implements a
comparison between _a_ and _b_, returning -1, 0, or +1. See also
+Enumerable#sort_by+.
a = [ "d", "a", "e", "c", "b" ]
a.sort #=> ["a", "b", "c", "d", "e"]
a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
--------------------------------------------------------- Array#collect!
array.collect! {|item| block } -> array
array.map! {|item| block } -> array
------------------------------------------------------------------------
Invokes the block once for each element of _self_, replacing the
element with the value returned by _block_. See also
+Enumerable#collect+.
a = [ "a", "b", "c", "d" ]
a.collect! {|x| x + "!" }
a #=> [ "a!", "b!", "c!", "d!" ]
--------------------------------------------------------- Array#compact!
array.compact! -> array or nil
------------------------------------------------------------------------
Removes +nil+ elements from array. Returns +nil+ if no changes were
made.
[ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
[ "a", "b", "c" ].compact! #=> nil
---------------------------------------------------------- Array#reject!
array.reject! {|item| block } -> array or nil
------------------------------------------------------------------------
Equivalent to +Array#delete_if+, deleting elements from _self_ for
which the block evaluates to true, but returns +nil+ if no changes
were made. Also see +Enumerable#reject+.
--------------------------------------------------------- Array#reverse!
array.reverse! -> array
------------------------------------------------------------------------
Reverses _self_ in place.
a = [ "a", "b", "c" ]
a.reverse! #=> ["c", "b", "a"]
a #=> ["c", "b", "a"]
------------------------------------------------------------- Array#map!
array.collect! {|item| block } -> array
array.map! {|item| block } -> array
------------------------------------------------------------------------
Invokes the block once for each element of _self_, replacing the
element with the value returned by _block_. See also
+Enumerable#collect+.
a = [ "a", "b", "c", "d" ]
a.collect! {|x| x + "!" }
a #=> [ "a!", "b!", "c!", "d!" ]
--------------------------------------------------------- Array#flatten!
array.flatten! -> array or nil
------------------------------------------------------------------------
Flattens _self_ in place. Returns +nil+ if no modifications were
made (i.e., _array_ contains no subarrays.)
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten! #=> [1, 2, 3, 4, 5]
a.flatten! #=> nil
a #=> [1, 2, 3, 4, 5]
----------------------------------------------------------- String#gsub!
str.gsub!(pattern, replacement) => str or nil
str.gsub!(pattern) {|match| block } => str or nil
------------------------------------------------------------------------
Performs the substitutions of +String#gsub+ in place, returning
_str_, or +nil+ if no substitutions were performed.
----------------------------------------------------------- String#succ!
str.succ! => str
str.next! => str
------------------------------------------------------------------------
Equivalent to +String#succ+, but modifies the receiver in place.
------------------------------------------------------- String#downcase!
str.downcase! => str or nil
------------------------------------------------------------------------
Downcases the contents of _str_, returning +nil+ if no changes were
made.
-------------------------------------------------------- String#squeeze!
str.squeeze!([other_str]*) => str or nil
------------------------------------------------------------------------
Squeezes _str_ in place, returning either _str_, or +nil+ if no
changes were made.
--------------------------------------------------------- String#rstrip!
str.rstrip! => self or nil
------------------------------------------------------------------------
Removes trailing whitespace from _str_, returning +nil+ if no
change was made. See also +String#lstrip!+ and +String#strip!+.
" hello ".rstrip #=> " hello"
"hello".rstrip! #=> nil
---------------------------------------------------------- String#slice!
str.slice!(fixnum) => fixnum or nil
str.slice!(fixnum, fixnum) => new_str or nil
str.slice!(range) => new_str or nil
str.slice!(regexp) => new_str or nil
str.slice!(other_str) => new_str or nil
------------------------------------------------------------------------
Deletes the specified portion from _str_, and returns the portion
deleted. The forms that take a +Fixnum+ will raise an +IndexError+
if the value is out of range; the +Range+ form will raise a
+RangeError+, and the +Regexp+ and +String+ forms will silently
ignore the assignment.
string = "this is a string"
string.slice!(2) #=> 105
string.slice!(3..6) #=> " is "
string.slice!(/s.*t/) #=> "sa st"
string.slice!("r") #=> "r"
string #=> "thing"
----------------------------------------------------------- String#chop!
str.chop! => str or nil
------------------------------------------------------------------------
Processes _str_ as for +String#chop+, returning _str_, or +nil+ if
_str_ is the empty string. See also +String#chomp!+.
----------------------------------------------------- String#capitalize!
str.capitalize! => str or nil
------------------------------------------------------------------------
Modifies _str_ by converting the first character to uppercase and
the remainder to lowercase. Returns +nil+ if no changes are made.
a = "hello"
a.capitalize! #=> "Hello"
a #=> "Hello"
a.capitalize! #=> nil
------------------------------------------------------------- String#tr!
str.tr!(from_str, to_str) => str or nil
------------------------------------------------------------------------
Translates _str_ in place, using the same rules as +String#tr+.
Returns _str_, or +nil+ if no changes were made.
----------------------------------------------------------- String#next!
str.succ! => str
str.next! => str
------------------------------------------------------------------------
Equivalent to +String#succ+, but modifies the receiver in place.
---------------------------------------------------------- String#chomp!
str.chomp!(separator=$/) => str or nil
------------------------------------------------------------------------
Modifies _str_ in place as described for +String#chomp+, returning
_str_, or +nil+ if no modifications were made.
------------------------------------------------------- String#swapcase!
str.swapcase! => str or nil
------------------------------------------------------------------------
Equivalent to +String#swapcase+, but modifies the receiver in
place, returning _str_, or +nil+ if no changes were made.
-------------------------------------------------------- String#reverse!
str.reverse! => str
------------------------------------------------------------------------
Reverses _str_ in place.
----------------------------------------------------------- String#tr_s!
str.tr_s!(from_str, to_str) => str or nil
------------------------------------------------------------------------
Performs +String#tr_s+ processing on _str_ in place, returning
_str_, or +nil+ if no changes were made.
---------------------------------------------------------- String#strip!
str.strip! => str or nil
------------------------------------------------------------------------
Removes leading and trailing whitespace from _str_. Returns +nil+
if _str_ was not altered.
------------------------------------------------------------ String#sub!
str.sub!(pattern, replacement) => str or nil
str.sub!(pattern) {|match| block } => str or nil
------------------------------------------------------------------------
Performs the substitutions of +String#sub+ in place, returning
_str_, or +nil+ if no substitutions were performed.
--------------------------------------------------------- String#upcase!
str.upcase! => str or nil
------------------------------------------------------------------------
Upcases the contents of _str_, returning +nil+ if no changes were
made.
--------------------------------------------------------- String#delete!
str.delete!([other_str]+>) => str or nil
------------------------------------------------------------------------
Performs a +delete+ operation in place, returning _str_, or +nil+
if _str_ was not modified.
--------------------------------------------------------- String#lstrip!
str.lstrip! => self or nil
------------------------------------------------------------------------
Removes leading whitespace from _str_, returning +nil+ if no change
was made. See also +String#rstrip!+ and +String#strip!+.
" hello ".lstrip #=> "hello "
"hello".lstrip! #=> nil
---Singleton
methods---------------------------------------------------------
Process::exit!
Process.exit!(fixnum=-1)
------------------------------------------------------------------------
Exits the process immediately. No exit handlers are run. _fixnum_
is returned to the underlying system as the exit status.
Process.exit!(0)
Nonetheless, I don't care about select!. Someone made a comment, err,
somewhere, about how all the stupid shit gets bantered to death simply
because more people understand it. It might have been Jason Hunter (of
JDOM fame). Not sure. It was funny, though.
Devin
And yes, it's merely a coincidence that the exception to the rule is the
last one in this list... ;)
> David A. Black wrote:
>
>> The ! doesn't mean that a method modifies the receiver in place,
>> though, but rather that this is a "dangerous" version of the method
>> and should be used carefully. The "danger" often has to do with
>> in-place change, but ! itself doesn't mean that.
>
> True, but the large majority of ! methods are simply in-place
> equivalents of their non-bang friends:
Wow. I just executed circular logic perfectly! Good night, all.
Devin
(Also, apologies to those who didn't want to see a curse word in my last
email. Really, judgment impaired. Good night. :)
On Sat, 8 Oct 2005, Devin Mullins wrote:
> David A. Black wrote:
>
>> The ! doesn't mean that a method modifies the receiver in place,
>> though, but rather that this is a "dangerous" version of the method
>> and should be used carefully. The "danger" often has to do with
>> in-place change, but ! itself doesn't mean that.
>
> True, but the large majority of ! methods are simply in-place equivalents of
> their non-bang friends:
[hundreds of lines of ri output snipped :-]
Heavens -- I think we all knew that already :-) There's one that I
don't think you included: Tempfile#close! which closes and unlinks the
file.
One reason I think it's useful to remember the real meaning of ! is
that gives one a potentially useful tool to use in one's own classes.
I don't know how many people actually write bang methods. I've done
it once or twice.
You're probably thinking about this:
http://www.unixguide.net/freebsd/faq/16.19.shtml
martin
an interesting question, i seem to do it alot:
jib:~/eg/ruby > find -name '*rb'|xargs -n1 egrep '^\s*def [^;(]+\!'|sort -u
def add!
def chop!
def close!
def close!
def collect!
def Complex.new!(a, b=0)
def ConfigTable.get_entry!(name)
def delete!(del)
def diagonal!(val=1)
def error! #:nodoc:
def escape! char, esc = 0x5c.chr
def escape! s, char, esc
def escape! s, char, esc
def escape! s, char, esc
def expand! string, opts = {}
def expand! string, variables = {}
def flatten!
def free!
def give_up!
def give_up! label = 'attempt'
def indent!
def maim!(pid, *sigs)
def map!
def map!
def mask!(mask)
def merge!(oth)
def next! implementation_changed = true, interface_changed = false, backwards_compatible = false
def normalize!
def order!(argv = ARGV, &nonopt)
def order!(&blk) options.order!(self, &blk) end
def parse!(argv = ARGV)
def parse!() options.parse!(self) end
def permute!(argv = ARGV)
def permute!() options.permute!(self) end
def Rational.new!(num, den = 1)
def reject!
def reject! &block
def reject! &block
def replace!(oth)
def select!( ypath_str )
def slice!(*args)
def squeeze!(del=nil)
def succ!
def test_collect!
def test_reject!
def tr!(from, to)
def tr_s!(from, to)
def try_again!
def try_again! label = 'attempt'
def update!
def update!
def update!
although about 10% of those aren't mine and i seem to stick to a few common
names (update!) in that list. still there are around 20 legit ones.
cheers.
-a
--
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze. --Nagarjuna
===============================================================================
(I'd want to give Professor Parkinson the benefit of the doubt and
assume that his book actually isn't as trite as that paraphrase
suggests. But I don't know. The "Someone's Law" formula certainly
operates often as a magic ticket to longevity :-)
Anyway.... at the risk of getting meta-meta-meta, I'd like to suggest
that discussing details of things like method names (in this case,
including Matz indicating that he was interested in what people think)
is actually not "stupid". We're just lucky that Matz pays attention
to details like this, over and over again year after year. It's that,
and not a deterministic, mechanistic "Well, X does this, so Y has to
do it" logic, that makes Ruby so beautiful.
> Heavens -- I think we all knew that already :-) There's one that I
> don't think you included: Tempfile#close! which closes and unlinks the
> file.
Yeah, I just used ObjectSpace, so it didn't pick up any stdlib stuff.
That was pretty stupid of me, but like I said, it was late, and I needed
sleep.
> One reason I think it's useful to remember the real meaning of ! is
> that gives one a potentially useful tool to use in one's own classes.
> I don't know how many people actually write bang methods. I've done
> it once or twice.
Point. I have never written a bang method. May I hang my head in shame. :P
David A. Black wrote:
> Anyway.... at the risk of getting meta-meta-meta, I'd like to suggest
> that discussing details of things like method names (in this case,
> including Matz indicating that he was interested in what people think)
> is actually not "stupid". We're just lucky that Matz pays attention
> to details like this, over and over again year after year. It's that,
> and not a deterministic, mechanistic "Well, X does this, so Y has to
> do it" logic, that makes Ruby so beautiful.
1. Agreed; attention to detail is what helped make Ruby so *tear* beautiful.
2. "Well, X does this, so Y has to do it" is just another aesthetic. In
this case, I think it applies to me, but to each his own.
3. Indeed, you're right. It's more important to have a small set of
cohesive and perfect doohickeys than a large set of jumbled and POS
ones. So, fine, let us continue the select! discussion....
I say we name it select! and alias as keep! -- that way, somebody ri'ing
it will be able to infer its meaning the English way, and somebody not
ri'ing will be able to infer its meaning from the parallels already
drawn in 90+% of the core bang methods (where x.foo! _=_ x = x.foo...
sort of).
Devin
On Sun, 9 Oct 2005, Devin Mullins wrote:
> 3. Indeed, you're right. It's more important to have a small set of cohesive
> and perfect doohickeys than a large set of jumbled and POS ones. So, fine,
> let us continue the select! discussion....
What's POS?
> I say we name it select! and alias as keep! -- that way, somebody ri'ing it
> will be able to infer its meaning the English way, and somebody not ri'ing
> will be able to infer its meaning from the parallels already drawn in 90+% of
> the core bang methods (where x.foo! _=_ x = x.foo... sort of).
(But how many times is foo! not, on its own, a good method name for
what it does? I still prefer that there not be a method called
select!, but I dare say that's pretty evident by now :-)
keep! implies keep. I think keep (without the !) would be an inplace
operation already. Or maybe keep_all { <test> }.
> Hi --
>
> On Sun, 9 Oct 2005, Devin Mullins wrote:
>
>> 3. Indeed, you're right. It's more important to have a small set of
>> cohesive and perfect doohickeys than a large set of jumbled and POS
>> ones. So, fine, let us continue the select! discussion....
>
> What's POS?
Piece of... err... sunshine...
> keep! implies keep. I think keep (without the !) would be an inplace
> operation already. Or maybe keep_all { <test> }.
Yeah, I like keep_all. I have the strongest feeling we're developing a
camel, though...
Devin
(a camel is a horse designed by committee...)
I vote we add keep_all or keep_if, and make select! a synonym for it.
Just like delete_if and reject!.
I feel symmetry and consistency is better than sticking to ideals of
the English language. Of course I think select! makes as much sense as
reject!, so for me it is a moot point.
Ryan
On Sun, 9 Oct 2005, Ryan Leavengood wrote:
> On 10/8/05, David A. Black <dbl...@wobblini.net> wrote:
>>
>> keep! implies keep. I think keep (without the !) would be an inplace
>> operation already. Or maybe keep_all { <test> }.
>
> I vote we add keep_all or keep_if, and make select! a synonym for it.
> Just like delete_if and reject!.
delete_if and reject! aren't quite synonyms, though:
irb(main):010:0> [1,2,3,4].delete_if {|x| x > 4 }
=> [1, 2, 3, 4]
irb(main):011:0> [1,2,3,4].reject! {|x| x > 4 }
=> nil
I definitely like keep_if better than select! for conditional keeping,
but because of the delete_if/reject! difference, one would expect
keep_if (or delete_unless, maybe?) to behave like delete_if rather
than like reject!. (I know this isn't a problem if select! exists
too, but I'm still not in favor of that name for this functionality.)
> I feel symmetry and consistency is better than sticking to ideals of
> the English language. Of course I think select! makes as much sense as
> reject!, so for me it is a moot point.
"Ruby: the triumph of balance over symmetry" (my personal Ruby slogan
:-) Not that I'm anti-symmetry -- I just like that it isn't always a
determinant.
It's not a matter of the English language as such -- English is just
the language that the keywords and method names are based on.
I oppose select! not on the basis on English purity, but on that of
Ruby purity.
One of the reasons I like Ruby is that Matz has *not* chosen to
slavishly follow symmetry and consistency.
Just my opinion.
Hal
Can you justify that opposition in the context of the following Array
methods?
collect! compact! flatten! map! reject! reverse!
slice! sort! uniq!
I've read the whole thread (perhaps too quickly), and don't see what at
all is controversial about #select! as an in-place #select.
I'm neither advocating it nor opposing it on its merits, but I think
it's equally meritorious as all of the above. Or even more:
#map!/#collect! and #uniq! are quite unappealing to me.
Point is: I doubt anyone on this thread would complain (even privately)
about #select! if it had been there all along. That's not to belittle
the discussion now, but it's a useful perspective.
And amongst all the praising of Ruby's balance over symmetry etc., I
can't help thinking that if the core classes were redesigned from
scratch, they'd be a little cleaner than they are now. [1] That is
inevitable and not a criticism. Such a criticism would be niggardly in
respect of the overall beauty of the language.
Finally, FWIW, here's a list of Array methods that _don't_ have an
in-place counterpart (including Enumerable methods):
find_all grep sort_by
Gee, not many! (Especially as #find_all is just #select.) As a lover
of minutae, I'd like to hear people's arguments for and against banging
these :) (ooh errrr)
Cheers,
Gavin
P.S. That faint buzz in the back of my mind has become clearer:
extensions.rubyforge.org defines Array#select! I put it there at
someone's request ages ago.
> scratch, they'd be a little cleaner than they are now. [1] That is
I was going to add a footnote, thought better of it, and forgot to
remove the "[1]". Apologies for the additional noise.
Gavin
On Sun, 9 Oct 2005, Gavin Sinclair wrote:
>
> Hal Fulton wrote:
>>
>> It's not a matter of the English language as such -- English is just
>> the language that the keywords and method names are based on.
>>
>> I oppose select! not on the basis on English purity, but on that of
>> Ruby purity.
>
> Can you justify that opposition in the context of the following Array
> methods?
>
> collect! compact! flatten! map! reject! reverse!
> slice! sort! uniq!
I'm not sure what you mean by the context of those methods. It's just
a question of whether select! is a good name for the proposed
behavior.
> I've read the whole thread (perhaps too quickly), and don't see what at
> all is controversial about #select! as an in-place #select.
Read it less quickly :-) My problem with it is that "a dangerous
version of select" doesn't evoke this behavior to me, and "an in-place
version of select" I find meaningless. I consider "select"
fundamentally a benign operation, not an operation that can either
have or not have dangers associated with it. See thread for more.
[...]
> Finally, FWIW, here's a list of Array methods that _don't_ have an
> in-place counterpart (including Enumerable methods):
>
> find_all grep sort_by
>
> Gee, not many! (Especially as #find_all is just #select.) As a lover
> of minutae, I'd like to hear people's arguments for and against banging
> these :) (ooh errrr)
find_all! and grep! don't seem to mean anything, other than "Tell me
which elements pass this test -- *really* tell me!" sort_by! would be
useful (or, as we've joked on irc, sort!_by :-)
> Finally, FWIW, here's a list of Array methods that _don't_ have an
> in-place counterpart (including Enumerable methods):
>
> find_all grep sort_by
Not to hijack the thread, but I secretly pine for sort_by!(). I
swear I've never used it when it wasn't like:
arr = arr.sort_by { ... whatever ... }
James Edward Gray II
P.S. I have no problem at all with select!(). Honestly, the English
seems fine to me. It's a real word and I know what it means. It's
certainly more English than extname(), callcc(), nitems(), etc.
Not to add to the highjacking, but I agree. In fact, if I had to
prioritize which should be added first, sort_by! would be higher than
select!.
And to address David's note about delete_if and reject! not quite
being synonyms, true, so therefore keep_if and select! should have
similar semantics.
Ryan