Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Conventions in ruby and the principle of least surprise

17 views
Skip to first unread message

Einar Boson

unread,
Jan 26, 2009, 9:11:55 PM1/26/09
to
Hi guys, and hi Matz. I have a few questions about ruby syntax and
library that so far has had me surprised. I know Matz doesn't say that
ruby shouldn't surprise me, but rather not surprise him but still, i
would like to hear the reasoning behind a few weird things:

do..end vs. {}

Say I have this function:

def save_block name, &b
@blocks ||= {}
@blocks[name] = b
end

Now this is fine:

save_block :say_hello do
puts "hello!"
end

but not this:

save_block :say_hello {
puts "hello!"
}

I find that rather annoying but I guess it's to be able to write things
like

save_block ["name1_long", "name2_long", "short"].find {|n| n.size <=
5}.to_sym do
puts "hello!"
end

Personally I would rather have had to use parentheses to bind the block
to find, but I realize that it's hardly up to me :)

Anyways. More serious, in my oppinion, is the fact that Array#insert and
String#insert are destructive without having an exclamation mark. Why is
that? I really do not expect them to change their owner.

>> hi = "hello world"
=> "hello world"
>> puts hi
hello world
=> nil
>> puts hi.insert(6, "surprising ")
hello surprising world
=> nil
>> puts hi
hello surprising world
=> nil

seriously, wtf? Why not `insert` and `insert!` that behave as expected?
Before I realized this I had a hard time tracking down some unexpected
behaviour.
--
Posted via http://www.ruby-forum.com/.

Yukihiro Matsumoto

unread,
Jan 26, 2009, 9:47:29 PM1/26/09
to
Hi,

In message "Re: Conventions in ruby and the principle of least surprise"
on Tue, 27 Jan 2009 11:11:55 +0900, Einar Boson <einar...@tistron.se> writes:

|do..end vs. {}

|I find that rather annoying but I guess it's to be able to write things
|like
|
|save_block ["name1_long", "name2_long", "short"].find {|n| n.size <=
|5}.to_sym do
| puts "hello!"
|end

Correct.

|Anyways. More serious, in my oppinion, is the fact that Array#insert and
|String#insert are destructive without having an exclamation mark. Why is
|that? I really do not expect them to change their owner.

|seriously, wtf? Why not `insert` and `insert!` that behave as expected?

The bang (!) does not mean "destructive" nor lack of it mean non
destructive either. The bang sign means "the bang version is more
dangerous than its non bang counterpart; handle with care". Since
Ruby has a lot of "destructive" methods, if bang signs follow your
opinion, every Ruby program would be full of bangs, thus ugly.

matz.

Brian Candler

unread,
Jan 27, 2009, 3:25:54 AM1/27/09
to
Einar Boson wrote:
> Now this is fine:
>
> save_block :say_hello do
> puts "hello!"
> end
>
> but not this:
>
> save_block :say_hello {
> puts "hello!"
> }

Although this is fine:

save_block(:say_hello) {
puts "hello!"

Damjan Rems

unread,
Jan 27, 2009, 5:08:06 AM1/27/09
to

My convention is use {} in oneliners. In all other examples I use
do..end.

by
TheR

Ryan Davis

unread,
Jan 27, 2009, 4:12:29 PM1/27/09
to

On Jan 27, 2009, at 02:08 , Damjan Rems wrote:

> My convention is use {} in oneliners. In all other examples I use
> do..end.

I follow (and teach) the weirich method:

http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc

{} for block values I care about (think map), do/end for regular block
sends (think each).

I use {} for blocks that return values (think #map) and do/end for all
other blocks (think #each).


Mike Gold

unread,
Jan 27, 2009, 7:21:39 PM1/27/09
to

funcs = []
(1..5).each do |i|
funcs << lambda { i }
end
p funcs.map { |f| f.call } # => [1, 2, 3, 4, 5]

funcs2 = []
for j in 1..5
funcs2 << lambda { j }
end
p funcs2.map { |f| f.call } # => [5, 5, 5, 5, 5]

I prefer to make the new binding scope of a block visually obvious,
therefore I always use {}. do/end tricks me into thinking it belongs to
the same category as for/end or while/end or if/end, but it's quite
different (above).

Also, I like one rule better than two rules.

Phlip

unread,
Jan 28, 2009, 6:35:03 PM1/28/09
to
Mike Gold wrote:

> funcs2 = []
> for j in 1..5
> funcs2 << lambda { j }
> end
> p funcs2.map { |f| f.call } # => [5, 5, 5, 5, 5]
>
> I prefer to make the new binding scope of a block visually obvious,
> therefore I always use {}. do/end tricks me into thinking it belongs to
> the same category as for/end or while/end or if/end, but it's quite
> different (above).
>
> Also, I like one rule better than two rules.

Curiously, Ruby departs with 40 years of Structural Programming tradition - the
statement groups controlled by if-end, and their ilk, do _not_ introduce a new
variable scope, while the statement groups inside true blocks _do_ introduce
scoped variables.

Furtherless, the region inside a block _might_ be someone else's scope! Rails's
render :update do ... end does this to us. Principle of Most Surprise applies.

So making dangerous things like blocks look ugly is a good way to help us
respect them!

--
Phlip

Julian Leviston

unread,
Jan 30, 2009, 6:31:57 PM1/30/09
to
Awesome :) perhaps these little gems of what certain things mean as a
FAQ could make their way into the web site.

Sent from my iPhone

On 27/01/2009, at 1:47 PM, Yukihiro Matsumoto <ma...@ruby-lang.org>
wrote:

Rick DeNatale

unread,
Feb 2, 2009, 11:44:32 AM2/2/09
to
[Note: parts of this message were removed to make it a legal post.]

Yes, it's the "I care about' that matters, a subtle distinction to the
weirich method, which I wrote about:

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

and Jim agreed in the comments.

--
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale

0 new messages