Block Style

J

James Gray

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

I use to just use the rule of { =85 } for one-liners and do =85 end for =20=

the longer stuff. However, I've recently switched to trying out { =85 } =
=20
for the times when I care about the return value and do =85 end for the =20=

times the block is for side effects. For the most part, I do like the =20=

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 =20
return value, but not the return value of the block, so which strategy =20=

should I use? It seems like do =85 end is more correct, but that seems =20=

a lot uglier in practice:

arr.sort.tap do |sorted|
p sorted
end.whatever=85

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

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

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

James Edward Gray II
 
R

Rick DeNatale

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

I use to just use the rule of { =85 } for one-liners and do =85 end for t= he
longer stuff. =A0However, I've recently switched to trying out { =85 } fo= r the
times when I care about the return value and do =85 end for the times the
block is for side effects. =A0For the most part, I do like the new strate= gy,
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. =A0I do care about the retur= n
value, but not the return value of the block, so which strategy should I
use? =A0It seems like do =85 end is more correct, but that seems a lot ug= lier in
practice:

=A0arr.sort.tap do |sorted|
=A0 =A0p sorted
=A0end.whatever=85

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 =3D 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 =3D 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. =A0When us= ing
such a tool, I often end up with calls where I care about both the side
effects (transactional behavior) and the return value:

=A0db.transaction {
=A0 =A0db[:count] +=3D 1
=A0 =A0db[:count]
=A0}

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.


--=20
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
 
J

James Gray

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.

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
 
B

Brian Adkins

Rick DeNatale said:
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.
 
R

Rick DeNatale

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

=A0description 'pickup up the leaves'
=A0task:)rake =3D> 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 =3D> :gadet_widget_usage
task :doit =3D> :didit

rather than

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

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

--=20
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
 
S

Sean O'Halpin

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

I use to just use the rule of { =85 } for one-liners and do =85 end for t= he
longer stuff. =A0However, I've recently switched to trying out { =85 } fo= r the
times when I care about the return value and do =85 end for the times the
block is for side effects. =A0For the most part, I do like the new strate= gy,
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. =A0I do care about the retur= n
value, but not the return value of the block, so which strategy should I
use? =A0It seems like do =85 end is more correct, but that seems a lot ug= lier in
practice:

=A0arr.sort.tap do |sorted|
=A0 =A0p sorted
=A0end.whatever=85

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

=A0db.transaction {
=A0 =A0db[:count] +=3D 1
=A0 =A0db[:count]
=A0}

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=85

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

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

if you're so inclined.

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

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

would seem appropriate.

I'm using this in DSL-type code:

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

and find it more aesthetically pleasing than:

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

Just my tuppenceworth :)

Regards,
Sean
 
J

Joel VanderWerf

Sean said:
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.
 
R

Robert Dober

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 ;)

Cheers
Robert
 
R

Robert Klemme

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? :)

Kind regards

robert
 
J

James Gray

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? :)

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
 
D

David A. Black

Hi --
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 :)


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
 
S

Sean O'Halpin

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.

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

Joel VanderWerf

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

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

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...
 
S

Sean O'Halpin

Does it make a difference, in choosing between

=A0foo {..}.bar

and

=A0foo 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...

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
 
R

Robert Klemme

2009/4/28 James Gray said:
It's definitely easier, but it can lead to less pretty code too, like:

=A0whatevery.map do |e|
=A0 =A0# multiple lines of calculation here...
=A0end.find { ... }

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

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

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

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

Robert Dober

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 ;)

_, *args =3D 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 ;)

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

Cheers
Robert
=A0whatevery.map do |e|
=A0 =A0# multiple lines of calculation here...
=A0end.find { ... }

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

James Edward Gray II



--=20
Si tu veux construire un bateau ...
Ne rassemble pas des hommes pour aller chercher du bois, pr=E9parer des
outils, r=E9partir les t=E2ches, all=E9ger le travail=85 mais enseigne aux
gens la nostalgie de l=92infini de la mer.

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

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,149
Messages
2,570,843
Members
47,390
Latest member
RobertMart

Latest Threads

Top