Proc vs lambda vs proc

Discussion in 'Ruby' started by Minkoo Seo, Feb 4, 2007.

  1. Minkoo Seo

    Minkoo Seo Guest

    Hi group(and probably ruby-talk list - is it running btw?).

    I got a question on Proc.new and lambda { ... }. AFAIK, there's two
    differences between Proc.new(=proc) and lambda. The first one is that
    Proc.new does not check the number of arguments passed to it while
    lambda does. The secondis that lambda returns as we expect, i.e., it
    returns value, while Proc.new does not.

    Though Proc.new lacks several advantages that lambda has, I guess
    there might be some situation where Proc.new is more suitable than
    lambda. As an example, some code blocks that have to executed
    thousands times might run more faster than lambda because it does not
    have to check the # of arguments, thereby decreasing computational
    overhead.

    What is your opinion?

    Sincerely,
    Minkoo Seo
    Minkoo Seo, Feb 4, 2007
    #1
    1. Advertising

  2. On 04.02.2007 04:55, Minkoo Seo wrote:
    > I got a question on Proc.new and lambda { ... }. AFAIK, there's two
    > differences between Proc.new(=proc) and lambda.


    I think you have it slightly wrong: "proc" and "lambda" are aliases
    while "Proc.new" works different.

    > The first one is that
    > Proc.new does not check the number of arguments passed to it while
    > lambda does.


    Correct:

    irb(main):001:0> f1 = Proc.new {|a,b|a+b}
    => #<Proc:0x003bb2d0@(irb):1>
    irb(main):002:0> f2 = proc {|a,b|a+b}
    => #<Proc:0x003b1690@(irb):2>
    irb(main):003:0> f3 = lambda {|a,b|a+b}
    => #<Proc:0x003a4d3c@(irb):3>
    irb(main):004:0> f1[1,2]
    => 3
    irb(main):005:0> f1[1,2,3]
    => 3
    irb(main):006:0> f2[1,2,3]
    ArgumentError: wrong number of arguments (3 for 2)
    from (irb):2
    from (irb):6:in `[]'
    from (irb):6
    from :0
    irb(main):007:0> f3[1,2,3]
    ArgumentError: wrong number of arguments (3 for 2)
    from (irb):3
    from (irb):7:in `[]'
    from (irb):7
    from :0
    irb(main):008:0> f2[1,2]
    => 3
    irb(main):009:0> f3[1,2]
    => 3

    > The secondis that lambda returns as we expect, i.e., it
    > returns value, while Proc.new does not.


    I do not understand what you mean here. All three return what you
    expect (apart from an exception in the case of wrong # of arguments.

    > Though Proc.new lacks several advantages that lambda has,


    Which advantages do you refer to?

    > I guess
    > there might be some situation where Proc.new is more suitable than
    > lambda. As an example, some code blocks that have to executed
    > thousands times might run more faster than lambda because it does not
    > have to check the # of arguments, thereby decreasing computational
    > overhead.


    I suggest to benchmark a concrete example if you are interested in
    timings. My guess is that the parameter checking overhead is negligible.

    > What is your opinion?


    I usually use lambda because it most resembles the term "lambda
    expression". But I guess this is just a matter of taste / personal
    preference.

    Kind regards

    robert
    Robert Klemme, Feb 4, 2007
    #2
    1. Advertising

  3. Minkoo Seo

    Kalman Noel Guest

    Robert Klemme:
    > On 04.02.2007 04:55, Minkoo Seo wrote:
    >> I got a question on Proc.new and lambda { ... }. AFAIK, there's two
    >> differences between Proc.new(=proc) and lambda.

    > I think you have it slightly wrong: "proc" and "lambda" are aliases
    > while "Proc.new" works different.


    This is true for Ruby 1.8, but was changed in Ruby 1.9. The decision was
    taken because proc and Proc.new are lexically too similar to have different
    meanings, IIRC.

    Kalman
    Kalman Noel, Feb 4, 2007
    #3
  4. On 04.02.2007 12:28, Kalman Noel wrote:
    > Robert Klemme:
    >> On 04.02.2007 04:55, Minkoo Seo wrote:
    >>> I got a question on Proc.new and lambda { ... }. AFAIK, there's two
    >>> differences between Proc.new(=proc) and lambda.

    >> I think you have it slightly wrong: "proc" and "lambda" are aliases
    >> while "Proc.new" works different.

    >
    > This is true for Ruby 1.8, but was changed in Ruby 1.9. The decision was
    > taken because proc and Proc.new are lexically too similar to have different
    > meanings, IIRC.


    Thanks for the heads up! Me not being an early adopter tested with 1.8
    only. At least I don't have to change my habit of using "lambda". :)

    Kind regards

    robert
    Robert Klemme, Feb 4, 2007
    #4
  5. Minkoo Seo

    Guest

    Hi --

    On Sun, 4 Feb 2007, Kalman Noel wrote:

    > Robert Klemme:
    >> On 04.02.2007 04:55, Minkoo Seo wrote:
    >>> I got a question on Proc.new and lambda { ... }. AFAIK, there's two
    >>> differences between Proc.new(=proc) and lambda.

    >> I think you have it slightly wrong: "proc" and "lambda" are aliases
    >> while "Proc.new" works different.

    >
    > This is true for Ruby 1.8, but was changed in Ruby 1.9. The decision was
    > taken because proc and Proc.new are lexically too similar to have different
    > meanings, IIRC.


    Yes -- this was something that was raised at RubyConf in 2002 or 2003,
    and Matz agreed that having proc != Proc.new, while proc == lambda,
    was confusing.


    David

    --
    Q. What is THE Ruby book for Rails developers?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
    , Feb 4, 2007
    #5
  6. Minkoo Seo

    Guest

    Hi --

    On Sun, 4 Feb 2007, Robert Klemme wrote:

    > On 04.02.2007 12:28, Kalman Noel wrote:
    >> Robert Klemme:
    >>> On 04.02.2007 04:55, Minkoo Seo wrote:
    >>>> I got a question on Proc.new and lambda { ... }. AFAIK, there's two
    >>>> differences between Proc.new(=proc) and lambda.
    >>> I think you have it slightly wrong: "proc" and "lambda" are aliases while
    >>> "Proc.new" works different.

    >>
    >> This is true for Ruby 1.8, but was changed in Ruby 1.9. The decision was
    >> taken because proc and Proc.new are lexically too similar to have different
    >> meanings, IIRC.

    >
    > Thanks for the heads up! Me not being an early adopter tested with 1.8 only.
    > At least I don't have to change my habit of using "lambda". :)


    Originally, I think the decision was to deprecate 'proc' entirely --
    which would be fine with me, though as long as it's not different from
    Proc.new that's OK too.


    David

    --
    Q. What is THE Ruby book for Rails developers?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
    , Feb 4, 2007
    #6
  7. Minkoo Seo

    Jim Weirich Guest

    Minkoo Seo wrote:
    > [...]
    > The secondis that lambda returns as we expect, i.e., it
    > returns value, while Proc.new does not.
    >
    > [...] I guess
    > there might be some situation where Proc.new is more suitable than
    > lambda. [...]


    lambda and Proc.new do handle the return statement in different ways.
    Return in lambda returns from the lambda, treating the lambda as an
    anonymous function.

    Return in Proc.new returns from the enclosing method, treating the block
    as an inline piece of code.

    The Proc.new behavior is useful where the block is simply a bit the
    algorithm. For example:

    def member?(target, list)
    list.each do |item|
    return true if target == item
    end
    false
    end

    The explicit return should return from the member? method, not just from
    the loop.

    -- Jim Weirich

    --
    Posted via http://www.ruby-forum.com/.
    Jim Weirich, Feb 4, 2007
    #7
  8. Minkoo Seo

    Minkoo Seo Guest

    On Feb 4, 8:18 pm, Robert Klemme <> wrote:
    > On 04.02.2007 04:55, Minkoo Seo wrote:
    > > there might be some situation where Proc.new is more suitable than
    > > lambda. As an example, some code blocks that have to executed
    > > thousands times might run more faster than lambda because it does not
    > > have to check the # of arguments, thereby decreasing computational
    > > overhead.

    >
    > I usually use lambda because it most resembles the term "lambda
    > expression". But I guess this is just a matter of taste / personal
    > preference.
    >
    > Kind regards
    >
    > robert


    Okay. The problem is that I am writing a ruby tutorial for people from
    other langauges (like C++ or Java), but there are three seemingly same
    things: block, proc, and lambda. So I need to write about not only the
    differences but also the simple but effective rule for choosing one
    out of three.

    To make it worse, the functionality provided by proc and lambda is
    quite similar except for the differences in parameter checking and
    return statement handling. And many people suggest to use lambda
    instead of proc if one does not have any particular reason. So what
    I'd like to do is to verify whether the preference for lambda is
    correct or not.

    So, my intention is to find out whether there are people who prefer
    Proc to lambda whatever the reason is. Up to now, I see none. Any one?

    Sincerely,
    Minkoo Seo
    Minkoo Seo, Feb 5, 2007
    #8
  9. Minkoo Seo

    Minkoo Seo Guest

    On Feb 5, 4:37 am, Jim Weirich <> wrote:
    > Minkoo Seo wrote:
    > > [...]
    > > The secondis that lambda returns as we expect, i.e., it
    > > returns value, while Proc.new does not.

    >
    > lambda and Proc.new do handle the return statement in different ways.
    > Return in lambda returns from the lambda, treating the lambda as an
    > anonymous function.
    >
    > Return in Proc.new returns from the enclosing method, treating the block
    > as an inline piece of code.
    >
    > The Proc.new behavior is useful where the block is simply a bit the
    > algorithm. For example:
    >


    I guess the following block (do |item| ... end)

    > def member?(target, list)
    > list.each do |item|
    > return true if target == item
    > end
    > false
    > end
    > The explicit return should return from the member? method, not just from
    > the loop.
    >
    > -- Jim Weirich


    is block and not a proc.

    AFAIK, block is not converted to proc unless the block is captured by
    parameter like &blk. Am I wrong?

    Sincerely,
    Minkoo Seo
    Minkoo Seo, Feb 5, 2007
    #9
  10. I found the following:
    http://innig.net/software/ruby/closures-in-ruby.rb
    to be an interesting read on the different flavors of closures in
    ruby; I think it takes into account some of the 1.9 changes, but it
    may be slightly outdated...

    -P

    On 2/5/07, Minkoo Seo <> wrote:
    > On Feb 5, 4:37 am, Jim Weirich <> wrote:
    > > Minkoo Seo wrote:
    > > > [...]
    > > > The secondis that lambda returns as we expect, i.e., it
    > > > returns value, while Proc.new does not.

    > >
    > > lambda and Proc.new do handle the return statement in different ways.
    > > Return in lambda returns from the lambda, treating the lambda as an
    > > anonymous function.
    > >
    > > Return in Proc.new returns from the enclosing method, treating the block
    > > as an inline piece of code.
    > >
    > > The Proc.new behavior is useful where the block is simply a bit the
    > > algorithm. For example:
    > >

    >
    > I guess the following block (do |item| ... end)
    >
    > > def member?(target, list)
    > > list.each do |item|
    > > return true if target == item
    > > end
    > > false
    > > end
    > > The explicit return should return from the member? method, not just from
    > > the loop.
    > >
    > > -- Jim Weirich

    >
    > is block and not a proc.
    >
    > AFAIK, block is not converted to proc unless the block is captured by
    > parameter like &blk. Am I wrong?
    >
    > Sincerely,
    > Minkoo Seo
    >
    >
    >
    Patrick Fernie, Feb 5, 2007
    #10
  11. Minkoo Seo

    Phrogz Guest

    On Feb 5, 8:29 am, "Patrick Fernie" <> wrote:
    > I found the following:http://innig.net/software/ruby/closures-in-ruby.rb
    > to be an interesting read on the different flavors of closures in
    > ruby; I think it takes into account some of the 1.9 changes, but it
    > may be slightly outdated...


    Although certainly interesting, the author seems to have a slightly
    too-broad definition of the term closure. He seems to think that
    closures must be first-class functions in addition to providing
    lexical binding to the environment they were defined in. That's simply
    not so.

    Further, he seems to be confusing the syntax of Ruby with features.
    For example, in a function:
    def foo( *a ); end
    You refer to array of values by the variable 'a', not by '*a'; just
    so, of course you refer to a block in a function
    def foo( &b ); end
    simply as 'b'...he seems hung up that you can't use &b directly.
    Phrogz, Feb 5, 2007
    #11
  12. Minkoo Seo

    Guest

    This thread caused me to do some experimenting and I came across some
    Proc semantics that I hadn't seen discussed before and that might
    be useful in a DSL context. Consider:

    class A
    Foo = define_method:)foo) { |x|
    p "self: #{self}"
    return 'positive' if x > 0
    'negative'
    }
    end

    p A::Foo # #<Proc::6>
    p A::Foo.call(0) # "self: A" "negative"
    p A::Foo.call(1) # "self: A" "positive"
    p A.new.foo(0) # "self: #<A:0x25ecc>" "negative"
    p A.new.foo(1) # "self: #<A:0x25e2c>" "positive"

    I was unaware that define_method returned a proc. I was even more
    surprised that it appears to be of the lambda "flavor". That is to
    say that a 'return' within the block is relative to the block and not
    to the scope where the block is defined.

    Previously I thought that only Kernel#proc and Kernel#lambda had
    the 'magic' property of altering the return semantics of a block.
    I understand why this is also necessary for define_method to be
    useful, I was just not aware that the resulting proc was accessible
    as the return value of define_method.

    I was going to ask if there was any way to write a method like
    'define_method' that forces any provided blocks to be interpreted
    as lambda vs. 'regular' procs. Then I did some more experimenting:

    a = Proc.new { return 42 }
    a.call # LocalJumpError

    b = lambda &a
    a.call # 42

    This was another surprise for me as I figured that when lambda was
    used, the first proc would be 'wrapped' in a new proc with
    lambda semantics, something like:

    c = lambda { a.call }

    But that isn't the case. If you try 'c.call' you'll get the
    LocalJumpError again.

    I hadn't see this type of transformation before. It might be
    useful in some DSL situations:

    class A
    filter {|x| x.to_s } # ok
    filter {|x| return x.to_s } # potential LocalJumpError
    end

    If you wrote filter as:

    def A.filter(&b)
    lambda(&b).call(42)
    end

    you can avoid the LocalJumpError.


    Gary Wright
    , Feb 5, 2007
    #12
  13. Minkoo Seo

    Pit Capitain Guest

    schrieb:
    > (... useful infos about procs ...)


    Very interesting! Thanks for sharing your experiments.

    Regards,
    Pit
    Pit Capitain, Feb 5, 2007
    #13
  14. On Tue, Feb 06, 2007 at 04:00:44AM +0900, Pit Capitain wrote:
    > schrieb:
    > >(... useful infos about procs ...)

    >
    > Very interesting! Thanks for sharing your experiments.


    Yes, it's interesting to be reminded of all this again.

    Much as I love Ruby, I hate having multiple versions of essentially the same
    concept which differ in subtle ways. I would find it more aesthetically
    pleasing if a tiny Ruby core could bootstrap the whole language - and it
    might make it easier to port (and understand).

    Now, I wonder why you couldn't approach this problem from the other
    direction: instead of having two or more different types of lambda, which
    handle 'return' semantics differently, have a single type of lambda and two
    different return statements. For example:

    return val # return from enclosing method
    result val # return from this block only

    Internally, you could implement 'return' semantics using catch and throw:

    def foo
    ... some code
    end

    # could be implemented as something like this:

    define_method:)foo) do
    catch:)return) do
    ... some code
    end
    end

    module Kernel
    def return(rc=nil)
    throw:)return, rc)
    end
    end

    The other difference concerns arity. I don't see why argument checking can't
    be done everywhere, as long as you have the option of explicitly allowing
    variable arguments where you want them:

    p1 = Proc.new { |x=nil,y=nil| ... } # accept 2 or fewer args
    p2 = Proc.new { |x, y, *z| ... } # accept 2 or more args
    p3 = Proc.new { |*x| ... } # no more single-arg special case!

    That is, use the same argument list handling for a 'def' method definition,
    a block, and a Proc/proc/lambda.

    Anyway, that's just a couple of random thoughts. No doubt it's only when you
    implement such a cut-down language that you'd find out what the pitfalls are
    in practice :-(

    Regards,

    Brian.
    Brian Candler, Feb 5, 2007
    #14
  15. "Patrick Fernie" <> wrote/schrieb <>:

    > I found the following:
    > http://innig.net/software/ruby/closures-in-ruby.rb to be an
    > interesting read on the different flavors of closures in ruby;


    Very interesting, indeed. BTW, in article
    <> I did the same, i.e. defining a
    data structure containing *all* of the Fibonacci numbers:
    s = Stream.delay {
    Stream.cons(0, Stream.delay {
    Stream.cons(1, Stream.map(lambda{|x,y| x+y}, s, s.cdr))})}
    (It uses methods posted in article <>.)

    Regards
    Thomas
    Thomas Hafner, Feb 5, 2007
    #15
  16. Minkoo Seo

    Guest

    Hi --

    On Tue, 6 Feb 2007, Brian Candler wrote:

    > On Tue, Feb 06, 2007 at 04:00:44AM +0900, Pit Capitain wrote:
    >> schrieb:
    >>> (... useful infos about procs ...)

    >>
    >> Very interesting! Thanks for sharing your experiments.

    >
    > Yes, it's interesting to be reminded of all this again.
    >
    > Much as I love Ruby, I hate having multiple versions of essentially the same
    > concept which differ in subtle ways. I would find it more aesthetically
    > pleasing if a tiny Ruby core could bootstrap the whole language - and it
    > might make it easier to port (and understand).
    >
    > Now, I wonder why you couldn't approach this problem from the other
    > direction: instead of having two or more different types of lambda, which
    > handle 'return' semantics differently, have a single type of lambda and two
    > different return statements. For example:
    >
    > return val # return from enclosing method
    > result val # return from this block only
    >
    > Internally, you could implement 'return' semantics using catch and throw:
    >
    > def foo
    > ... some code
    > end
    >
    > # could be implemented as something like this:
    >
    > define_method:)foo) do
    > catch:)return) do
    > ... some code
    > end
    > end
    >
    > module Kernel
    > def return(rc=nil)
    > throw:)return, rc)
    > end
    > end
    >
    > The other difference concerns arity. I don't see why argument checking can't
    > be done everywhere, as long as you have the option of explicitly allowing
    > variable arguments where you want them:
    >
    > p1 = Proc.new { |x=nil,y=nil| ... } # accept 2 or fewer args
    > p2 = Proc.new { |x, y, *z| ... } # accept 2 or more args
    > p3 = Proc.new { |*x| ... } # no more single-arg special case!
    >
    > That is, use the same argument list handling for a 'def' method definition,
    > a block, and a Proc/proc/lambda.


    I think the reason for there not being default arguments in code
    blocks is the ambiguity of the pipe character:

    {| x=1 | 2 | 3 } # {(x=1) 2 | 3 } or {(x=1|2) 3 } ?

    Dave Thomas suggested something at RubyConf 2005 along the lines of:

    def m(a,b,c) # method
    end

    def (a,b,c) # anonymous function
    end

    I'm not sure what happened to that; I haven't seen it mentioned much
    in discussions of this stuff.


    David

    --
    Q. What is THE Ruby book for Rails developers?
    A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf)
    Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
    A. Ruby Power and Light, LLC (http://www.rubypal.com)
    , Feb 5, 2007
    #16
  17. Minkoo Seo

    Guest

    On Feb 5, 2007, at 4:28 PM, Brian Candler wrote:
    > Now, I wonder why you couldn't approach this problem from the other
    > direction: instead of having two or more different types of lambda,
    > which
    > handle 'return' semantics differently, have a single type of lambda
    > and two
    > different return statements. For example:
    >
    > return val # return from enclosing method
    > result val # return from this block only


    I think Ruby already has this via 'break'. Also, the default behavior
    of returning the last expression evaluated in a block is an implicit
    'break' in Proc.new procs.

    Sometimes you want a Proc to behave like the body of a method (the
    lambda flavor of procs) and sometimes you want it to behave like the
    body of
    an iterator (the Proc.new flavor of procs).

    > That is, use the same argument list handling for a 'def' method
    > definition,
    > a block, and a Proc/proc/lambda.


    That seems to be a goal of the 1.9/2.0 line of Ruby as part of
    'cleaning up'
    the semantics of block argument scope.

    I wish there was some better terminology for the two different types
    of procs (rather than 'lambda type' and 'Proc.new type'). I think
    Pickaxe
    uses 'raw proc' but I can never remember which type of proc is being
    referenced by that phrase.


    Gary Wright
    , Feb 5, 2007
    #17
  18. On Tue, Feb 06, 2007 at 07:33:20AM +0900, wrote:
    > > p1 = Proc.new { |x=nil,y=nil| ... } # accept 2 or fewer args
    > > p2 = Proc.new { |x, y, *z| ... } # accept 2 or more args
    > > p3 = Proc.new { |*x| ... } # no more single-arg special case!
    > >
    > >That is, use the same argument list handling for a 'def' method
    > >definition,
    > >a block, and a Proc/proc/lambda.

    >
    > I think the reason for there not being default arguments in code
    > blocks is the ambiguity of the pipe character:
    >
    > {| x=1 | 2 | 3 } # {(x=1) 2 | 3 } or {(x=1|2) 3 } ?
    >
    > Dave Thomas suggested something at RubyConf 2005 along the lines of:
    >
    > def m(a,b,c) # method
    > end
    >
    > def (a,b,c) # anonymous function
    > end
    >
    > I'm not sure what happened to that; I haven't seen it mentioned much
    > in discussions of this stuff.


    But make this into block syntax and you still have potential ambiguities:

    3.times { (i=nil) puts i }

    3.times do (i=nil)
    puts i
    end

    (i=nil) is a valid expression/statement in its own right, so you'd need some
    more lexical rules to disambiguate this from an argument list. I'd hate more
    whitespace-sensitive rules to be added, e.g.

    {(i) ... } # block args
    { (i) ... } # expression :-(

    Perhaps you use parentheses, and if a block starts with an open-parenthesis
    then it's always an argument list. If you want it otherwise, you have to
    explicitly avoid it:

    3.times { nil, (a=b, c=d) }

    It seems the rest of the ASCII set has been used already; e.g.
    angle-brackets would have the same problem.

    3.times { < i = j > 4 > puts i }

    Incidentally, I do see a reason for not doing full argument-checking in
    blocks: there are methods which pass block arguments which it's convenient
    for the block to ignore if it doesn't want them.

    3.times { puts "hello" }
    3.times { |x| puts "hello #{x}" }

    You could get around this by:

    (a) having different methods which pass or do not pass arguments:

    3.times { puts "hello" }
    3.times_i { |x| puts "hello #{x}" }

    (b) making such arguments explicitly ignorable at the caller side, which I
    think I prefer. At worst:

    class Integer
    def times(&blk)
    if blk.arity == 1
    ... loop, yield with index
    else
    ... loop, yield without index
    end
    end
    end

    Regards,

    Brian.
    Brian Candler, Feb 6, 2007
    #18
  19. On Tue, Feb 06, 2007 at 08:20:49AM +0900, wrote:
    > Sometimes you want a Proc to behave like the body of a method (the
    > lambda flavor of procs) and sometimes you want it to behave like the
    > body of
    > an iterator (the Proc.new flavor of procs).


    What are those different behaviours?
    1. Handling of 'return'
    2. Handling of arity
    3. Anything else?

    If it's just (1) and (2), then I just wonder if you could get the different
    behaviours using different keywords, so that there's only a single
    underlying proc-like object.

    As another idea, if we really need different behaviours, it could be an
    explicit attribute of the object:

    a = Proc.new:)iterator) { ... }
    b = Proc.new:)method_body) { ... }

    def proc(opt = :iterator)
    Proc.new(opt)
    end

    def lambda(opt = :method_body)
    Proc.new(opt)
    end

    # or is it the other way round??

    Regards,

    Brian.
    Brian Candler, Feb 6, 2007
    #19
  20. > (b) making such arguments explicitly ignorable at the caller side, which I
    > think I prefer. At worst:
    >
    > class Integer
    > def times(&blk)
    > if blk.arity == 1
    > ... loop, yield with index
    > else
    > ... loop, yield without index
    > end
    > end
    > end


    or have a "yieldopt" statement, which does something like

    def yieldopt(*a, &blk)
    blk.arity == 0 ? blk.call() : blk.call(*a)
    end

    so the caller is saying that the callee can either have all of the
    arguments, or ignore them all.

    I can't think of any useful cases where an iterator calls a block with (say)
    three arguments, but the block only accepts two and is happy for the third
    to be silently ignored.

    If the block only accepts one argument, but yield passes more than one, this
    is currently treated as another special case:

    irb(main):001:0> h = {1=>"one", 2=>"two", 3=>"three"}
    => {1=>"one", 2=>"two", 3=>"three"}
    irb(main):002:0> h.each { |k| puts k.inspect }
    [1, "one"]
    [2, "two"]
    [3, "three"]
    => {1=>"one", 2=>"two", 3=>"three"}
    irb(main):003:0>

    This could be eliminated if people wrote

    h.each { |*k| .. I want an array .. }
    h.each { |k,v| .. I want separate items .. }

    which I think makes the intention very clear. Maybe this is already
    considered for 1.9

    Cheers,

    Brian.
    Brian Candler, Feb 6, 2007
    #20
    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. David Lozzi
    Replies:
    3
    Views:
    1,932
    David Lozzi
    Jun 1, 2005
  2. Roman Suzi
    Replies:
    13
    Views:
    607
    Bengt Richter
    Jan 7, 2005
  3. Eric Mahurin
    Replies:
    25
    Views:
    373
    Trans
    Oct 11, 2005
  4. Steve Dogers

    lambda vs non-lambda proc

    Steve Dogers, Mar 30, 2009, in forum: Ruby
    Replies:
    1
    Views:
    177
    Sean O'Halpin
    Mar 30, 2009
  5. Haochen Xie
    Replies:
    4
    Views:
    242
    Haochen Xie
    Mar 17, 2013
Loading...

Share This Page