[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: Is there a replacement for sub?

Bernard Kenik

7/22/2007 2:54:00 AM

ruby-talk-admin@ruby-lang.org wrote:
>
>
>
> ------------------------------------------------------------------------
>
> Subject:
> Re: Is there a replacement for sub?
> From:
> "Robert Dober" <robert.dober@gmail.com>
> Date:
> Fri, 20 Jul 2007 20:49:07 +0900
> To:
> ruby-talk@ruby-lang.org (ruby-talk ML)
>
> To:
> ruby-talk@ruby-lang.org (ruby-talk ML)
>
>
> On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:
>> On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:
>> >
>> > I was reading this whole thread and I kind of think to be dreaming, I
>> > must have missed something obvious!!!
>> > Anyway maybe this is was OP wants, well I think it is ;)
>> >
>> > 529/29 > irb
>> > irb(main):001:0> a='a b c d e f'
>> > => "a b c d e f"
>> > irb(main):002:0> a.gsub!(" ","")
>>
>> Nope, he wants a method that only replaces the first n occurrences of
>> the pattern. gsub will not do this - you need to run sub in a loop.
>> (This is where perl's "continue matching where you left off" would
>> have been a nice optimisation)

The primary problem is that sub! returns nil when no substitutions are made.

I have similar problem with Array#flatten!, Array#uniq! since it causes
problem when chaining!
My solution has been to override these bang! methods to return self even
when the bang! method did not have to change the receiver.

for sub! I would override the sub! method as follow

class String
alias old_sub! sub!
def sub!(pattern, replacement)
self.old_sub!(pattern, replacement)
self
end
end

As a user of a method, I really do not care if the method did not have
to do anything so long as the object is in the desired state.

For an array such as arr = [1,2,3,4,5,6], I can safely chain the bang!
methods without worrying about nil returns from flatten! and uniq!

arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!' for
nil:NilClass (NoMethodError)" because flatten! would have returned nil
p arr => [1, 2, 3, 4, 5, 6]


14 Answers

Michael W. Ryder

7/22/2007 3:40:00 AM

0

Bernard Kenik wrote:
> ruby-talk-admin@ruby-lang.org wrote:
>>
>>
>>
>> ------------------------------------------------------------------------
>>
>> Subject:
>> Re: Is there a replacement for sub?
>> From:
>> "Robert Dober" <robert.dober@gmail.com>
>> Date:
>> Fri, 20 Jul 2007 20:49:07 +0900
>> To:
>> ruby-talk@ruby-lang.org (ruby-talk ML)
>>
>> To:
>> ruby-talk@ruby-lang.org (ruby-talk ML)
>>
>>
>> On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:
>>> On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:
>>> >
>>> > I was reading this whole thread and I kind of think to be dreaming, I
>>> > must have missed something obvious!!!
>>> > Anyway maybe this is was OP wants, well I think it is ;)
>>> >
>>> > 529/29 > irb
>>> > irb(main):001:0> a='a b c d e f'
>>> > => "a b c d e f"
>>> > irb(main):002:0> a.gsub!(" ","")
>>>
>>> Nope, he wants a method that only replaces the first n occurrences of
>>> the pattern. gsub will not do this - you need to run sub in a loop.
>>> (This is where perl's "continue matching where you left off" would
>>> have been a nice optimisation)
>
> The primary problem is that sub! returns nil when no substitutions are
> made.
>
> I have similar problem with Array#flatten!, Array#uniq! since it causes
> problem when chaining!
> My solution has been to override these bang! methods to return self even
> when the bang! method did not have to change the receiver.
>
> for sub! I would override the sub! method as follow
>
> class String
> alias old_sub! sub!
> def sub!(pattern, replacement)
> self.old_sub!(pattern, replacement)
> self
> end
> end
>

And this can easily be expanded to do what I was trying to do in the
first place! Adding the following method with your replacement method:

class String
def subn!(pattern, replacement, n=1)
n.times do
self.sub!(pattern, replacement)
end
end
end

With this I can specify a.subn!(' ', '', 10) and it will return 'abcdef'
just like I was looking for. It will work with zero or negative values
returning 'a b c d e f', again like I would expect. Of course if you
enter a non-integer value it will error out in its current state but the
error is from the times method.

> As a user of a method, I really do not care if the method did not have
> to do anything so long as the object is in the desired state.
>

I too hate surprises.


> For an array such as arr = [1,2,3,4,5,6], I can safely chain the bang!
> methods without worrying about nil returns from flatten! and uniq!
>
> arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!' for
> nil:NilClass (NoMethodError)" because flatten! would have returned nil
> p arr => [1, 2, 3, 4, 5, 6]
>
>

bbiker

7/22/2007 7:35:00 AM

0

On Jul 21, 11:40 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net>
wrote:
> Bernard Kenik wrote:
> > ruby-talk-ad...@ruby-lang.org wrote:
>
> >> ------------------------------------------------------------------------
>
> >> Subject:
> >> Re: Is there a replacement for sub?
> >> From:
> >> "Robert Dober" <robert.do...@gmail.com>
> >> Date:
> >> Fri, 20 Jul 2007 20:49:07 +0900
> >> To:
> >> ruby-t...@ruby-lang.org (ruby-talk ML)
>
> >> To:
> >> ruby-t...@ruby-lang.org (ruby-talk ML)
>
> >> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
> >>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:
>
> >>> > I was reading this whole thread and I kind of think to be dreaming, I
> >>> > must have missed something obvious!!!
> >>> > Anyway maybe this is was OP wants, well I think it is ;)
>
> >>> > 529/29 > irb
> >>> > irb(main):001:0> a='a b c d e f'
> >>> > => "a b c d e f"
> >>> > irb(main):002:0> a.gsub!(" ","")
>
> >>> Nope, he wants a method that only replaces the first n occurrences of
> >>> the pattern. gsub will not do this - you need to run sub in a loop.
> >>> (This is where perl's "continue matching where you left off" would
> >>> have been a nice optimisation)
>
> > The primary problem is that sub! returns nil when no substitutions are
> > made.
>
> > I have similar problem with Array#flatten!, Array#uniq! since it causes
> > problem when chaining!
> > My solution has been to override these bang! methods to return self even
> > when the bang! method did not have to change the receiver.
>
> > for sub! I would override the sub! method as follow
>
> > class String
> > alias old_sub! sub!
> > def sub!(pattern, replacement)
> > self.old_sub!(pattern, replacement)
> > self
> > end
> > end
>
> And this can easily be expanded to do what I was trying to do in the
> first place! Adding the following method with your replacement method:
>
> class String
> def subn!(pattern, replacement, n=1)
> n.times do
> self.sub!(pattern, replacement)
> end
> end
> end
>
> With this I can specify a.subn!(' ', '', 10) and it will return 'abcdef'
> just like I was looking for. It will work with zero or negative values
> returning 'a b c d e f', again like I would expect. Of course if you
> enter a non-integer value it will error out in its current state but the
> error is from the times method.
>
> > As a user of a method, I really do not care if the method did not have
> > to do anything so long as the object is in the desired state.
>
> I too hate surprises.
>
>
>
> > For an array such as arr = [1,2,3,4,5,6], I can safely chain the bang!
> > methods without worrying about nil returns from flatten! and uniq!
>
> > arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!' for
> > nil:NilClass (NoMethodError)" because flatten! would have returned nil
> > p arr => [1, 2, 3, 4, 5, 6]- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -

Note that as written, subn! returns n. So if you need to do some
chaining, you should change subn! as follows:

def subn!(pattern, replacement, n=1)
n.times { self.sub!(pattern, replacement) }
self
end

str = "a b c d e f g h i j"
str.subn!(/ /,'',2).reverse! # won't produce an error msg such as

C:/Documents ... /rb5C.tmp:30: undefined method `reverse!' for
1:Fixnum (NoMethodError)

instead of => "j i h g f e d cba"

dblack

7/22/2007 9:55:00 AM

0

Michael W. Ryder

7/23/2007 2:39:00 AM

0

dblack@wobblini.net wrote:
> Hi --
>
> On Sun, 22 Jul 2007, Bernard Kenik wrote:
>
>> ruby-talk-admin@ruby-lang.org wrote:
>>>
>>>
>>>
>>> ------------------------------------------------------------------------
>>>
>>> Subject:
>>> Re: Is there a replacement for sub?
>>> From:
>>> "Robert Dober" <robert.dober@gmail.com>
>>> Date:
>>> Fri, 20 Jul 2007 20:49:07 +0900
>>> To:
>>> ruby-talk@ruby-lang.org (ruby-talk ML)
>>>
>>> To:
>>> ruby-talk@ruby-lang.org (ruby-talk ML)
>>>
>>>
>>> On 7/20/07, Martin DeMello <martindemello@gmail.com> wrote:
>>>> On 7/20/07, Robert Dober <robert.dober@gmail.com> wrote:
>>>> >
>>>> > I was reading this whole thread and I kind of think to be dreaming, I
>>>> > must have missed something obvious!!!
>>>> > Anyway maybe this is was OP wants, well I think it is ;)
>>>> >
>>>> > 529/29 > irb
>>>> > irb(main):001:0> a='a b c d e f'
>>>> > => "a b c d e f"
>>>> > irb(main):002:0> a.gsub!(" ","")
>>>>
>>>> Nope, he wants a method that only replaces the first n occurrences of
>>>> the pattern. gsub will not do this - you need to run sub in a loop.
>>>> (This is where perl's "continue matching where you left off" would
>>>> have been a nice optimisation)
>>
>> The primary problem is that sub! returns nil when no substitutions are
>> made.
>>
>> I have similar problem with Array#flatten!, Array#uniq! since it
>> causes problem when chaining!
>> My solution has been to override these bang! methods to return self
>> even when the bang! method did not have to change the receiver.
>>
>> for sub! I would override the sub! method as follow
>>
>> class String
>> alias old_sub! sub!
>> def sub!(pattern, replacement)
>> self.old_sub!(pattern, replacement)
>> self
>> end
>> end
>>
>> As a user of a method, I really do not care if the method did not have
>> to do anything so long as the object is in the desired state.
>>
>> For an array such as arr = [1,2,3,4,5,6], I can safely chain the
>> bang! methods without worrying about nil returns from flatten! and uniq!
>>
>> arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!'
>> for nil:NilClass (NoMethodError)" because flatten! would have returned
>> nil
>> p arr => [1, 2, 3, 4, 5, 6]
>
> I would very, very strongly advise you, and everyone else, not to do
> this. You will break any code (inside the standard library and/or any
> other code you load, or any code that uses your code) that depends on
> the documented behavior of these methods. You may not like how sub!
> and friends work, but it's a very bad idea to make the decision to
> change them on behalf of everyone else, over and above the language
> documentation.
>
>
What I planned to do was get rid of the alias and change the name of the
new sub! method to something like subf! for just that reason. I still
prefer this version much better than the original version as there are
no surprises. It is very hard to change 30+ years of practice overnight.


> David
>

Michael W. Ryder

7/23/2007 2:45:00 AM

0

bbiker wrote:
> On Jul 21, 11:40 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net>
> wrote:
>> Bernard Kenik wrote:
>>> ruby-talk-ad...@ruby-lang.org wrote:
>>>> ------------------------------------------------------------------------
>>>> Subject:
>>>> Re: Is there a replacement for sub?
>>>> From:
>>>> "Robert Dober" <robert.do...@gmail.com>
>>>> Date:
>>>> Fri, 20 Jul 2007 20:49:07 +0900
>>>> To:
>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
>>>> To:
>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
>>>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
>>>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:
>>>>>> I was reading this whole thread and I kind of think to be dreaming, I
>>>>>> must have missed something obvious!!!
>>>>>> Anyway maybe this is was OP wants, well I think it is ;)
>>>>>> 529/29 > irb
>>>>>> irb(main):001:0> a='a b c d e f'
>>>>>> => "a b c d e f"
>>>>>> irb(main):002:0> a.gsub!(" ","")
>>>>> Nope, he wants a method that only replaces the first n occurrences of
>>>>> the pattern. gsub will not do this - you need to run sub in a loop.
>>>>> (This is where perl's "continue matching where you left off" would
>>>>> have been a nice optimisation)
>>> The primary problem is that sub! returns nil when no substitutions are
>>> made.
>>> I have similar problem with Array#flatten!, Array#uniq! since it causes
>>> problem when chaining!
>>> My solution has been to override these bang! methods to return self even
>>> when the bang! method did not have to change the receiver.
>>> for sub! I would override the sub! method as follow
>>> class String
>>> alias old_sub! sub!
>>> def sub!(pattern, replacement)
>>> self.old_sub!(pattern, replacement)
>>> self
>>> end
>>> end
>> And this can easily be expanded to do what I was trying to do in the
>> first place! Adding the following method with your replacement method:
>>
>> class String
>> def subn!(pattern, replacement, n=1)
>> n.times do
>> self.sub!(pattern, replacement)
>> end
>> end
>> end
>>
>> With this I can specify a.subn!(' ', '', 10) and it will return 'abcdef'
>> just like I was looking for. It will work with zero or negative values
>> returning 'a b c d e f', again like I would expect. Of course if you
>> enter a non-integer value it will error out in its current state but the
>> error is from the times method.
>>
>>> As a user of a method, I really do not care if the method did not have
>>> to do anything so long as the object is in the desired state.
>> I too hate surprises.
>>
>>
>>
>>> For an array such as arr = [1,2,3,4,5,6], I can safely chain the bang!
>>> methods without worrying about nil returns from flatten! and uniq!
>>> arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!' for
>>> nil:NilClass (NoMethodError)" because flatten! would have returned nil
>>> p arr => [1, 2, 3, 4, 5, 6]- Hide quoted text -
>> - Show quoted text -- Hide quoted text -
>>
>> - Show quoted text -
>
> Note that as written, subn! returns n. So if you need to do some
> chaining, you should change subn! as follows:
>
> def subn!(pattern, replacement, n=1)
> n.times { self.sub!(pattern, replacement) }
> self
> end
>
> str = "a b c d e f g h i j"
> str.subn!(/ /,'',2).reverse! # won't produce an error msg such as
>
> C:/Documents ... /rb5C.tmp:30: undefined method `reverse!' for
> 1:Fixnum (NoMethodError)
>
> instead of => "j i h g f e d cba"
>

I made your suggested change with one cosmetic change. I added return
in front of the self to remind me what is the result of the method.
Thanks for the improvement.

bbiker

7/23/2007 3:52:00 PM

0

On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net>
wrote:
> dbl...@wobblini.net wrote:
> > Hi --
>
> > On Sun, 22 Jul 2007, Bernard Kenik wrote:
>
> >> ruby-talk-ad...@ruby-lang.org wrote:
>
> >>> ------------------------------------------------------------------------
>
> >>> Subject:
> >>> Re: Is there a replacement for sub?
> >>> From:
> >>> "Robert Dober" <robert.do...@gmail.com>
> >>> Date:
> >>> Fri, 20 Jul 2007 20:49:07 +0900
> >>> To:
> >>> ruby-t...@ruby-lang.org (ruby-talk ML)
>
> >>> To:
> >>> ruby-t...@ruby-lang.org (ruby-talk ML)
>
> >>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
> >>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:
>
> >>>> > I was reading this whole thread and I kind of think to be dreaming, I
> >>>> > must have missed something obvious!!!
> >>>> > Anyway maybe this is was OP wants, well I think it is ;)
>
> >>>> > 529/29 > irb
> >>>> > irb(main):001:0> a='a b c d e f'
> >>>> > => "a b c d e f"
> >>>> > irb(main):002:0> a.gsub!(" ","")
>
> >>>> Nope, he wants a method that only replaces the first n occurrences of
> >>>> the pattern. gsub will not do this - you need to run sub in a loop.
> >>>> (This is where perl's "continue matching where you left off" would
> >>>> have been a nice optimisation)
>
> >> The primary problem is that sub! returns nil when no substitutions are
> >> made.
>
> >> I have similar problem with Array#flatten!, Array#uniq! since it
> >> causes problem when chaining!
> >> My solution has been to override these bang! methods to return self
> >> even when the bang! method did not have to change the receiver.
>
> >> for sub! I would override the sub! method as follow
>
> >> class String
> >> alias old_sub! sub!
> >> def sub!(pattern, replacement)
> >> self.old_sub!(pattern, replacement)
> >> self
> >> end
> >> end
>
> >> As a user of a method, I really do not care if the method did not have
> >> to do anything so long as the object is in the desired state.
>
> >> For an array such as arr = [1,2,3,4,5,6], I can safely chain the
> >> bang! methods without worrying about nil returns from flatten! and uniq!
>
> >> arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!'
> >> for nil:NilClass (NoMethodError)" because flatten! would have returned
> >> nil
> >> p arr => [1, 2, 3, 4, 5, 6]
>
> > I would very, very strongly advise you, and everyone else, not to do
> > this. You will break any code (inside the standard library and/or any
> > other code you load, or any code that uses your code) that depends on
> > the documented behavior of these methods. You may not like how sub!
> > and friends work, but it's a very bad idea to make the decision to
> > change them on behalf of everyone else, over and above the language
> > documentation.
>
> What I planned to do was get rid of the alias and change the name of the
> new sub! method to something like subf! for just that reason. I still
> prefer this version much better than the original version as there are
> no surprises. It is very hard to change 30+ years of practice overnight.
>
>
>
> > David- Hide quoted text -
>
> - Show quoted text -- Hide quoted text -
>
> - Show quoted text -

Actually you do not have to define subf! as an intermediate step
you can directly define subn and subn! directly

class String
def subn!(pattern, replacement, n = 1)
n.times { self.sub!(pattern, replacement) }
self # or return self
end

def subn(pattern, replacement, n = 1)
return self if n < 1
@str = self.sub(pattern, replacement)
(n-1).times { @str = @str.sub(pattern, replacement) }
@str # or return @str
end
end

Note that sub and sub! are the original definitions

You use subn(pattern, replacement) and subn!(pattern, replacement) as
substitutes for sub(pattern, replacement) and sub!(pattern,
replacement) which eliminate the unpleasant surprises.

In addition, both can be safely chained !!!!

Hope this helps

dblack

7/23/2007 4:42:00 PM

0

bbiker

7/23/2007 6:46:00 PM

0

On Jul 23, 11:51 am, bbiker <renard3...@gmail.com> wrote:
> On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net>
> wrote:
>
>
>
>
>
> > dbl...@wobblini.net wrote:
> > > Hi --
>
> > > On Sun, 22 Jul 2007, Bernard Kenik wrote:
>
> > >> ruby-talk-ad...@ruby-lang.org wrote:
>
> > >>> ------------------------------------------------------------------------
>
> > >>> Subject:
> > >>> Re: Is there a replacement for sub?
> > >>> From:
> > >>> "Robert Dober" <robert.do...@gmail.com>
> > >>> Date:
> > >>> Fri, 20 Jul 2007 20:49:07 +0900
> > >>> To:
> > >>> ruby-t...@ruby-lang.org (ruby-talk ML)
>
> > >>> To:
> > >>> ruby-t...@ruby-lang.org (ruby-talk ML)
>
> > >>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
> > >>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:
>
> > >>>> > I was reading this whole thread and I kind of think to be dreaming, I
> > >>>> > must have missed something obvious!!!
> > >>>> > Anyway maybe this is was OP wants, well I think it is ;)
>
> > >>>> > 529/29 > irb
> > >>>> > irb(main):001:0> a='a b c d e f'
> > >>>> > => "a b c d e f"
> > >>>> > irb(main):002:0> a.gsub!(" ","")
>
> > >>>> Nope, he wants a method that only replaces the first n occurrences of
> > >>>> the pattern. gsub will not do this - you need to run sub in a loop.
> > >>>> (This is where perl's "continue matching where you left off" would
> > >>>> have been a nice optimisation)
>
> > >> The primary problem is that sub! returns nil when no substitutions are
> > >> made.
>
> > >> I have similar problem with Array#flatten!, Array#uniq! since it
> > >> causes problem when chaining!
> > >> My solution has been to override these bang! methods to return self
> > >> even when the bang! method did not have to change the receiver.
>
> > >> for sub! I would override the sub! method as follow
>
> > >> class String
> > >> alias old_sub! sub!
> > >> def sub!(pattern, replacement)
> > >> self.old_sub!(pattern, replacement)
> > >> self
> > >> end
> > >> end
>
> > >> As a user of a method, I really do not care if the method did not have
> > >> to do anything so long as the object is in the desired state.
>
> > >> For an array such as arr = [1,2,3,4,5,6], I can safely chain the
> > >> bang! methods without worrying about nil returns from flatten! and uniq!
>
> > >> arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!'
> > >> for nil:NilClass (NoMethodError)" because flatten! would have returned
> > >> nil
> > >> p arr => [1, 2, 3, 4, 5, 6]
>
> > > I would very, very strongly advise you, and everyone else, not to do
> > > this. You will break any code (inside the standard library and/or any
> > > other code you load, or any code that uses your code) that depends on
> > > the documented behavior of these methods. You may not like how sub!
> > > and friends work, but it's a very bad idea to make the decision to
> > > change them on behalf of everyone else, over and above the language
> > > documentation.
>
> > What I planned to do was get rid of the alias and change the name of the
> > new sub! method to something like subf! for just that reason. I still
> > prefer this version much better than the original version as there are
> > no surprises. It is very hard to change 30+ years of practice overnight.
>
> > > David- Hide quoted text -
>
> > - Show quoted text -- Hide quoted text -
>
> > - Show quoted text -
>
> Actually you do not have to define subf! as an intermediate step
> you can directly define subn and subn! directly
>
> class String
> def subn!(pattern, replacement, n = 1)
> n.times { self.sub!(pattern, replacement) }
> self # or return self
> end
>
> def subn(pattern, replacement, n = 1)
> return self if n < 1
> @str = self.sub(pattern, replacement)
> (n-1).times { @str = @str.sub(pattern, replacement) }
> @str # or return @str
> end
> end
>
> Note that sub and sub! are the original definitions
>
> You use subn(pattern, replacement) and subn!(pattern, replacement) as
> substitutes for sub(pattern, replacement) and sub!(pattern,
> replacement) which eliminate the unpleasant surprises.
>
> In addition, both can be safely chained !!!!
>
> Hope this helps- Hide quoted text -
>
> - Show quoted text -

You might consider adding the following, so you have a matching
replacement set for sub, sub!, gsub, and gsub!

You can think of gsubn and gsubn! as no nil returns :>)

class String
def subn!(pattern, replacement, n = 1)
n.times { self.sub!(pattern, replacement) }
self
end

def subn(pattern, replacement, n = 1)
return self if n < 1
@str = self.sub(pattern, replacement)
(n-1).times { @str = @str.sub(pattern, replacement) }
@str
end

def gsubn!(pattern, replacement)
self.gsub!(pattern, replacement)
self # does not return nil if no
changes were made
end

alias gsubn gsub # you can use either gsubn or gsub
end


My primary objection to have a nil return is that it prevents me from
safely chaining bang! methods.

The nil return is counter-intuitive and violates the Principle of
Least Surprise

As I said before given an array such as arr = [1, 2, 3, 4, 5, 6], I
can do

new_arr = arr.flatten.uniq.sort => [1, 2, 3, 4, 5, 6]

Intuitively I would think that I should be able to do
arr.flatten!.uniq!.sort!; however because of the nil return by
#flatten!, a NoMethodError is raised by #uniq! since the nil object
does not have a uniq! method.

Note that not all bang! methods return nil when nothing was changed in
the receiver. Array#sort! return self if self was already sorted.

Hopefully Matz might be reading this thread and might consider
changing the behavior of bang! methods returns.

Michael W. Ryder

7/23/2007 6:53:00 PM

0

bbiker wrote:
> On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net>
> wrote:
>> dbl...@wobblini.net wrote:
>>> Hi --
>>> On Sun, 22 Jul 2007, Bernard Kenik wrote:
>>>> ruby-talk-ad...@ruby-lang.org wrote:
>>>>> ------------------------------------------------------------------------
>>>>> Subject:
>>>>> Re: Is there a replacement for sub?
>>>>> From:
>>>>> "Robert Dober" <robert.do...@gmail.com>
>>>>> Date:
>>>>> Fri, 20 Jul 2007 20:49:07 +0900
>>>>> To:
>>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
>>>>> To:
>>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
>>>>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
>>>>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:
>>>>>>> I was reading this whole thread and I kind of think to be dreaming, I
>>>>>>> must have missed something obvious!!!
>>>>>>> Anyway maybe this is was OP wants, well I think it is ;)
>>>>>>> 529/29 > irb
>>>>>>> irb(main):001:0> a='a b c d e f'
>>>>>>> => "a b c d e f"
>>>>>>> irb(main):002:0> a.gsub!(" ","")
>>>>>> Nope, he wants a method that only replaces the first n occurrences of
>>>>>> the pattern. gsub will not do this - you need to run sub in a loop.
>>>>>> (This is where perl's "continue matching where you left off" would
>>>>>> have been a nice optimisation)
>>>> The primary problem is that sub! returns nil when no substitutions are
>>>> made.
>>>> I have similar problem with Array#flatten!, Array#uniq! since it
>>>> causes problem when chaining!
>>>> My solution has been to override these bang! methods to return self
>>>> even when the bang! method did not have to change the receiver.
>>>> for sub! I would override the sub! method as follow
>>>> class String
>>>> alias old_sub! sub!
>>>> def sub!(pattern, replacement)
>>>> self.old_sub!(pattern, replacement)
>>>> self
>>>> end
>>>> end
>>>> As a user of a method, I really do not care if the method did not have
>>>> to do anything so long as the object is in the desired state.
>>>> For an array such as arr = [1,2,3,4,5,6], I can safely chain the
>>>> bang! methods without worrying about nil returns from flatten! and uniq!
>>>> arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!'
>>>> for nil:NilClass (NoMethodError)" because flatten! would have returned
>>>> nil
>>>> p arr => [1, 2, 3, 4, 5, 6]
>>> I would very, very strongly advise you, and everyone else, not to do
>>> this. You will break any code (inside the standard library and/or any
>>> other code you load, or any code that uses your code) that depends on
>>> the documented behavior of these methods. You may not like how sub!
>>> and friends work, but it's a very bad idea to make the decision to
>>> change them on behalf of everyone else, over and above the language
>>> documentation.
>> What I planned to do was get rid of the alias and change the name of the
>> new sub! method to something like subf! for just that reason. I still
>> prefer this version much better than the original version as there are
>> no surprises. It is very hard to change 30+ years of practice overnight.
>>
>>
>>
>>> David- Hide quoted text -
>> - Show quoted text -- Hide quoted text -
>>
>> - Show quoted text -
>
> Actually you do not have to define subf! as an intermediate step
> you can directly define subn and subn! directly
>
> class String
> def subn!(pattern, replacement, n = 1)
> n.times { self.sub!(pattern, replacement) }
> self # or return self
> end
>
> def subn(pattern, replacement, n = 1)
> return self if n < 1
> @str = self.sub(pattern, replacement)
> (n-1).times { @str = @str.sub(pattern, replacement) }
> @str # or return @str
> end
> end
>
> Note that sub and sub! are the original definitions
>
> You use subn(pattern, replacement) and subn!(pattern, replacement) as
> substitutes for sub(pattern, replacement) and sub!(pattern,
> replacement) which eliminate the unpleasant surprises.
>
> In addition, both can be safely chained !!!!
>
> Hope this helps
>

Thanks for the updated code. I think I will keep the subf and subf!
definitions for when I want to do single replacements that are free of
surprises. Maybe I will someday be able to use the original definitions
with confidence but when I am in the middle of a programming run I hate
to stop and look up language definitions to avoid problems. It just
ruins the flow of thought.

bbiker

7/23/2007 7:33:00 PM

0

On Jul 23, 2:53 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net>
wrote:
> bbiker wrote:
> > On Jul 22, 10:39 pm, "Michael W. Ryder" <_mwry...@worldnet.att.net>
> > wrote:
> >> dbl...@wobblini.net wrote:
> >>> Hi --
> >>> On Sun, 22 Jul 2007, Bernard Kenik wrote:
> >>>> ruby-talk-ad...@ruby-lang.org wrote:
> >>>>> ------------------------------------------------------------------------
> >>>>> Subject:
> >>>>> Re: Is there a replacement for sub?
> >>>>> From:
> >>>>> "Robert Dober" <robert.do...@gmail.com>
> >>>>> Date:
> >>>>> Fri, 20 Jul 2007 20:49:07 +0900
> >>>>> To:
> >>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
> >>>>> To:
> >>>>> ruby-t...@ruby-lang.org (ruby-talk ML)
> >>>>> On 7/20/07, Martin DeMello <martindeme...@gmail.com> wrote:
> >>>>>> On 7/20/07, Robert Dober <robert.do...@gmail.com> wrote:
> >>>>>>> I was reading this whole thread and I kind of think to be dreaming, I
> >>>>>>> must have missed something obvious!!!
> >>>>>>> Anyway maybe this is was OP wants, well I think it is ;)
> >>>>>>> 529/29 > irb
> >>>>>>> irb(main):001:0> a='a b c d e f'
> >>>>>>> => "a b c d e f"
> >>>>>>> irb(main):002:0> a.gsub!(" ","")
> >>>>>> Nope, he wants a method that only replaces the first n occurrences of
> >>>>>> the pattern. gsub will not do this - you need to run sub in a loop.
> >>>>>> (This is where perl's "continue matching where you left off" would
> >>>>>> have been a nice optimisation)
> >>>> The primary problem is that sub! returns nil when no substitutions are
> >>>> made.
> >>>> I have similar problem with Array#flatten!, Array#uniq! since it
> >>>> causes problem when chaining!
> >>>> My solution has been to override these bang! methods to return self
> >>>> even when the bang! method did not have to change the receiver.
> >>>> for sub! I would override the sub! method as follow
> >>>> class String
> >>>> alias old_sub! sub!
> >>>> def sub!(pattern, replacement)
> >>>> self.old_sub!(pattern, replacement)
> >>>> self
> >>>> end
> >>>> end
> >>>> As a user of a method, I really do not care if the method did not have
> >>>> to do anything so long as the object is in the desired state.
> >>>> For an array such as arr = [1,2,3,4,5,6], I can safely chain the
> >>>> bang! methods without worrying about nil returns from flatten! and uniq!
> >>>> arr.flatten!.uniq!.sort! # NO ERROR MSG "undefined method `uniq!'
> >>>> for nil:NilClass (NoMethodError)" because flatten! would have returned
> >>>> nil
> >>>> p arr => [1, 2, 3, 4, 5, 6]
> >>> I would very, very strongly advise you, and everyone else, not to do
> >>> this. You will break any code (inside the standard library and/or any
> >>> other code you load, or any code that uses your code) that depends on
> >>> the documented behavior of these methods. You may not like how sub!
> >>> and friends work, but it's a very bad idea to make the decision to
> >>> change them on behalf of everyone else, over and above the language
> >>> documentation.
> >> What I planned to do was get rid of the alias and change the name of the
> >> new sub! method to something like subf! for just that reason. I still
> >> prefer this version much better than the original version as there are
> >> no surprises. It is very hard to change 30+ years of practice overnight.
>
> >>> David- Hide quoted text -
> >> - Show quoted text -- Hide quoted text -
>
> >> - Show quoted text -
>
> > Actually you do not have to define subf! as an intermediate step
> > you can directly define subn and subn! directly
>
> > class String
> > def subn!(pattern, replacement, n = 1)
> > n.times { self.sub!(pattern, replacement) }
> > self # or return self
> > end
>
> > def subn(pattern, replacement, n = 1)
> > return self if n < 1
> > @str = self.sub(pattern, replacement)
> > (n-1).times { @str = @str.sub(pattern, replacement) }
> > @str # or return @str
> > end
> > end
>
> > Note that sub and sub! are the original definitions
>
> > You use subn(pattern, replacement) and subn!(pattern, replacement) as
> > substitutes for sub(pattern, replacement) and sub!(pattern,
> > replacement) which eliminate the unpleasant surprises.
>
> > In addition, both can be safely chained !!!!
>
> > Hope this helps
>
> Thanks for the updated code. I think I will keep the subf and subf!
> definitions for when I want to do single replacements that are free of
> surprises. Maybe I will someday be able to use the original definitions
> with confidence but when I am in the middle of a programming run I hate
> to stop and look up language definitions to avoid problems. It just
> ruins the flow of thought.- Hide quoted text -
>
> - Show quoted text -

for single substitution you can use subn!(pattern, replacement) since
n defaults to 1. Ditto for subn.