Method Chaining Issues

ES wrote:

class Foo
  def initialize
    @a = 5
  end

  attr_accessor :a
end

foo = Foo.new
foo.a = 6

Current behaviour aside, should the last line create a new Foo object?

Very funny. Totally different argument,

This is the counterargument for keeping destructive methods.

       nikolai

E

···

Le 2/6/2005, "Nikolai Weibull" <mailing-lists.ruby-talk@rawuncut.elitemail.org> a écrit:

--
template<typename duck>
void quack(duck& d) { d.quack(); }

Eric, thank you for kind explanation. It helps me.
I have been reading ruby source code with very lazy mode.
I need a kind of booster reading engine. :wink:

···

On 6/2/05, Eric Hodel <drbrain@segment7.net> wrote:

On 01 Jun 2005, at 18:36, Gyoung-Yoon Noh wrote:

> OK, you're right in case of String#gsub and String#gsub!.
> But not 'a lot slower' but 'a little slower'.
>
> $ cat destructive.rb
> require 'benchmark'
>
> Benchmark.bmbm do |bm|
> bm.report("Destructive") do
> 100.times do
> str = (0..10000).to_a.join('-')
> str.gsub!(/\d+/, '-')
> end
> end
> bm.report("Non-destructive") do
> 100.times do
> str = (0..10000).to_a.join('-')
> str = str.gsub(/\d+/, '-')
> end
> end
> end
>
> $ ruby destructive.rb
> Rehearsal ---------------------------------------------------
> Destructive 4.240000 0.010000 4.250000 ( 4.448997)
> Non-destructive 4.250000 0.010000 4.260000 ( 4.279959)
> ------------------------------------------ total: 8.510000sec
>
> user system total real
> Destructive 4.260000 0.010000 4.270000 ( 4.378810)
> Non-destructive 4.230000 0.010000 4.240000 ( 4.305321)

The difference is not in the speed of the operations themselves, it
is in the memory pressure on the GC. Your benchmark is not a fair
comparison between the two because it ignores the side-effect of
memory pressure and does not fit with the way you would use chaining
vs !.

This benchmark more realisticly shows the effects of memory pressure
and is more fitting with how you would really use chaining vs !:

$ cat sub.rb
require 'benchmark'

N = 10_000
STR = (0..N).to_a.join('-')

Benchmark.bmbm do |bm|
   bm.report("Base") do
     str = STR.dup
     N.times { }
   end

   bm.report("Destructive") do
     str = STR.dup
     N.times { str.sub!(/\d+/, '-') }
   end

   bm.report("Non-destructive") do
     str = STR.dup
     N.times { str = str.sub(/\d+/, '-') }
   end
end

$ ruby sub.rb
Rehearsal ---------------------------------------------------
Base 0.000000 0.000000 0.000000 ( 0.003034)
Destructive 1.470000 1.380000 2.850000 ( 3.266492)
Non-destructive 1.930000 2.740000 4.670000 ( 5.584387)
------------------------------------------ total: 7.520000sec

                       user system total real
Base 0.000000 0.000000 0.000000 ( 0.002857)
Destructive 1.460000 1.400000 2.860000 ( 3.383933)
Non-destructive 1.910000 2.800000 4.710000 ( 5.688635)

> I don't understand what exactly this difference implies.

Your benchmark wasn't helpful in revealing the true difference
between the two methods. As you can see, the non-destructive case
takes much more time in user space because the GC has to clean up all
the temporary strings.

It also takes ~33% more time in general because of the GC.

> Does that mean Ruby's String is much alike raw C string?

It wraps a C string.

> Or is there any particular optimization for String copy?

Certain operations are COW.

--
Eric Hodel - drbrain@segment7.net - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

--
http://nohmad.sub-port.net

Logan Capaldo <logancapaldo@gmail.com> writes:

From: Logan Capaldo <logancapaldo@gmail.com>
Subject: Re: Method Chaining Issues
To: ruby-talk@ruby-lang.org (ruby-talk ML)
Date: Thu, 2 Jun 2005 20:50:15 +0900
Reply-To: ruby-talk@ruby-lang.org
X-Mail-Count: 144347

Kyle Heon wrote:
>
> I'm new to Ruby so I when you refer to a "bang" method you mean something
> like "chomp!"? And if so, why do some thing they shouldn't exist? Just
> curious.
>

Oops, failed to address the other half of that.

The ! usually (not always) indicates that a method changes its
receiver "in place" rather than creating a new object as a result.

Just curious, can you give me an example of a bang method that doesn't
modify the
receiver in place?

----------------------------------------------------------- Kernel#exit!
     Process.exit!(fixnum=-1)

···

On 6/1/05, Hal Fulton <hal9000@hypermetrics.com> wrote:

------------------------------------------------------------------------
     Exits the process immediately. No exit handlers are run. _fixnum_
     is returned to the underlying system as the exit status.

        Process.exit!(0)

--
Christian Neukirchen <chneukirchen@gmail.com> http://chneukirchen.org

Logan Capaldo wrote:

The ! usually (not always) indicates that a method changes its
receiver "in place" rather than creating a new object as a result.

Just curious, can you give me an example of a bang method that doesn't
modify the
receiver in place?

The only one in the core is exit! as far as I know.

Some things like Kernel#chomp! have an implicit receiver,
so they don't really make my point.

There may be others in the std lib or other common libs,
I don't know.

The point is that the ! is to mark a method as "dangerous"
or "requiring caution."

I certainly use it in my own code in situations where it doesn't
change the receiver. In fact, I encourage others to do the
same, as it helps dispel the minor misconception. Just my
opinion.

Hal

···

On 6/1/05, Hal Fulton <hal9000@hypermetrics.com> wrote:

ES wrote:

> > class Foo
> > def initialize
> > @a = 5
> > end
> >
> > attr_accessor :a
> > end
> >
> > foo = Foo.new
> > foo.a = 6
> >
> > Current behaviour aside, should the last line create a new Foo object?
>
> Very funny. Totally different argument,

This is the counterargument for keeping destructive methods.

No it’s not. This is an argument for keeping Ruby non-functional. This
has nothing to do with String#sub vs. String#sub! or Array#sort vs.
Array#sort! for that matter. When discussing destructive methods with
bangs, we’re discussing the merit of having String#sub! around for
efficiency reasons. It’s not a discussion of whether to allow objects
to modify their internal state or not. I know you know this and I know
what you’re trying to say, but this doesn’t lead anywhere,
        nikolai

···

--
Nikolai Weibull: now available free of charge at http://bitwi.se/\!
Born in Chicago, IL USA; currently residing in Gothenburg, Sweden.
main(){printf(&linux["\021%six\012\0"],(linux)["have"]+"fun"-97);}

ES wrote:

> > class Foo
> > def initialize
> > @a = 5
> > end
> >
> > attr_accessor :a
> > end
> >
> > foo = Foo.new
> > foo.a = 6
> >
> > Current behaviour aside, should the last line create a new Foo object?
>
> Very funny. Totally different argument,

This is the counterargument for keeping destructive methods.

No it’s not. This is an argument for keeping Ruby non-functional. This
has nothing to do with String#sub vs. String#sub! or Array#sort vs.
Array#sort! for that matter. When discussing destructive methods with
bangs, we’re discussing the merit of having String#sub! around for
efficiency reasons. It’s not a discussion of whether to allow objects
to modify their internal state or not. I know you know this and I know
what you’re trying to say, but this doesn’t lead anywhere,

It is relevant to the discussion on whether the bang-methods
should be deprecated (that was the topic). Efficiency usually
does not factor in apart from high-volume transactions, so the
only remaining valid argument for them is a conceptual one.

If I want to modify a String, I want to modify it, not create a
new one and assign it to the space of the old one. The conceptual
benefit of this is, of course, more prominent in contexts other
than Strings as shown by the Foo example.

       nikolai

E

···

Le 2/6/2005, "Nikolai Weibull" <mailing-lists.ruby-talk@rawuncut.elitemail.org> a écrit:

--
template<typename duck>
void quack(duck& d) { d.quack(); }

Nikolai Weibull wrote:

It’s not a discussion of whether to allow objects
to modify their internal state or not.

Seeing how Strings are objects, I'm confused, then. You're only talking about builtin objects? You're only talking about objects that have "literal" counterparts (String, Array, Hash, Symbol, etc.)? You're only talking about objects that end in "tring"?

While I almost always opt for the nondestructive methods, I don't feel like making that decision for others.

That said, I don't really care, but I thought I'd try and get you both on the same page.

Devin

Note that string.meth! is not an optimisation of string.meth, it's an
optimisation of string.replace(string.sort). There's a difference when
there are multiple references to the string.

martin

···

Nikolai Weibull <mailing-lists.ruby-talk@rawuncut.elitemail.org> wrote:

No it?s not. This is an argument for keeping Ruby non-functional. This
has nothing to do with String#sub vs. String#sub! or Array#sort vs.
Array#sort! for that matter. When discussing destructive methods with
bangs, we?re discussing the merit of having String#sub! around for
efficiency reasons. It?s not a discussion of whether to allow objects
to modify their internal state or not. I know you know this and I know
what you?re trying to say, but this doesn?t lead anywhere,