Do/end vs braces


#1

Hi all,

It looks to me like when you use an iterator (each for instance), you
can make
the block either from a do/end pair, or from curly braces. All things
being
equal, I’d greatly prefer to use do/end. Are there any differences in
runtime
speed, capabilities, or Rubyness?

#!/usr/bin/ruby
(1…4).each do |i|
puts i
end
print “================\n”
(1…4).each { |i|
puts i
}

Output:

[slitt@mydesk slitt]$ ./test.rb
1
2
3
4

1
2
3
4
[slitt@mydesk slitt]$

Thanks

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid


#2

On 12/8/05, Steve L. removed_email_address@domain.invalid wrote:

Hi all,

It looks to me like when you use an iterator (each for instance), you can make
the block either from a do/end pair, or from curly braces. All things being
equal, I’d greatly prefer to use do/end. Are there any differences in runtime
speed, capabilities, or Rubyness?

Typically,

5.times { |i| puts i }

5.times do |i|
puts i
end

Generally people save do … end for multiline stuff. Don’t think
there’s a difference in speed.

Sometimes people who use vim use only braces for vim’s matching
capabilities, although didn’t someone fix that for do…end?


#3

On Dec 8, 2005, at 8:13 AM, Joe Van D. wrote:

Typically,

5.times { |i| puts i }

5.times do |i|
puts i
end

Generally people save do … end for multiline stuff. Don’t think
there’s a difference in speed.

Another convention some use is that { … } are for the times when
you care about the return value and do … end is for when you’re
interested in the side effects. For example:

sum = [1, 2, 3].inject { |sum, n| sum + n } # return value

File.open(“total.txt”, “w”) do |file| # side effects
file.puts sum
end

James Edward G. II


#4

On Dec 8, 2005, at 8:09 AM, Steve L. wrote:

Are there any differences in runtime speed, capabilities, or Rubyness?

There is a subtle difference in binding precedence. I wrote about
that in this message:

http://groups.google.com/group/comp.lang.ruby/msg/b67b116e49473e11

Hope that helps.

James Edward G. II


#5

On 12/8/05, James Edward G. II removed_email_address@domain.invalid wrote:

in runtime
Generally people save do … end for multiline stuff. Don’t think
end
Good point. And also use { … } if you want to do crazy chains like

[1, 2, 3].collect { |a| i * a }.each { |a| puts a }

Joe


#6

On 12/8/05, Joe Van D. removed_email_address@domain.invalid wrote:

equal, I’d greatly prefer to use do/end. Are there any differences

file.puts sum
end

Good point. And also use { … } if you want to do crazy chains like

[1, 2, 3].collect { |a| i * a }.each { |a| puts a }

Oops, that first ‘i’ should be an ‘a’.


#7

Steve L. wrote:

Hi all,

It looks to me like when you use an iterator (each for instance), you can make
the block either from a do/end pair, or from curly braces. All things being
equal, I’d greatly prefer to use do/end. Are there any differences in runtime
speed, capabilities, or Rubyness?

There’s a slight difference in how they’re parsed.

foo bar { block }

is the same as

foo(bar { block })

while

foo bar do
block
end

is the same as

foo(bar) do
block
end

or

foo(bar) { block }

but it’s only an issue when you leave out the parantheses. The styling
convention is that the curly braces are used for one-line blocks and the
do…end for multi-line blocks

foo { make_me_a_bar }
bar do
foo = Foo.new
pass_the_foo(foo)
do_something_else
end

Cheers,
Daniel


#8

Joe Van D. removed_email_address@domain.invalid wrote:

Sometimes people who use vim use only braces for vim’s matching
capabilities, although didn’t someone fix that for do…end?

matchit.vim

martin


#9

Quoting Joe Van D. removed_email_address@domain.invalid:

5.times { |i| puts i }

5.times do |i|
puts i
end

Generally people save do … end for multiline stuff. Don’t think
there’s a difference in speed.

I can promise there’s no speed difference. They both parse to the
same thing:

(iter
(call
(lit #<5>) times)
(dasgn_curr i)
(fcall puts
(array
(dvar i))))

(iter
(call
(lit #<5>) times)
(dasgn_curr i)
(fcall puts
(array
(dvar i))))

However, {} and do…end are not totally interchangable as syntax.
These are all equivalent:

obj.meth( 1, 2 ) { |i|
puts i
}

obj.meth( 1, 2 ) do |i|
puts i
end

obj.meth 1, 2 do |i|
puts i
end

But this will net you a parse error (‘2’ is not a valid method
name):

obj.meth 1, 2 { |i|
puts i
}

And these two parse equivalently:

obj.meth 1, zog { |i|
puts i
}

obj.meth( 1, zog { |i| puts i } )

Think of {} as being more “clingy” than do…end.

Basically, {} has higher precedence than do…end, just as (among
otherwise equivalent operators) && has higher precedence than
‘and’, and || has higher precedence than ‘or’.

I’m sure Ter hates Ruby now. :slight_smile:

-mental


#10

On 12/8/05, Steve L. removed_email_address@domain.invalid wrote:

[slitt@mydesk slitt]$ ./test.rb
./test.rb:3: syntax error
./test.rb:6: syntax error

Take out the space between puts and the open paren:

~$ cat test.rb
my_array = [“alpha”, “beta”, “gamma”]
puts(my_array.collect do
|word|
word.capitalize
end)

~$ ruby test.rb
Alpha
Beta
Gamma

Jacob F.


#11

On Thursday 08 December 2005 06:06 pm, Jacob F. wrote:

end)

Output:
[slitt@mydesk slitt]$ ./test.rb
./test.rb:3: syntax error
./test.rb:6: syntax error

Take out the space between puts and the open paren:

Confirmed! Thanks Jacob. This is the first time I’ve seen Ruby conflict
with
the Rule of Least Surprise (http://www.faqs.org/docs/artu/ch11s01.html).

Is there any chance of a Ruby change so as not to require the paren to
be
flush up against the function name?

Thanks

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid


#12

In article removed_email_address@domain.invalid,
Steve L. removed_email_address@domain.invalid wrote:

    word.capitalize

the Rule of Least Surprise (http://www.faqs.org/docs/artu/ch11s01.html).

Is there any chance of a Ruby change so as not to require the paren to be
flush up against the function name?

Interestingly, it worked for me with a space or without the parens when
I did the puts as a one-liner:

puts my_array.collect {|word| word.capitalize}

or

puts (my_array.collect {|word| word.capitalize})

–paul


#13

On Thursday 08 December 2005 08:42 pm, Paul Sanchez wrote:

Take out the space between puts and the open paren:

puts my_array.collect {|word| word.capitalize}

or

puts (my_array.collect {|word| word.capitalize})

Hi Paul,

It works as expected with braces, but not with do/end.

Thanks

SteveT

Steve L.
http://www.troubleshooters.com
removed_email_address@domain.invalid


#14

On Fri, 2005-12-09 at 10:11 +0900, Steve L. wrote:

Is there any chance of a Ruby change so as not to require the paren to be
flush up against the function name?

Egh… I think that’d introduce more ambiguities into the grammar…
it’s pretty bad that way already.

-mental


#15

On Thursday 08 December 2005 10:07 am, Daniel S. wrote:

foo bar { block }

but it’s only an issue when you leave out the parantheses.
Except I can’t put in the parentheses:

#!/usr/bin/ruby
my_array = [“alpha”, “beta”, “gamma”]
puts (my_array.collect do
|word|
word.capitalize
end)

Output:
[slitt@mydesk slitt]$ ./test.rb
./test.rb:3: syntax error
./test.rb:6: syntax error
[slitt@mydesk slitt]$

Thanks

SteveT


#16

On Fri, Dec 09, 2005 at 05:00:13PM +0900, Logan C. wrote:

Doubtful. Matz. has been trying to move in the opposite direction:
irb(main):003:0> puts (“Hello”, “World”)
(irb):3: warning: don’t put space before argument parentheses
Hello
World
=> nil

I’d be happy with it either way, as long as it’s consistent.


Chad P. [ CCD CopyWrite | http://ccd.apotheon.org ]

unix virus: If you’re using a unixlike OS, please forward
this to 20 others and erase your system partition.


#17

On Dec 8, 2005, at 8:11 PM, Steve L. wrote:

    word.capitalize

conflict with

Doubtful. Matz. has been trying to move in the opposite direction:
irb(main):003:0> puts (“Hello”, “World”)
(irb):3: warning: don’t put space before argument parentheses
Hello
World
=> nil


#18

Chad P. wrote:

I’d be happy with it either way, as long as it’s consistent.

Without space, it’s consistent.
It’s not always what we want it to mean, though.

Take this example (with which I frequently inconvenience myself):

#-----------------------------------------------------
(0…5).map do |n|
10*n
end
#-----------------------------------------------------

  • I want to see the result, so I prepend "p ":

#-----------------------------------------------------
p (0…5).map do |n|
10*n
end
#=> C:/TEMP/rb284.TMP:1: warning: (…) interpreted as grouped
expression

[- Okay, that’s what it is.]

#=> [0, 1, 2, 3, 4, 5]

[- But that’s not what I wanted. The block binds to method #p

- the argument to #p is ((0…5).map) - an Array (in Ruby 1.8.2)

#-----------------------------------------------------

  • Remove the space after p

#-----------------------------------------------------
p(0…5).map do |n|
10*n
end
#=> 0…5

[Oh, no !]

#=> C:/TEMP/rb284.TMP:1: undefined method `map’ for nil:NilClass
(NoMethodError)

[Aargh!]

#-----------------------------------------------------

  • Parenthesise correctly but “uglily” ;))

#-----------------------------------------------------
p((0…5).map do |n|
10*n
end)
#=> [0, 10, 20, 30, 40, 50] # no problem at all
#-----------------------------------------------------

  • But we don’t need to do any of those.
  • From the initial example, just prepend " = "
    and there’s no “binding” issue …

#-----------------------------------------------------
r = (0…5).map do |n|
10*n
end
p r #=> [0, 10, 20, 30, 40, 50]
#-----------------------------------------------------

IMHO, it’s our problem, not Ruby’s.
The problem could appear in many places but, for me,
it’s almost always when prepending p, puts or print.

Things could be a lot worse than this :wink:

daz


#19

Joe Van D. removed_email_address@domain.invalid writes:

Generally people save do … end for multiline stuff. Don’t think

I am not sure why Pickaxe mentioned this convention that is based
on LOC factor rather than one that is based on intent.

Basing it on LOC is silly, IMO. It really is more suitable for
languages that are white-space sensitive.

Consider you wrote:

foo.bar {|a| zoo(a)}

Oh, further down the road you realise that it is valuable to log the
value of a or perhaps you are simply reformatting your code.

foo.bar {|a|
log.debug(a)
zoo(a)
}

Whoops, that’s out of the convention. Your eyes are itchy at that, so
you spent some time fixing it like:

foo.bar do |a|
log.debug(a)
zoo(a)
end

Later on, you decided that logging the value of a is frivolous, so you
changed it again:

foo.bar do |a| zoo(a) end

That violates the convention as well, so you do yet another do-end to
{} transformation

foo.bar {|a| zoo(a)}

All that works is just for one method call. Imagine if there are more,
and there are likely to be more.

Basing it on intent (return value or side-effect or what-have-you)
seems a more rational guideline. For certain, that would make code
reformatting a more pleasurable exercise.

YS.


#20

Yohanes S. wrote:

foo.bar {|a|
end
foo.bar {|a| zoo(a)}

In the end doesn’t it all come up to a matter of preference? I prefer
the curly braces, others prefer do…end. In my book its a matter of
versatility of the language. Which in turn is a verry nice feature,
IMHO.

Daniel C.