gsub and gsub! are inconsistent

Discussion in 'Ruby' started by aurelianito, Nov 8, 2005.

  1. aurelianito

    aurelianito Guest

    Hi all!

    I've been trying to optimize the code
    a_string.gsub(/pattern_1/, "REPLACE_1").gsub(/pattern_2/,
    "REPLACE_2").gsub(/PATTERN_3/,"REPLACE_3").

    with a_string.gsub(/pattern_1/, "REPLACE_1").gsub!(/pattern_2/,
    "REPLACE_2").gsub!(/pattern_3/,"REPLACE_3") (note the '!' on the second
    and third gsub).

    IMHO, this two blocks of pseudocode should behave in the same way, but
    if the second pattern don't matches, it returns null on the second
    version, and then generates an exception.
    Why is it than the destructive gsub behaves differently?
    Do you think that the current behaviour is the right behaviour? Why?

    Please comment,
    Aureliano.
     
    aurelianito, Nov 8, 2005
    #1
    1. Advertising

  2. aurelianito wrote:
    > Hi all!
    >
    > I've been trying to optimize the code
    > a_string.gsub(/pattern_1/, "REPLACE_1").gsub(/pattern_2/,
    > "REPLACE_2").gsub(/PATTERN_3/,"REPLACE_3").
    >
    > with a_string.gsub(/pattern_1/, "REPLACE_1").gsub!(/pattern_2/,
    > "REPLACE_2").gsub!(/pattern_3/,"REPLACE_3") (note the '!' on the second
    > and third gsub).
    >
    > IMHO, this two blocks of pseudocode should behave in the same way, but
    > if the second pattern don't matches, it returns null on the second
    > version, and then generates an exception.
    > Why is it than the destructive gsub behaves differently?
    > Do you think that the current behaviour is the right behaviour? Why?


    There have been many discussions about method chaining. Some think it
    would be good for bang-methods to always return self, some think that
    nil should silently consume those method calls and the rest think that
    you should not be chaining methods in the first place because of all
    the problems it would mask and think of the children!

    Yeah, it would be sensible for it to return self.

    > Please comment,
    > Aureliano.


    E
     
    Eero Saynatkari, Nov 8, 2005
    #2
    1. Advertising

  3. aurelianito

    Eric Hodel Guest

    On Nov 8, 2005, at 11:52 AM, aurelianito wrote:

    > Hi all!
    >
    > I've been trying to optimize the code
    > a_string.gsub(/pattern_1/, "REPLACE_1").gsub(/pattern_2/,
    > "REPLACE_2").gsub(/PATTERN_3/,"REPLACE_3").


    So you've profiled your code and determined that gsub is your slow
    point?

    If so, you've also checked that regex matching is not slowing you
    down, but the creation of a new string and the garbage collection of
    the old string is?

    > IMHO, this two blocks of pseudocode should behave in the same way, but
    > if the second pattern don't matches, it returns null on the second
    > version, and then generates an exception.
    > Why is it than the destructive gsub behaves differently?


    $ ri String#gsub!
    ----------------------------------------------------------- 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.


    > Do you think that the current behaviour is the right behaviour? Why?


    Yes.

    Bang methods can change things in places you don't expect.

    Bang methods should give an indication that something was changed if
    something was changed.

    --
    Eric Hodel - - http://segment7.net
    FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04
     
    Eric Hodel, Nov 8, 2005
    #3
  4. aurelianito <> wrote:
    > Hi all!
    >
    > I've been trying to optimize the code
    > a_string.gsub(/pattern_1/, "REPLACE_1").gsub(/pattern_2/,
    > "REPLACE_2").gsub(/PATTERN_3/,"REPLACE_3").
    >
    > with a_string.gsub(/pattern_1/, "REPLACE_1").gsub!(/pattern_2/,
    > "REPLACE_2").gsub!(/pattern_3/,"REPLACE_3") (note the '!' on the
    > second and third gsub).
    >
    > IMHO, this two blocks of pseudocode should behave in the same way, but
    > if the second pattern don't matches, it returns null on the second
    > version, and then generates an exception.
    > Why is it than the destructive gsub behaves differently?


    To be able to determine whether something was changed

    if s.gsub!(...)
    puts "oops, changed!"
    end

    > Do you think that the current behaviour is the right behaviour? Why?


    If there were no other reasons then at least existing code. But there are
    other reasons (see above).

    Btw, did you consider changing your code altoghether? Depending on your
    patterns and replacements, there are other options possible:

    s.gsub!(/pat1|pat2/) {|m| replacements[m]}

    s.gsub! /(pat1)|(pat2)/ do |m|
    case
    when m[1]; "re1"
    when m[2]; "re2"
    else raise "Unexpected"
    end
    end

    Kind regards

    robert
     
    Robert Klemme, Nov 8, 2005
    #4
  5. aurelianito

    aurelianito Guest

    Hi!

    Thank's all for your responses,
    what I can see is that there is no consensus on how the bang methods
    should behave. May be, the always self returning bang methods can be
    made available with an external library (there is an trivial
    implementation for a bang method to return always self :D). Is it
    already in the facets library? (right there with the "message eating"
    nil).

    Thank you all for your feedback,
    Aureliano.
     
    aurelianito, Nov 9, 2005
    #5
  6. aurelianito

    aurelianito Guest

    Hi!

    Thank's all for your responses,
    what I can see is that there is no consensus on how the bang methods
    should behave. May be, the always self returning bang methods can be
    made available with an external library (there is an trivial
    implementation for a bang method to return always self :D). Is it
    already in the facets library? (right there with the "message eating"
    nil).

    Thank you all for your feedback,
    Aureliano.
     
    aurelianito, Nov 9, 2005
    #6
  7. aurelianito

    Eric Hodel Guest

    On Nov 8, 2005, at 6:27 PM, aurelianito wrote:

    > what I can see is that there is no consensus on how the bang methods
    > should behave. May be, the always self returning bang methods can be
    > made available with an external library (there is an trivial
    > implementation for a bang method to return always self :D). Is it
    > already in the facets library? (right there with the "message eating"
    > nil).


    You realize you may break the Ruby standard library by doing that?

    --
    Eric Hodel - - http://segment7.net
    FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04
     
    Eric Hodel, Nov 9, 2005
    #7
  8. aurelianito

    aurelianito Guest

    > > what I can see is that there is no consensus on how the bang methods
    > > should behave. May be, the always self returning bang methods can be
    > > made available with an external library (there is an trivial
    > > implementation for a bang method to return always self :D). Is it
    > > already in the facets library? (right there with the "message eating"
    > > nil).

    >
    > You realize you may break the Ruby standard library by doing that?



    Ups!
    You are right.

    I see three choices:
    1 - use the caller method to change the bang methods to behave
    differently depending on the caller.
    2 - Use the rubycon tests to check how the standard library works with
    the modified methods.
    3 - Leave it as is, and complain that I don't like it.

    Option number one is really nasty.
    Option number two is too much work.
    Option number three seems to be the right choice.

    Thank's,
    Aureliano.
     
    aurelianito, Nov 9, 2005
    #8
  9. Hi --

    On Wed, 9 Nov 2005, aurelianito wrote:

    >>> what I can see is that there is no consensus on how the bang methods
    >>> should behave. May be, the always self returning bang methods can be
    >>> made available with an external library (there is an trivial
    >>> implementation for a bang method to return always self :D). Is it
    >>> already in the facets library? (right there with the "message eating"
    >>> nil).

    >>
    >> You realize you may break the Ruby standard library by doing that?

    >
    >
    > Ups!
    > You are right.
    >
    > I see three choices:
    > 1 - use the caller method to change the bang methods to behave
    > differently depending on the caller.
    > 2 - Use the rubycon tests to check how the standard library works with
    > the modified methods.
    > 3 - Leave it as is, and complain that I don't like it.
    >
    > Option number one is really nasty.
    > Option number two is too much work.


    And also *incredibly* fragile. It's really not an option.

    > Option number three seems to be the right choice.


    4. Investigate the various libraries on RAA that let you make
    temporary changes to core behavior.
    5. Wait until Ruby 2.0 and the possibility of selector namespaces.

    (You can of course combine either of this with complaining that you
    don't like it :)


    David

    --
    David A. Black
     
    David A. Black, Nov 9, 2005
    #9
  10. David A. Black wrote:
    > Hi --
    >
    > On Wed, 9 Nov 2005, aurelianito wrote:
    >
    >>>> what I can see is that there is no consensus on how the bang
    >>>> methods should behave. May be, the always self returning bang
    >>>> methods can be made available with an external library (there is
    >>>> an trivial implementation for a bang method to return always self
    >>>> :D). Is it already in the facets library? (right there with the
    >>>> "message eating" nil).
    >>>
    >>> You realize you may break the Ruby standard library by doing that?

    >>
    >>
    >> Ups!
    >> You are right.
    >>
    >> I see three choices:
    >> 1 - use the caller method to change the bang methods to behave
    >> differently depending on the caller.
    >> 2 - Use the rubycon tests to check how the standard library works
    >> with the modified methods.
    >> 3 - Leave it as is, and complain that I don't like it.
    >>
    >> Option number one is really nasty.
    >> Option number two is too much work.

    >
    > And also *incredibly* fragile. It's really not an option.
    >
    >> Option number three seems to be the right choice.

    >
    > 4. Investigate the various libraries on RAA that let you make
    > temporary changes to core behavior.
    > 5. Wait until Ruby 2.0 and the possibility of selector namespaces.
    >
    > (You can of course combine either of this with complaining that you
    > don't like it :)


    I'd like to add another option to the mix:

    6. Don't complain and accept it the way it is.

    This form of serenity can help a great deal in modern life.
    :)

    Kind regards

    robert
     
    Robert Klemme, Nov 9, 2005
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    7
    Views:
    317
    Rod Pemberton
    Oct 8, 2006
  2. Serengeti
    Replies:
    2
    Views:
    483
    Serengeti
    Nov 20, 2005
  3. Replies:
    10
    Views:
    478
    James Kanze
    May 31, 2007
  4. ibloom
    Replies:
    12
    Views:
    908
    Bruno Desthuilliers
    Feb 13, 2008
  5. Lie
    Replies:
    12
    Views:
    415
    Terry Reedy
    Apr 8, 2008
Loading...

Share This Page