I'm trying to understand when one should code blocks implicitly or explicitly. Given the following code blocks:
Implicit
def two_times_implicit
return "No block" unless block_given?
yield
yield
end
puts two_times_implicit { print "Hello "}
puts two_times_implicit
Explicit
def two_times_explicit (&i_am_a_block)
return "No block" if i_am_a_block.nil?
i_am_a_block.call
i_am_a_block.call
end
puts two_times_explicit { puts "Hello"}
puts two_times_explicit
Is it preferable to code using one over the other? Is there a standard practice and are there instances where one would work better or differently than the other and where one would not work at all?
Receiving a block via & creates a new proc object out of the block, so from the point of view of efficiency, it is better not to use it. However, using & generally makes it easier to define methods that may or may not take a block, and using &, you can also handle blocks together with arguments, so it is preferred by many.
Actually, according to one very interesting read, second variant is 439% slower (related thread on HackerNews).
TL;DR: Creating and passing a block via yield is a highly optimized common case in MRI, which is handled by dedicated C function in interpreter, while passing &block is implemented differently and has a big overhead of creating new environment and creating Proc itself on every call.
Summing up, use &block only if you need passing it further (for example, to a next function), or manipulate it somehow in other way. Otherwise, use yield, since it's way faster.
Related
def foo(a)
# some computation
bar(a, b)
end
def bar(a,b)
# some computation
baz(a, b, c)
end
def baz(a, b ,c)
print a
end
How to avoid passing same parameter (a) to all methods? One way is to make parameter a as an instance variable. What is the right way to do this?
There is no single solution which works in every case, and often, passing the parameters explicitly is simply the best choice, especially when it comes to debugging.
You can use instance variables, but I would not introduce a new instance variable for the sole reason not to avoid passing it down the call chain. It should have its own value in addition.
One approach which I can see often in projects, is to us a single parameter hash, where the new parameters are added:
def foo(a)
....
bar({a:a, b:b})
end
def bar(par)
....
par[:c] = c
end
def baz(par)
par[:a]+par[:b]+par[:c]
end
This is not without drawbacks either. If you, for instance, forget to "add" a necessary parameter, this will either yield wrong results or throw an exception (depending on how to used them), while forgetting them explicitly via the parameter list, would be found at compile time already.
I would make the decisiion depending on the length of the parameter lists involved. If the number of parameters to a methods is larger than 5, I would start thinking, whether a different design might be more appropriate.
Answering the question stated: yes, ruby is a stateful OO language, having mutable everything. So in ruby one might introduce instance variables:
class MyClass
def foo(a)
#a = a
# some computation
bar(b)
end
def bar(b)
#b = b
# some computation
baz(c)
end
def baz(c)
print [#a, #b, c].inspect
end
end
In the real life, the best practice would be to avoid using instance variables wherever possible, and pass everything across methods. That might save you days of debugging in the future.
I understand that we use the ampersand in front of the method's argument in order to avoid using yield, which would output an error if it doesn't find a block in its way.
However, I've seen that sometimes we use the & in front of the argumenent when we call a method, in order to transform the proc back into a block. It eventually happens that there are 2 ampersands, one for turning blocks into procs, and the second for the opposite.
How's that?! When do we need to put the ampersand to getting back a block from a proc, and why?
I hope I've been clear, beacause not being english mother tongue could make harsh to pose difficult questions for me.
Example
I took this example from the slides of CodeSchool, which can be found on http://courseware.codeschool.com/ruby_bits_2/ruby_bits_2_level_1.pdf.
class Timeline
attr_accessor :tweets
def each(&block)
tweets.each(&block)
end
end
I understand that we use the ampersand in front of the method's
argument in order to avoid using yield, which would output an error if
it doesn't find a block in its way.
Your understanding is wrong.
You use &block as the last argument to capture the block into a Proc, in particular to store it and use it later on. When calling a method, &block does the reverse, i.e. specifies that the block corresponds to the given block. This is the same idea as def foo(*args) and foo(*args).
The example you gave is basically equivalent to:
def each
tweets.each{|t| yield y}
end
As Yehuda Katz explains at the end of this talk, you should think of a "block" as a Proc with a special argument position and a dedicated syntax to specify it.
It's common to use them together. This is the case because blocks can't be used as parameters, while procs can. So if you need to use the block as a parameter within the method's body, you must turn it into a proc.
Within that method, you might want to pass the proc to another method that only accepts a block, so you have to do the conversion once again.
For example:
def each(&block) # block to proc
posts.each(&block) # proc to block
end
I hope I am not repeating anyone here, but I have been searching google and here and not coming up with anything. This question is really more a matter of "sexifying" my code.
What I am specifically trying to do is this:
Dir.new('some_directory').each do |file|
# is there a way to refer to the string 'some_directory' via a method or variable?
end
Thanks!
Not in general; it's totally up to the method itself what arguments the block gets called with, and by the time each has been called (which calls your block), the fact that the string 'some_directory' was passed to Dir.new has been long forgotten, i.e. they're quite separate things.
You can do something like this, though:
Dir.new(my_dir = 'some_directory').each do |file|
puts "#{my_dir} contains #{file}"
end
The reason it won't work is that new and each are two different methods so they don't have access to each others' parameters. To 'sexify' your code, you could consider creating a new method to contain the two method calls and pass the repeated parameter to that:
def do_something(dir)
Dir.new(dir).each do |file|
# use dir in some way
end
end
The fact that creating a new method has such a low overhead means it's entirely reasonable to create one for as small a chunk of code as this - and is one of the many reasons that make Ruby such a pleasure of a language to work with.
Just break it out into a variable. Ruby blocks are closures so they will have access -
dir = 'some_directory'
Dir.new(dir).each do |file|
# use dir here as expected.
end
As is stated in the title, I was curious to know why Ruby decided to go away from classical for loops and instead use the array.each do ...
I personally find it a little less readable, but that's just my personal opinion. No need to argue about that. On the other hand, I suppose they designed it that way on purpose, there should be a good reason behind.
So, what are the advantages of putting loops that way? What is the "raison d'etre" of this design decision?
This design decision is a perfect example of how Ruby combines the object oriented and functional programming paradigms. It is a very powerful feature that can produce simple readable code.
It helps to understand what is going on. When you run:
array.each do |el|
#some code
end
you are calling the each method of the array object, which, if you believe the variable name, is an instance of the Array class. You are passing in a block of code to this method (a block is equivalent to a function). The method can then evaluate this block and pass in arguments either by using block.call(args) or yield args. each simply iterates through the array and for each element it calls the block you passed in with that element as the argument.
If each was the only method to use blocks, this wouldn't be that useful but many other methods and you can even create your own. Arrays, for example have a few iterator methods including map, which does the same as each but returns a new array containing the return values of the block and select which returns a new array that only contains the elements of the old array for which the block returns a true value. These sorts of things would be tedious to do using traditional looping methods.
Here's an example of how you can create your own method with a block. Let's create an every method that acts a bit like map but only for every n items in the array.
class Array #extending the built in Array class
def every n, &block #&block causes the block that is passed in to be stored in the 'block' variable. If no block is passed in, block is set to nil
i = 0
arr = []
while i < self.length
arr << ( block.nil? ? self[i] : block.call(self[i]) )#use the plain value if no block is given
i += n
end
arr
end
end
This code would allow us to run the following:
[1,2,3,4,5,6,7,8].every(2) #= [1,3,5,7] #called without a block
[1,2,3,4,5,6,7,8,9,10].every(3) {|el| el + 1 } #= [2,5,8,11] #called with a block
Blocks allow for expressive syntax (often called internal DSLs), for example, the Sinatra web microframework.
Sinatra uses methods with blocks to succinctly define http interaction.
eg.
get '/account/:account' do |account|
#code to serve of a page for this account
end
This sort of simplicity would be hard to achieve without Ruby's blocks.
I hope this has allowed you to see how powerful this language feature is.
I think it was mostly because Matz was interested in exploring what a fully object oriented scripting language would look like when he built it; this feature is based heavily on the CLU programming language's iterators.
It has turned out to provide some interesting benefits; a class that provides an each method can 'mix in' the Enumerable module to provide a huge variety of pre-made iteration routines to clients, which reduces the amount of tedious boiler-plate array/list/hash/etc iteration code that must be written. (Ever see java 4 and earlier iterators?)
I think you are kind of biased when you ask that question. Another might ask "why were C for loops designed that way?". Think about it - why would I need to introduce counter variable if I only want to iterate through array's elements? Say, compare these two (both in pseudocode):
for (i = 0; i < len(array); i++) {
elem = array[i];
println(elem);
}
and
for (elem in array) {
println(elem);
}
Why would the first feel more natural than the second, except for historical (almost sociological) reasons?
And Ruby, highly object-oriented as is, takes this even further, making it an array method:
array.each do |elem|
puts elem
end
By making that decision, Matz just made the language lighter for superfluous syntax construct (foreach loop), delegating its use to ordinary methods and blocks (closures). I appreciate Ruby the most just for this very reason - being really rational and economical with language features, but retaining expressiveness.
I know, I know, we have for in Ruby, but most of the people consider it unneccessary.
The do ... end blocks (or { ... }) form a so-called block (almost a closure, IIRC). Think of a block as an anonymous method, that you can pass as argument to another method. Blocks are used a lot in Ruby, and thus this form of iteration is natural for it: the do ... end block is passed as an argument to the method each. Now you can write various variations to each, for example to iterate in reverse or whatnot.
There's also the syntactic sugar form:
for element in array
# Do stuff
end
Blocks are also used for example to filter an array:
array = (1..10).to_a
even = array.select do |element|
element % 2 == 0
end
# "even" now contains [2, 4, 6, 8, 10]
I think it's because it emphasizes the "everything is an object" philosophy behind Ruby: the each method is called on the object.
Then switching to another iterator is much smoother than changing the logic of, for example, a for loop.
Ruby was designed to be expressive, to read as if it was being spoken... Then I think it just evolved from there.
This comes from Smalltalk, that implements control structures as methods, thus reducing the number of keywords and simplifying the parser. Thus allowing controll strucures to serve as proff of concept for the language definition.
In ST, even if conditions are methods, in the fashion:
boolean.ifTrue ->{executeIfBody()}, :else=>-> {executeElseBody()}
In the end, If you ignore your cultural bias, what will be easier to parse for the machine will also be easier to parse by yourself.
I recently discovered Ruby's blocks and yielding features, and I was wondering: where does this fit in terms of computer science theory? Is it a functional programming technique, or something more specific?
Ruby's yield is not an iterator like in C# and Python. yield itself is actually a really simple concept once you understand how blocks work in Ruby.
Yes, blocks are a functional programming feature, even though Ruby is not properly a functional language. In fact, Ruby uses the method lambda to create block objects, which is borrowed from Lisp's syntax for creating anonymous functions — which is what blocks are. From a computer science standpoint, Ruby's blocks (and Lisp's lambda functions) are closures. In Ruby, methods usually take only one block. (You can pass more, but it's awkward.)
The yield keyword in Ruby is just a way of calling a block that's been given to a method. These two examples are equivalent:
def with_log
output = yield # We're calling our block here with yield
puts "Returned value is #{output}"
end
def with_log(&stuff_to_do) # the & tells Ruby to convert into
# an object without calling lambda
output = stuff_to_do.call # We're explicitly calling the block here
puts "Returned value is #{output}"
end
In the first case, we're just assuming there's a block and say to call it. In the other, Ruby wraps the block in an object and passes it as an argument. The first is more efficient and readable, but they're effectively the same. You'd call either one like this:
with_log do
a = 5
other_num = gets.to_i
#my_var = a + other_num
end
And it would print the value that wound up getting assigned to #my_var. (OK, so that's a completely stupid function, but I think you get the idea.)
Blocks are used for a lot of things in Ruby. Almost every place you'd use a loop in a language like Java, it's replaced in Ruby with methods that take blocks. For example,
[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value} # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]
As Andrew noted, it's also commonly used for opening files and many other places. Basically anytime you have a standard function that could use some custom logic (like sorting an array or processing a file), you'll use a block. There are other uses too, but this answer is already so long I'm afraid it will cause heart attacks in readers with weaker constitutions. Hopefully this clears up the confusion on this topic.
There's more to yield and blocks than mere looping.
The series Enumerating enumerable has a series of things you can do with enumerations, such as asking if a statement is true for any member of a group, or if it's true for all the members, or searching for any or all members meeting a certain condition.
Blocks are also useful for variable scope. Rather than merely being convenient, it can help with good design. For example, the code
File.open("filename", "w") do |f|
f.puts "text"
end
ensures that the file stream is closed when you're finished with it, even if an exception occurs, and that the variable is out of scope once you're finished with it.
A casual google didn't come up with a good blog post about blocks and yields in ruby. I don't know why.
Response to comment:
I suspect it gets closed because of the block ending, not because the variable goes out of scope.
My understanding is that nothing special happens when the last variable pointing to an object goes out of scope, apart from that object being eligible for garbage collection. I don't know how to confirm this, though.
I can show that the file object gets closed before it gets garbage collected, which usually doesn't happen immediately. In the following example, you can see that a file object is closed in the second puts statement, but it hasn't been garbage collected.
g = nil
File.open("/dev/null") do |f|
puts f.inspect # #<File:/dev/null>
puts f.object_id # Some number like 70233884832420
g = f
end
puts g.inspect # #<File:/dev/null (closed)>
puts g.object_id # The exact same number as the one printed out above,
# indicating that g points to the exact same object that f pointed to
I think the yield statement originated from the CLU language. I always wonder if the character from Tron was named after CLU too....
I think 'coroutine' is the keyword you're looking for.
E.g. http://en.wikipedia.org/wiki/Yield
Yield in computing and information science:
in computer science, a point of return (and re-entry) of a coroutine