Having trouble distinguishing where the block is/if this function has a block - ruby

I am under the impression that when you write a function, the block is what goes in between do and end.
(1..5).each do |i|
puts 2 ** i
end
So in the function above, would the block part consist of the following?
|i| puts 2 ** i

You are playing with words. It is a matter of definition. Usually, the block includes the do and end. The whole:
do |i|
puts 2 ** i
end
is the block. But since a block is not an object in Ruby (unlike proc), it does not make much difference whichever you call a block.

Related

Can I break a loop using a toplevel break within a Proc in Ruby?

Questions
Why does break within a proc jump out of three loops all the way to puts 8? It's pretty counter-intuitive.
Is there a way to make it break out of the innermost loop, that is, to puts 6?
Code
3.times do
puts "outer loop"
break_proc = proc { break }
puts 1
loop do
puts 2
loop do
puts 3
loop do
puts 4
break_proc.call
puts 5
end
puts 6
end
puts 7
end
puts 8
end
outer loop
1
2
3
4
8
outer loop
1
2
3
4
8
outer loop
1
2
3
4
8
TL;DR
The behavior you're seeing is a result of attempting to treat a Proc object like a snippet of code passed to Kernel#eval, or thinking that a toplevel break inside a Proc is the same as a bare break keyword inside a loop. An explanation for the behavior is provided, but the real solution is to avoid doing what you're doing.
Procs Carry Context
Why does break within a proc jump out of three loops all the way to puts 8?
This happens because a Proc object contains a Binding to the context in which it's created, and the break keyword is exiting the iterator block and returning to its calling context. Specifically, you're creating the Proc in the top-level loop here:
3.times do
puts "outer loop"
break_proc = proc { break }
One could be forgiven for thinking that Ruby's break just exits a loop wherever its called, but its behavior is more complex than that, especially when you're trying to do something odd like a toplevel break inside a Proc. Your use case for break is even covered in The Ruby Programming Language, where it says:
[A break] causes the block to return to its iterator and the iterator to return to the method that invoked it. Because procs work like blocks, we expect break to do the same thing in a proc. We can’t easily test this, however. When we create a proc with Proc.new, Proc.new is the iterator that break would return from. And by the time we can invoke the proc object, the iterator has already returned. So it never makes sense to have a top-level break statement in a proc created with Proc.new[.]
— David Flanagan and Yukihiro Matsumoto. The Ruby Programming Language (Kindle Locations 8185-8192). O'Reilly Media.
When you create deeply nested loops and then complicate that with objects that carry runtime bindings, the results aren't always what you expect. The behavior you're seeing is not a bug, although it may be a misfeature in some cases. You'd have to ask the language designers why it behaves this way if you want a reason for the implementation semantics rather an explanation for the behavior you're seeing.
Breaking Loops
Is there a way to make it break out of the innermost loop, that is, to puts 6?
Yes, but not with break inside a Proc. Replacing the Proc#call with an actual inline break statement does what you expect and is the "simplest thing that could possibly work," but you can also use throw and catch if you want to adjust your nesting level. For example:
3.times do
puts "outer loop"
break_proc = proc { throw :up }
puts 1
loop do
puts 2
loop do
puts 3
catch :up do
loop do
puts 4
break_proc.call
puts 5
end
end
puts 6
end
puts 7
end
puts 8
end
This will yield:
outer loop
1
2
3
4
6
3
4
6
3
4
6
and endlessly loop inside the third loop where you puts 3.
So, this will do what you're asking, but may or may not do what you want. If it helps, great! If not, you may want to ask a separate question with some real data and behavior if you want to find a more elegant data structure or decompose your task into a set of collaborating objects.
Because of context binding break escapes from the loop defined at the same level:
3.times do
puts 1
loop do
break_proc = proc {|b| break }
puts 2
loop do
puts 3
loop do
puts 4
break_proc.call
puts 5
end
puts 6
end
puts 7
raise 'break other loops'
end
puts 8
end
=>
1
2
3
4
7
1.rb:18:in `block (2 levels) in <main>': break other loops (RuntimeError)
Easiest way to break from your construction - return a boolean from the block indicating if loop should be terminated (... = proc{ true }/break if break_proc.call), or use throw:
3.times do
puts "outer loop"
break_proc = proc {|b| throw :breakit }
puts 1
loop do
puts 2
loop do
puts 3
catch :breakit do
loop do
puts 4
break_proc.call
puts 5
end
end
puts 6
raise 'break the other loops...'
end
puts 7
end
puts 8
end
If you want to break till 6 block you could do this
3.times do
puts "outer loop"
break_proc = proc { break }
puts 1
loop do
puts 2
loop do
puts 3
loop do
puts 4
break
puts 5
end
puts 6
end
puts 7
end
puts 8
end
Ruby Folks:
To use proc & lambda in Ruby, kindly consider the following info to use them error-free and use break or return with proper understanding:
Lambda and non-lambda semantics:
-------------------------------
Procs are coming in two flavors: lambda and non-lambda (regular procs). Differences are:
In lambdas, return and break means exit from this lambda;
In non-lambda procs, return means exit from embracing method (and will throw LocalJumpError if invoked outside the method);
In non-lambda procs, break means exit from the method for which the block is given. (and will throw LocalJumpError if invoked after the method returns);
In lambdas, arguments are treated in the same way as in methods: strict, with ArgumentError for mismatching argument number, and no additional argument processing;
Regular procs accept arguments more generously: missing arguments are filled with nil, single Array arguments are deconstructed if the proc has multiple arguments, and there is no error raised on extra arguments.
Ref: https://ruby-doc.org/core-3.0.2/Proc.html

What do c == self and yield do?

Can you help me understand what this class does and how we can make use of it?
class Integer
def myt
c=0
until c == self
yield(c)
c+=1
end
self
end
end
Thank you.
x = Integer.new
x.myt
I tried to test it but it doesn't work. Error is: "no block given (yield)"
Also, in my book it says to test like this:
5.myt (|| puts "I'm on iteration #{i}! "} but it also gives an error - not sure why or what this line of code means.
allonhadaya and PNY did a good job explaining the purpose (enumeration) of the myt method.
Regarding your two questions mentioned in the title:
1.) What does 'c == self' do?
The '==' operator checks whether the integer c and Integer object you instantiate, are equal in value. If they are, the expression evaluates to true.
2.) What does 'yield' do?
The 'yield' statement passes control from the current method to a block which has been provided to the method. Blocks are ruby's implementation of a closure which, simple put, means that a method can be "extended" by calling the method with a block of additional code as long as the method supports a block (ie. incorporates yield statements)
The method seems to be a times implementation.
Basically 5.times { |i| puts i } and 5.myt { |i| puts i } will do exactly the same thing.
First, it sets a counter to 0, c = 0. Then you have a conditional where it checks if c is equal with self which will always be the integer attached to the method myt. It, then yields the counter and return self when is done.
Looks like it enumerates the values between zero inclusively and self exclusively.
allon#ahadaya:~$ irb
irb(main):001:0> class Integer
irb(main):002:1> def myt
irb(main):003:2> c=0
irb(main):004:2> until c == self
irb(main):005:3> yield(c)
irb(main):006:3> c+=1
irb(main):007:3> end
irb(main):008:2> self
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0> 5.myt { |i| puts i }
0
1
2
3
4
=> 5
irb(main):012:0>
Using the example your book gave --
5.myt {|i| puts "I'm on iteration #{i}! "}
#You were missing an object in the pipes and a curly bracket before the pipes (not parentheses)
Allows you to see the internal workings of your myt method. Initializing variable c with a value of 0 the method executes an until look until the condition "c == self" is satisfied. Self references the object, here 5, which the method is acting on.
Therefore ...
def myt
until c == 5 #Until this is true
yield(c) #Do this .. here yield will do whatever the block specified
c+=1 #Increment on each iteration the value of variable c by 1
end #closing the until loop
self #return self
end
The yield within the method passes control from your method to the parameter, a block, back to the method.
Yield therefore allows you to build methods which can have similar patterns but with block you customize it to do your particular need.
If instead of putting each number maybe all you want to do is put the odd integers between 0 and the integer you call the method on --
5.myt {|i| puts i if i.odd?} # returns I am odd: 1 and I am odd: 3
I would suggest that you write your own blocks here to see how yield works and how you can keep the same method but pass in different blocks and create different method outputs!

Ruby yield example explanation?

I'm doing a SaaS course with Ruby. On an exercise, I'm asked to calculate the cartesian product of two sequences by using iterators, blocks and yield.
I ended up with this, by pure guess-and-error, and it seems to work. But I'm not sure about how. I seem to understand the basic blocks and yield usage, but this? Not at all.
class CartProd
include Enumerable
def initialize(a,b)
#a = a
#b = b
end
def each
#a.each{|ae|
#b.each{|be|
yield [ae,be]
}
}
end
end
Some explanation for a noob like me, please?
(PS: I changed the required class name to CartProd so people doing the course can't find the response by googling it so easily)
Let's build this up step-by-step. We will simplify things a bit by taking it out of the class context.
For this example it is intuitive to think of an iterator as being a more-powerful replacement for a traditional for-loop.
So first here's a for-loop version:
seq1 = (0..2)
seq2 = (0..2)
for x in seq1
for y in seq2
p [x,y] # shorthand for puts [x, y].inspect
end
end
Now let's replace that with more Ruby-idiomatic iterator style, explicitly supplying blocks to be executed (i.e., the do...end blocks):
seq1.each do |x|
seq2.each do |y|
p [x,y]
end
end
So far, so good, you've printed out your cartesian product. Now your assignment asks you to use yield as well. The point of yield is to "yield execution", i.e., pass control to another block of code temporarily (optionally passing one or more arguments).
So, although it's not really necessary for this toy example, instead of directly printing the value like above, you can yield the value, and let the caller supply a block that accepts that value and prints it instead.
That could look like this:
def prod(seq1, seq2)
seq1.each do |x|
seq2.each do |y|
yield [x,y]
end
end
end
Callable like this:
prod (1..2), (1..2) do |prod| p prod end
The yield supplies the product for each run of the inner loop, and the yielded value is printed by the block supplied by the caller.
What exactly do you not understand here? You've made an iterator that yields all possible pairs of elements. If you pass CartProd#each a block, it will be executed a.length*b.length times. It's like having two different for cycles folded one into another in any other programming language.
yield simply passes (yields) control to a block of code that has been passed in as part of the method call. The values after the yield keyword are passed into the block as arguments. Once the block has finished execution it passes back control.
So, in your example you could call #each like this:
CartProd.new([1, 2], [3, 4]).each do |pair|
# control is yielded to this block
p pair
# control is returned at end of block
end
This would output each pair of values.

Accessing a passed block in Ruby

I have a method that accepts a block, lets call it outer. It in turn calls a method that accepts another block, call it inner.
What I would like to have happen is for outer to call inner, passing it a new block which calls the first block.
Here's a concrete example:
class Array
def delete_if_index
self.each_with_index { |element, i| ** A function that removes the element from the array if the block passed to delete_if_index is true }
end
end
['a','b','c','d'].delete_if_index { |i| i.even? }
=> ['b','d']
the block passed to delete_if_index is called by the block passed to each_with_index.
Is this possible in Ruby, and, more broadly, how much access do we have to the block within the function that receives it?
You can wrap a block in another block:
def outer(&block)
if some_condition_is_true
wrapper = lambda {
p 'Do something crazy in this wrapper'
block.call # original block
}
inner(&wrapper)
else
inner(&passed_block)
end
end
def inner(&block)
p 'inner called'
yield
end
outer do
p 'inside block'
sleep 1
end
I'd say opening up an existing block and changing its contents is Doing it WrongTM, maybe continuation-passing would help here? I'd also be wary of passing around blocks with side-effects; I try and keep lambdas deterministic and have actions like deleting stuff in the method body. In a complex application this will likely make debugging a lot easier.
Maybe the example is poorly chosen, but your concrete example is the same as:
[1,2,3,4].reject &:even?
Opening up and modifying a block strikes me as code smell. It'd be difficult to write it in a way that makes the side effects obvious.
Given your example, I think a combination of higher order functions will do what you're looking to solve.
Update: It's not the same, as pointed out in the comments. [1,2,3,4].reject(&:even?) looks at the contents, not the index (and returns [1,3], not [2,4] as it would in the question). The one below is equivalent to the original example, but isn't vary pretty.
[1,2,3,4].each_with_index.reject {|element, index| index.even? }.map(&:first)
So here's a solution to my own question. The passed in block is implicitly converted into a proc which can be received with the & parameter syntax. The proc then exists inside the closure of any nested block, as it is assigned to a local variable in scope, and can be called by it:
class Array
def delete_if_index(&proc)
ary = []
self.each_with_index { |a, i| ary << self[i] unless proc.call(i) }
ary
end
end
[0,1,2,3,4,5,6,7,8,9,10].delete_if_index {|index| index.even?}
=> [1, 3, 5, 7, 9]
Here the block is converted into a proc, and assigned to the variable proc, which is then available within the block passed to each_with_index.

Does begin . . . end while denote a 'block'?

temp = 98.3
begin
print "Your temperature is " + temp.to_s + " Fahrenheit. "
puts "I think you're okay."
temp += 0.1
end while temp < 98.6
In the above example, is everything between begin and end a block?
I'm still confused what a block is.
If you can't call it a block, what would you call that chunk of code between begin and end? Is it ok to call it a chunk?
Block has a special meaning in Ruby. According to Matz, Ruby's creator, you can look at a block as a nameless function - typically something that can be yielded into, and which may also take parameters.
You may see the following kind of disamiguation when describing Ruby syntax:
begin...end (what is called block in other languages) may sometimes be referred to simply as what it is, i.e. an expression (which may in turn contain other expressions - an expression is simply something that has a return value) in Ruby. Some references will still call it a begin/end block, or a code block, adding somewhat to the confusion
do...end or {...} will always be referred to as a block in Ruby
For examples, peruse the the Ruby syntax man page, e.g.
begin expression end
expression while expression
loop block
For further reading, see:
Programming Ruby
Ruby (from other languages)
Much, much more documentation
begin/end are strictly control flow, not blocks.
begin
puts "hi"
end
# => "hi"
The code runs immediately. If it was a block, it would have to been called somehow in order for the code in it to run, as in this example:
def a_method; end
a_method { puts "hi" }
# nothing..
def a_method
yield
end
a_method { puts "Hi!" }
# => "Hi!"

Resources