Block Style

I hate to be the guy to start another { … } vs. do … end thread, but I have some questions I would love to hear opinions on.

I use to just use the rule of { … } for one-liners and do … end for the longer stuff. However, I've recently switched to trying out { … } for the times when I care about the return value and do … end for the times the block is for side effects. For the most part, I do like the new strategy, but sometimes I have trouble deciding which to use.

Let me give two examples that have made me stop and think.

First, tap() is Ruby 1.9 is a little tricky. I do care about the return value, but not the return value of the block, so which strategy should I use? It seems like do … end is more correct, but that seems a lot uglier in practice:

   arr.sort.tap do |sorted|
     p sorted
   end.whatever…

Another example is with a transaction() method for a database. When using such a tool, I often end up with calls where I care about both the side effects (transactional behavior) and the return value:

   db.transaction {
     db[:count] += 1
     db[:count]
   }

Any thoughts on how edge cases like this mesh with the block strategy?

James Edward Gray II

I hate to be the guy to start another { … } vs. do … end thread, but I have
some questions I would love to hear opinions on.

I use to just use the rule of { … } for one-liners and do … end for the
longer stuff. However, I've recently switched to trying out { … } for the
times when I care about the return value and do … end for the times the
block is for side effects. For the most part, I do like the new strategy,
but sometimes I have trouble deciding which to use.

Well, I went back to what I wrote over a year ago on this
"controversy" and I think it stands up pretty well.

http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace

I for one, eschew dogmatism. When I went back and re-read that article
I was pleased to see that I was far from dogmatic. I talk about
leaning or tilting one way or the other. This is more about
aesthetics than laws of nature or rocket surgery.

Let me give two examples that have made me stop and think.

First, tap() is Ruby 1.9 is a little tricky. I do care about the return
value, but not the return value of the block, so which strategy should I
use? It seems like do … end is more correct, but that seems a lot uglier in
practice:

arr.sort.tap do |sorted|
p sorted
end.whatever…

Here I'd go with braces, because as I say in that article, that

    end.whatever

just grates with me. On the other hand if it was

var = arr.sort.tap.do | sorted|
    #.....
end

I would probably lean more towards do/end, but then again, if the
block was a one-liner like yours then I might well 'break the tie"
with the one-vs-multi line idea

var = arr.sort.tap {|sorted| p sorted}

In fact I'd probably be inclined to write your example on one line

arr.sort.tap {|sorted| p sorted}.whatever

Another example is with a transaction() method for a database. When using
such a tool, I often end up with calls where I care about both the side
effects (transactional behavior) and the return value:

db.transaction {
db[:count] += 1
db[:count]
}

This one looks a little odd to my eye just because most of the db
transaction delimiting methods I've seen don't return the value of the
block, they are concerned simply with marking a transaction boundary.

···

On Sun, Apr 26, 2009 at 6:48 PM, James Gray <james@grayproductions.net> wrote:

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

I prefer {} when using blocks in a functional style, do..end when
using statements but I'm with Rick on the 'foolish consistency'.

In your first example, it would appear that you ~are~ concerned with
the return value of the block as you call #whatever on it, so I'd use:

  arr.sort.tap { |sorted|
    p sorted
  }.whatever…

assuming that the 'p sorted' stands for a multiline statement. In 1.9
you can even do:

  arr
    .sort
    .tap { |sorted| p sorted }
    .whatever…

if you're so inclined.

In the second you're not using the return value, so

  db.transaction do
    db[:count] += 1
    db[:count]
  end

would seem appropriate.

I'm using this in DSL-type code:

  person = Person :name => "Arthur" do
    age 42
  end

and find it more aesthetically pleasing than:

  person = Person(:name => "Arthur") {
    age 42
  }

Just my tuppenceworth :slight_smile:

Regards,
Sean

···

On Sun, Apr 26, 2009 at 11:48 PM, James Gray <james@grayproductions.net> wrote:

I hate to be the guy to start another { … } vs. do … end thread, but I have
some questions I would love to hear opinions on.

I use to just use the rule of { … } for one-liners and do … end for the
longer stuff. However, I've recently switched to trying out { … } for the
times when I care about the return value and do … end for the times the
block is for side effects. For the most part, I do like the new strategy,
but sometimes I have trouble deciding which to use.

Let me give two examples that have made me stop and think.

First, tap() is Ruby 1.9 is a little tricky. I do care about the return
value, but not the return value of the block, so which strategy should I
use? It seems like do … end is more correct, but that seems a lot uglier in
practice:

arr.sort.tap do |sorted|
p sorted
end.whatever…

Another example is with a transaction() method for a database. When using
such a tool, I often end up with calls where I care about both the side
effects (transactional behavior) and the return value:

db.transaction {
db[:count] += 1
db[:count]
}

Any thoughts on how edge cases like this mesh with the block strategy?

James Edward Gray II

Interesting. I've been using Amalgalite a lot lately. It definitely returns the value. PStore in the standard library does as well. I have double-checked ActiveRecord, but my expection would be that it does too. Maybe I'm wrong though.

James Edward Gray II

···

On Apr 26, 2009, at 7:32 PM, Rick DeNatale wrote:

On Sun, Apr 26, 2009 at 6:48 PM, James Gray > <james@grayproductions.net> wrote:

Another example is with a transaction() method for a database. When using
such a tool, I often end up with calls where I care about both the side
effects (transactional behavior) and the return value:

db.transaction {
   db[:count] += 1
   db[:count]
}

This one looks a little odd to my eye just because most of the db
transaction delimiting methods I've seen don't return the value of the
block, they are concerned simply with marking a transaction boundary.

Rick DeNatale <rick.denatale@gmail.com> writes:

···

On Sun, Apr 26, 2009 at 6:48 PM, James Gray <james@grayproductions.net> wrote:

I hate to be the guy to start another { … } vs. do … end thread, but I have
some questions I would love to hear opinions on.

I use to just use the rule of { … } for one-liners and do … end for the
longer stuff. However, I've recently switched to trying out { … } for the
times when I care about the return value and do … end for the times the
block is for side effects. For the most part, I do like the new strategy,
but sometimes I have trouble deciding which to use.

Well, I went back to what I wrote over a year ago on this
"controversy" and I think it stands up pretty well.

http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace

FYI - looks like you have an extra trailing paren here in the last
code example:

  description 'pickup up the leaves'
  task(:rake => pre_raking_tasks) {#code to rake the leaves})

BTW - this is one of the reasons I tend to use parens on function
invocations consistently.

--
Brian Adkins
http://lojic.com/

Sean O'Halpin wrote:

In your first example, it would appear that you ~are~ concerned with
the return value of the block as you call #whatever on it, so I'd use:

  arr.sort.tap { |sorted|
    p sorted
  }.whatever…

Actually, the return value of #tap is different from the return value of the block (which is ignored by tap, IIRC). That puzzled me for a moment.

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

I have adapted a very simple rule for a long time now, if I use the
block for the side effect it is do..end, always.
If I use it for its return value it is { } always, (BTW thank you Rick ;).
But of course when I do side effects and use the return value I am
lost. (I guess that it is {} for one liners and do end otherwise than)

I know this was very helpful :wink:

Cheers
Robert

Hi --

Sean O'Halpin wrote:

···

On Sun, Apr 26, 2009 at 11:48 PM, James Gray<james@grayproductions.net> wrote:

I hate to be the guy to start another { … } vs. do … end thread, but I have
some questions I would love to hear opinions on.

I use to just use the rule of { … } for one-liners and do … end for the
longer stuff. However, I've recently switched to trying out { … } for the
times when I care about the return value and do … end for the times the
block is for side effects. For the most part, I do like the new strategy,
but sometimes I have trouble deciding which to use.

Let me give two examples that have made me stop and think.

First, tap() is Ruby 1.9 is a little tricky. I do care about the return
value, but not the return value of the block, so which strategy should I
use? It seems like do … end is more correct, but that seems a lot uglier in
practice:

  arr.sort.tap do |sorted|
    p sorted
  end.whatever…

Another example is with a transaction() method for a database. When using
such a tool, I often end up with calls where I care about both the side
effects (transactional behavior) and the return value:

  db.transaction {
    db[:count] += 1
    db[:count]
  }

Any thoughts on how edge cases like this mesh with the block strategy?

James Edward Gray II

I prefer {} when using blocks in a functional style, do..end when
using statements but I'm with Rick on the 'foolish consistency'.

In your first example, it would appear that you ~are~ concerned with
the return value of the block as you call #whatever on it, so I'd use:

   arr.sort.tap { |sorted|
     p sorted
   }.whatever…

assuming that the 'p sorted' stands for a multiline statement. In 1.9
you can even do:

   arr
     .sort
     .tap { |sorted| p sorted }
     .whatever…

if you're so inclined.

Though not in irb. (And, preferably, not anywhere, but that's probably a lost cause :slight_smile:

David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Now out in PDF: The Well-Grounded Rubyist (http://manning.com/black2\)
"Ruby 1.9: What You Need To Know" Envycasts with David A. Black
http://www.envycasts.com

Rick DeNatale <rick.denatale@gmail.com> writes:

http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace

FYI - looks like you have an extra trailing paren here in the last
code example:

description 'pickup up the leaves'
task(:rake => pre_raking_tasks) {#code to rake the leaves})

Yeah that was a cut and past typo in the sequence of examples.

BTW - this is one of the reasons I tend to use parens on function
invocations consistently.

I also tend to use more parentheses than most rubyists, but I don't
normally use them in the face of a DSL method, so I use

attr_reader :foo
alias_method :meth1, :meth2
has_many :widgets, :through => :gadet_widget_usage
task :doit => :didit

rather than

attr_reader(:foo)
alias_method(:meth1, :meth2)
has_many(:widgets, :through => :gadet_widget_usage)
task(:doit => :didit)

As I said eariler, I eschew dogmatism. I agree with Ralph Waldo
Emerson's "A foolish consistency is the hobgoblin of little minds."

···

On Mon, Apr 27, 2009 at 7:00 AM, Brian Adkins <lojicdotcom@gmail.com> wrote:

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

I have adapted a very simple rule for a long time now, if I use the
block for the side effect it is do..end, always.
If I use it for its return value it is { } always, (BTW thank you Rick ;).
But of course when I do side effects and use the return value I am
lost.

I don't have the problem, because I always do this:

(I guess that it is {} for one liners and do end otherwise than)

One liner and multi liner is actually exclusive, which cannot be said of return value and side effects. Maybe my sticking to the syntactical convention is the reason why I never bother to think about which rules to use. James, maybe that can ease your "pain" as well? :slight_smile:

Kind regards

  robert

···

On 27.04.2009 19:11, Robert Dober wrote:

You're right - sloppy wording on my part. But you were only puzzled
for a moment, right? :wink:

···

On Mon, Apr 27, 2009 at 6:07 PM, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

Sean O'Halpin wrote:

In your first example, it would appear that you ~are~ concerned with
the return value of the block as you call #whatever on it, so I'd use:

arr.sort.tap { |sorted|
p sorted
}.whatever…

Actually, the return value of #tap is different from the return value of the
block (which is ignored by tap, IIRC). That puzzled me for a moment.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

It's definitely easier, but it can lead to less pretty code too, like:

   whatevery.map do |e|
     # multiple lines of calculation here...
   end.find { ... }

That's one reason why I was looking into the other option.

James Edward Gray II

···

On Apr 27, 2009, at 3:25 PM, Robert Klemme wrote:

On 27.04.2009 19:11, Robert Dober wrote:

(I guess that it is {} for one liners and do end otherwise than)

One liner and multi liner is actually exclusive, which cannot be said of return value and side effects. Maybe my sticking to the syntactical convention is the reason why I never bother to think about which rules to use. James, maybe that can ease your "pain" as well? :slight_smile:

Sean O'Halpin wrote:

Sean O'Halpin wrote:

In your first example, it would appear that you ~are~ concerned with
the return value of the block as you call #whatever on it, so I'd use:

arr.sort.tap { |sorted|
   p sorted
}.whatever…

Actually, the return value of #tap is different from the return value of the
block (which is ignored by tap, IIRC). That puzzled me for a moment.

--
     vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

You're right - sloppy wording on my part. But you were only puzzled
for a moment, right? :wink:

No, I'm puzzled most of the time :slight_smile:

Does it make a difference, in choosing between

  foo {..}.bar

and

  foo do..end.bar

whether the value is the block value or the #foo return value (in those cases where they differ)? Probably not, just a thought...

···

On Mon, Apr 27, 2009 at 6:07 PM, Joel VanderWerf > <vjoel@path.berkeley.edu> wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

I guess it's in the eye of the beholder but

  end.bar

just looks odd to me.

And now I think about it, when we do

  arr.map {|x| x * x }.sort

we're not operating on the return value of the block either but

   arr.map do |x| x * x end.sort

just looks wrong to me.

Regards,
Sean

···

On Tue, Apr 28, 2009 at 12:47 AM, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:

Does it make a difference, in choosing between

foo {..}.bar

and

foo do..end.bar

whether the value is the block value or the #foo return value (in those
cases where they differ)? Probably not, just a thought...

Well, I personally do not find that "less pretty" - but this lies in
the eye of the beholder. :slight_smile:

If it comes to prettiness of code, for me these items are more important:

* proper indentation,
* avoidance of deep nesting of control structures,
* wise use of empty lines to visually separate logical bits of code.

But I'm digressing...

Kind regards

robert

···

2009/4/28 James Gray <james@grayproductions.net>:

On Apr 27, 2009, at 3:25 PM, Robert Klemme wrote:

On 27.04.2009 19:11, Robert Dober wrote:

(I guess that it is {} for one liners and do end otherwise than)

One liner and multi liner is actually exclusive, which cannot be said of
return value and side effects. Maybe my sticking to the syntactical
convention is the reason why I never bother to think about which rules to
use. James, maybe that can ease your "pain" as well? :slight_smile:

It's definitely easier, but it can lead to less pretty code too, like:

whatevery.map do |e|
# multiple lines of calculation here...
end.find { ... }

That's one reason why I was looking into the other option.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

(I guess that it is {} for one liners and do end otherwise than)

One liner and multi liner is actually exclusive, which cannot be said of
return value and side effects. Maybe my sticking to the syntactical
convention is the reason why I never bother to think about which rules to
use. James, maybe that can ease your "pain" as well? :slight_smile:

It's definitely easier, but it can lead to less pretty code too, like:

...and being easier it just does not convey any additional information.

I adapted my style because I thought - and still think - that
providing the information of side effect is of value to the reader of
the code.
I am aware that being used to the style is also very valuable to the
reader, but that is a long, interesting and complicated matter, which,
if not OT is Super Topic in the mathematical sense of superset.
That said I should probable stick to {} if there is no side effect to
the block (1), thus indicating functional style and to do end for
anything else, because if the return value of the block is used or not
should actually be well documented.
Which is worth yet another discussion.

That would, e.g give, to cite myself :wink:

_, *args = whatever.split.sort_by{ .... }
inject{ } # while inject do ... end should raise an alarm bell

and

each.do |x| puts x end # sorry if this example is too sophisticated :wink:

(1) Updating closed in locals considering a side effect or not?

Cheers
Robert

···

On Tue, Apr 28, 2009 at 12:05 AM, James Gray <james@grayproductions.net> wrote:

On Apr 27, 2009, at 3:25 PM, Robert Klemme wrote:

On 27.04.2009 19:11, Robert Dober wrote:

whatevery.map do |e|
# multiple lines of calculation here...
end.find { ... }

That's one reason why I was looking into the other option.

James Edward Gray II

--
Si tu veux construire un bateau ...
Ne rassemble pas des hommes pour aller chercher du bois, préparer des
outils, répartir les tâches, alléger le travail… mais enseigne aux
gens la nostalgie de l’infini de la mer.

If you want to build a ship, don’t herd people together to collect
wood and don’t assign them tasks and work, but rather teach them to
long for the endless immensity of the sea.

--
Antoine de Saint-Exupéry