Conventions in ruby and the principle of least surprise

Discussion in 'Ruby' started by Einar Boson, Jan 27, 2009.

  1. Einar Boson

    Einar Boson Guest

    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/.
    Einar Boson, Jan 27, 2009
    #1
    1. Advertising

  2. 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!"
    }
    --
    Posted via http://www.ruby-forum.com/.
    Brian Candler, Jan 27, 2009
    #2
    1. Advertising

  3. Einar Boson

    Damjan Rems Guest

    Damjan Rems, Jan 27, 2009
    #3
  4. Einar Boson

    Ryan Davis Guest

    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).
    Ryan Davis, Jan 27, 2009
    #4
  5. Einar Boson

    Mike Gold Guest

    Ryan Davis wrote:
    > 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).


    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.
    --
    Posted via http://www.ruby-forum.com/.
    Mike Gold, Jan 28, 2009
    #5
  6. Einar Boson

    Phlip Guest

    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
    Phlip, Jan 28, 2009
    #6
  7. [Note: parts of this message were removed to make it a legal post.]

    On Tue, Jan 27, 2009 at 4:12 PM, Ryan Davis <>wrote:

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


    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
    Rick DeNatale, Feb 2, 2009
    #7
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. AAaron123
    Replies:
    0
    Views:
    591
    AAaron123
    Oct 3, 2008
  2. Jamie Herre
    Replies:
    1
    Views:
    193
    why the lucky stiff
    Jan 7, 2005
  3. Dave Howell
    Replies:
    20
    Views:
    257
    William James
    Feb 5, 2006
  4. globalrev
    Replies:
    4
    Views:
    101
    Marc Heiler
    May 10, 2008
  5. matt neuburg
    Replies:
    1
    Views:
    99
    Rick DeNatale
    Feb 17, 2009
Loading...

Share This Page