# Difference between proc.call and yield?

Consider the following contrived examples:

def func1()
ret = []
t = nil
5.times do |i|
t = yield i
ret << t
end
ret
end

func1 { |b| b + 10 } # [ 10, 11, 12, 13, 14 ]

def func2(&block)
ret = []
t = nil
5.times do |i|
t = block.call(i)
ret << t
end
ret
end

func2 { |b| b + 10 } # [ 10, 11, 12, 13, 14 ]

Is this just TMTOWTDI, or is there a difference?

Dan

···

/^Dan Debertin\$/
airboss@nodewarrior.org
www.nodewarrior.org
ignorami: n:
The art of folding problem users into representational shapes.

Consider the following contrived examples:

But I hate contrived examples!

def func1()
ret =
t = nil
5.times do |i|
t = yield i
ret << t
end
ret
end

func1 { |b| b + 10 } # [ 10, 11, 12, 13, 14 ]

def func2(&block)
ret =
t = nil
5.times do |i|
t = block.call(i)
ret << t
end
ret
end

func2 { |b| b + 10 } # [ 10, 11, 12, 13, 14 ]

Is this just TMTOWTDI, or is there a difference?

AFAIK, TMTOWTDI.

GS

···

----- Original Message -----
From: “Dan Debertin” airboss@nodewarrior.org

Dan

Dan Debertin airboss@nodewarrior.org writes:

``````  t = yield i
``````
``````  t = block.call(i)
``````

Is this just TMTOWTDI, or is there a difference?

There’s an internal difference, in that ‘yield’ does not create a proc
object, while (&block) does. This might make a performance
difference. Let’s find out…

`````` require "benchmark"
include Benchmark

N = 500000

def block(&b)
N.times { b.call(1) }
end

def no_block
N.times { yield 1 }
end

bm(10) do |test|

test.report("block")    { block {|i|}    }
test.report("no block") { no_block {|i|} }
test.report("block")    { block {|i|}    }
test.report("no block") { no_block {|i|} }

end

dave[~/tmp 22:58:57] ruby t.rb
user     system      total        real
block       3.430000   0.000000   3.430000 (  3.450126)
no block    1.320000   0.000000   1.320000 (  1.383497)
block       3.450000   0.000000   3.450000 (  3.450232)
no block    1.330000   0.000000   1.330000 (  1.329939)
``````

Yup - there’s a difference

Cheers

Dave

The parameter passing is also different, quoting Matz (from ruby-talk
46413):

First, you have to learn several tips:

(a) block parameter |v| means takes everything in a single variable,
which is better described as |*v|.

(b) “call” requires exact number of required argument, whereas
“yield” fills nil for fewer arguments and ignores too much
arguments.

HTH,

– Shanko

“Dan Debertin” airboss@nodewarrior.org wrote in message
news:87ptwitcpq.wl@discus.nodewarrior.org

···

Consider the following contrived examples:

def func1()
ret =
t = nil
5.times do |i|
t = yield i
ret << t
end
ret
end

func1 { |b| b + 10 } # [ 10, 11, 12, 13, 14 ]

def func2(&block)
ret =
t = nil
5.times do |i|
t = block.call(i)
ret << t
end
ret
end

func2 { |b| b + 10 } # [ 10, 11, 12, 13, 14 ]

Is this just TMTOWTDI, or is there a difference?

## Dan

/^Dan Debertin\$/
airboss@nodewarrior.org
www.nodewarrior.org
ignorami: n:
The art of folding problem users into representational shapes.

“Dave Thomas” Dave@PragmaticProgrammer.com wrote in message
news:m2vg6anngv.fsf@zip.local.thomases.com

Dan Debertin airboss@nodewarrior.org writes:

``````  t = yield i
``````
``````  t = block.call(i)
``````

Is this just TMTOWTDI, or is there a difference?

There’s an internal difference, in that ‘yield’ does not create a proc
object, while (&block) does. This might make a performance
difference. Let’s find out…

In recursive situations it’s sort of advantageous to use the block
form since it prevents the creation of unnecessary blocks.
Furthermore, it’s more elegant …

···

\$ cat stack.rb
class Stack
NullStack = new

def initialize()
@top = self
@rest = NullStack
end

def each_mixed(&b)
yield @data
@rest.each_mixed(&b)
end

def each_block(&b)
b.call(@data)
@rest.each_block(&b)
end

def each_yield
yield @data
@rest.each_yield {|r| yield r }
end

def push(data)
@data = data
@rest = clone
end

def pop()
unless empty?
data = @data
@rest = @rest.rest
data
else
nil
end
end

def empty?; NullStack.equal?(@rest) end
protected

class << NullStack
protected
def each_mixed; end
def each_block; end
def each_yield; end
# undef all unapplicable methods
undef :pop
# etc.
end
end

stack = Stack.new
1000.times {|i| stack.push(i) }

## require ‘benchmark’ Benchmark::bmbm {|x| x.report(“each_mixed”) { stack.each_mixed {|i| ii + 3iii } } x.report(“each_block”) { stack.each_block {|i| ii + 3iii } } x.report(“each_yield”) { stack.each_yield {|i| ii + 3iii } } }

\$ ruby stack.rb
Rehearsal ----------------------------------------------
each_mixed 0.170000 0.020000 0.190000 ( 0.184000)
each_block 0.080000 0.000000 0.080000 ( 0.089000)
each_yield 14.761000 0.010000 14.771000 ( 15.143000)
------------------------------------ total: 15.041000sec

``````             user     system      total        real
``````

## each_mixed 0.080000 0.000000 0.080000 ( 0.083000) each_block 0.080000 0.000000 0.080000 ( 0.087000) each_yield 12.929000 0.000000 12.929000 ( 13.101000)

/Christoph

"Christoph"wrote

def push(data)
@data = data
@rest = clone
end

Sigh, …

``````def push(data)
@rest = clone
@data = data
end
``````

/Christoph