I have started learning Ruby, and I have read a couple of tutorials and I even bought a book ("Programming Ruby 1.9 - The Pragmatic Programmers' Guide"), and I came across something new that I haven't seen before in any of the other languages I know (I am working as a PHP webdeveloper).
Blocks & Procs.
I think I understand what they are, but what I don't understand is why they are so great, and when and why I should use them.
Everywhere I look they say blocks and procs are a great feature in Ruby, but I don't understand them.
Can anybody here give a total Ruby-newbie like me some explanations?
There are a lot of things that are good about blocks. The elevator pitch: Blocks let us pass around actions the same way we normally pass around data.
The most obvious level is that they let you abstract things out into functions that wouldn't be possible otherwise. For example, let's look at a common case where you have a list of things and you want to filter it to only include items that match some criterion:
int list[50] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50};
int evenNumbers[50] = {0};
int copyIndex = 0;
for (int i = 0; i < 50; i++) {
if (list[i] % 2 == 0) {
evenNumbers[copyIndex++] = list[i];
}
}
Here's how you write that in Ruby:
list = 1..50
listCopy = list.select {|n| n.even?}
All the common busywork is moved out of your code and into a method with a meaningful name. We don't care about copying the array and going through indexes and all that — we just want a filtered list. And that's what select gives us. The block allows us to pass our custom logic into this standard method.
But iterators aren't the only place where this "hole in the middle pattern" is useful. For example, if you pass a block to File.open, it will open the file, execute the block with the file and then close the file for you.
Another thing that blocks give us is a really powerful form of callbacks. For example, without blocks, we might have to do something like this (based on how dialogs actually work in Objective-C Cocoa):
class Controller
def delete_button_clicked(item)
item.add_red_highlight
context = {:item => item}
dialog = Dialog.new("Are you sure you want to delete #{item}?")
dialog.ok_callback = :delete_OK
dialog.ok_receiver = self
dialog.cancel_callback = :cancel_delete
dialog.cancel_receiver = self
dialog.context = context
dialog.ask_for_confirmation
end
def delete_OK(sender)
delete(sender.context[:item])
sender.dismiss
end
def cancel_delete(sender)
sender.context[:item].remove_red_highlight
sender.dismiss
end
end
Yowza. With blocks, we could do this instead (based on a common pattern used in many Ruby libraries):
class Controller
def delete_button_clicked(item)
item.add_red_highlight
Dialog.ask_for_confirmation("Are you sure you want to delete #{item}?") do |response|
response.ok { delete item }
response.cancel { item.remove_red_highlight }
end
end
end
That's actually two levels of blocks — the do...end block and the two {}-style blocks. But it reads pretty naturally, doesn't it? This works because a block captures the context it's created in, so we don't need to pass around self and item.
As for Procs, they're just an object wrapper for blocks. Not very much to them.
Its important to view blocks not as using methods to begin a code block, you are actually taking the block and using it like a parameter in the function.
So when you use the each method to iterate over an array like so:
superOverFlowArray.each { |flow| puts flow }
You are sending the block { |flow| puts flow } into the each method. The code is telling ruby to send the current value of the array to this block in place of |flow|.
Procs take a block and make them into a variable. Procs are object instances that hold blocks. Blocks are passed as a parameter to the proc and are executed when you call the 'call' method on that Proc instance.
So here is a Proc example:
def category_and_title(category)
Proc.new { |title| "The title is: " + title + " in category: " + category }
end
myFirstTitle = category_and_title("Police Drama")
mySecondTitle = category_and_title("Comedy")
puts myFirstTitle.call("Law and Order")
puts mySecondTitle.call("Seinfeld")
puts myFirstTitle.call("CSI")
The Proc will remember the original category that was passed in, allowing a convenient way of grouping types.
Blocks are used from many methods in Ruby classes, and they are used where in PHP you would use a callback.
[1,2,3,4,5].each {|i| print "#{i} "}
[1,2,3,4,5].each do |i|
print "#{i} "
end
File.open('p014constructs.rb', 'r') do |f1|
while line = f1.gets
puts line
end
end
PHP5 introduced anonymous functions; instead of using a callback, you could use an anonymous function.
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world');
Procs, also known as closures or lambdas is a concept in ruby that may seem confusing at first, especially to a newbie. In short, procs allow you to pass code blocks around with ease. An example, below
hello = Proc.new do |x, y|
puts "i am a proc"
sum = x+y
puts "sum: #{sum}"
end
now to make use of this block of code, just call the method "call" on hello. Note that the example above receives arguments x and y which the code block uses. Therefore be sure to pass in arguments when you call out the Proc object like i have done below:
hello.call(2, 3)
yielding the following results:
i am a proc
sum: 5
Hurray!! That was an easy way to create a Proc object. How useful is this? Well, proc objects allow you to pass around chunks of code. An illustration below explains it better by making use of the proc created in the example above.
Let's create some random class,
class SomeClass
def initialize(&block)
#block = block
end
def output_value(x, y)
#block.call(x, y)
end
end
now, let's create an instance of SomeClass,
some_class = SomeClass.new(&hello)
NOTE that the ampersand sign "&" before the hello allows you to pass a proc object as an argument.
finally, let's output a value by passing 2 arguments, like below:
some_class.output_value(1, 3)
the result you get is as follows:
i am a proc
sum: 4
See!! it's that simple. You have been able to pass a chunk of code around.
Procs are so useful that ruby makes use of it a lot. Hope this was super helpful :)
These concepts are tied to concepts from functional programming into ruby, hence it enables you to use patterns and techniques that are usually found in languages, where functions are first-class citizens.
Blocks and procs let you extract small bits of code without the full overhead and complexity of methods.
Even map by itself is pretty powerful, and jQuery is built around this same concept:
['spite','rest','purpose'].map {|s| s << 'ful' }
And you can throw logic in if necessary
['sprite','restful','luck'].map {|s| s << (s.end_with?('uck') ? 'i' : '') << 'ly' }
There is a clever operator '&' that means "convert the symbol to a proc and call it", so you can convert objects strings:
['spite',12,:purpose].map(&:to_s)
And using closures and combining writing a simple closures we can find where adjacent of numbers appear. This is rather clumsy Ruby, but more concise than most languages:
last = -2 # this variable is accessed and changed within the closure
objs.sort.map do |o|
if (last + 1) != o
last = o
nil # not one more than previous so return nil
else
o
end
end.compact # compact removes nils
When you start rewriting it in another language you realize how convenient this is. It encourages you to structure your code into smaller operations, so it is more re-usable and testable.
Related
Let's suppose I have this class:
class Example
attr_accessor :numbers
def initialize(numbers = [])
#numbers = numbers
end
private
def validate!(number)
number >= 0 || raise(ArgumentError)
end
end
I would like to run the #validate! on any new number before pushing it into the numbers:
example = Example.new([1, 2, 3])
example.numbers # [1, 2, 3]
example.numbers << 4
example.numbers # [1, 2, 3, 4]
example.numbers << -1 # raise ArgumentError
Below is the best I can do but I'm really not sure about it.
Plus it works only on <<, not on push. I could add it but there is risk of infinite loop...).
Is there a more "regular" way to do it? I couldn't find any official process for that.
class Example
attr_accessor :numbers
def initialize(numbers = [])
#numbers = numbers
bind = self # so the instance is usable inside the singleton block
#numbers.singleton_class.send(:define_method, :<<) do |value|
# here, self refers to the #numbers array, so use bind to refer to the instance
bind.send(:validate!, value)
push(value)
end
end
private
def validate!(number)
number >= 0 || raise(ArgumentError)
end
end
Programming is a lot like real life: it is not a good idea to just run around and let strangers touch your private parts.
You are solving the wrong problem. You are trying to regulate what strangers can do when they play with your private parts, but instead you simply shouldn't let them touch your privates in the first place.
class Example
def initialize(numbers = [])
#numbers = numbers.clone
end
def numbers
#numbers.clone.freeze
end
def <<(number)
validate(number)
#numbers << number
self
end
private
def validate(number)
raise ArgumentError, "number must be non-negative, but is #{number}" unless number >= 0
end
end
example = Example.new([1, 2, 3])
example.numbers # [1, 2, 3]
example << 4
example.numbers # [1, 2, 3, 4]
example << -1 # raise ArgumentError
Let's look at all the changes I made one-by-one.
cloneing the initializer argument
You are taking a mutable object (an array) from an untrusted source (the caller). You should make sure that the caller cannot do anything "sneaky". In your first code, I can do this:
ary = [1, 2, 3]
example = Example.new(ary)
ary << -1
Since you simply took my array I handed you, I can still do to the array anything I want!
And even in the hardened version, I can do this:
ary = [1, 2, 3]
example = Example.new(ary)
class << ary
remove_method :<<
end
ary << -1
Or, I can freeze the array before I hand it to you, which makes it impossible to add a singleton method to it.
Even without the safety aspects, you should still do this, because you violate another real-life rule: Don't play with other people's toys! I am handing you my array, and then you mutate it. In the real world, that would be considered rude. In programming, it is surprising, and surprises breed bugs.
cloneing in the getter
This goes to the heart of the matter: the #numbers array is my private internal state. I should never hand that to strangers. If you don't hand the #numbers array out, then none of the problems you are protecting against can even occur.
You are trying to protect against strangers mutating your internal state, and the solution to that is simple: don't give strangers your internal state!
The freeze is technically not necessary, but I like it to make clear to the caller that this is just a view into the state of the example object, and they are only allowed to view what I want them to.
And again, even without the safety aspects, this would still be a bad idea: by exposing your internal implementation to clients, you can no longer change the internal implementation without breaking clients. If you change the array to a linked list, your clients are going to break, because they are used to getting an array that you can randomly index, but you can't randomly index a linked list, you always have to traverse it from the front.
The example is unfortunately too small and simple to judge that, but I would even question why you are handing out arrays in the first place. What do the clients want to do with those numbers? Maybe it is enough for them to just iterate over them, in which case you don't need to give them a whole array, just an iterator:
class Example
def each(...)
return enum_for(__callee__) unless block_given?
#numbers.each(...)
self
end
end
If the caller wants an array, they can still easily get one by calling to_a on the Enumerator.
Note that I return self. This has two reasons:
It is simply the contract of each. Every other object in Ruby that implements each returns self. If this were Java, this would be part of the Iterable interface.
I would actually accidentally leak the internal state that I work so hard to protect! As I just wrote: every implementation of each returns self, so what does #numbers.each return? It returns #numbers, which means my whole Example#each method returns #numbers which is exactly the thing I am trying to hide!
Implement << myself
Instead of handing out my internal state and have the caller append to it, I control what happens with my internal state. I implement my own version of << in which I can check for whatever I want and make sure no invariants of my object are violated.
Note that I return self. This has two reasons:
It is simply the contract of <<. Every other object in Ruby that implements << returns self. If this were Java, this would be part of the Appendable interface.
I would actually accidentally leak the internal state that I work so hard to protect! As I just wrote: every implementation of << returns self, so what does #numbers << number return? It returns #numbers, which means my whole Example#<< method returns #numbers which is exactly the thing I am trying to hide!
Drop the bang
In Ruby, method names that end with a bang mean "This method is more surprising than its non-bang counterpart". In your case, there is no non-bang counterpart, so the method shouldn't have a bang.
Don't abuse boolean operators for control flow
… or at least if you do, use the keyword versions (and / or) instead of the symbolic ones (&& / ||).
But really, you should void it altogether. do or die is idiomatic in Perl, but not in Ruby.
Technically, I have changed the return value of your method: it used to return true for a valid value, now it returns nil. But you ignore its return value anyway, so it doesn't matter.
validate is probably not a good name for the method, though. I would expect a method named validate to return a boolean result, not raise an exception.
An exceptional message
You should add messages to your exceptions that tell the programmer what went wrong. Another possibility is to create more specific exceptions, e.g.
class NegativeNumberError < ArgumentError; end
But that would be overkill in this case. In general, if you expect code to "read" your exception, create a new class, if you expect humans to read your exception, then a message is enough.
Encapsulation, Data Abstraction, Information Hiding
Those are three subtly different but related concepts, and they are among the most important concepts in programming. We always want hide our internal state and encapsulate it behind methods that we control.
Encapsulation to the max
Some people (including myself) don't particularly like even the object itself playing with its internal state. Personally, I even encapsulate private instance variables that are never exposed behind getters and setters. The reason is that this makes the class easier to subclass: you can override and specialize methods, but not instance variables. So, if I use the instance variable directly, a subclass cannot "hook" into those accesses.
Whereas if I use getter and setter methods, the subclass can override those (or only one of those).
Note: the example is too small and simple, so I had some real trouble coming up with a good name (there is not enough in the example to understand how the variable is used and what it means), so eventually, I just gave up, but you will see what I mean about using getters and setters:
class Example
class NegativeNumberError < ArgumentError; end
def initialize(numbers = [])
self.numbers_backing = numbers.clone
end
def each(...)
return enum_for(__callee__) unless block_given?
numbers_backing.each(...)
self
end
def <<(number)
validate(number)
numbers_backing << number
self
end
private
attr_accessor :numbers_backing
def validate(number)
raise NegativeNumberError unless number >= 0
end
end
example = Example.new([1, 2, 3])
example.each.to_a # [1, 2, 3]
example << 4
example.each.to_a # [1, 2, 3, 4]
example << -1 # raise NegativeNumberError
Some programmer made a method that gets lots of arguements like this:
def age_entry(age_1, age_2, age_3, age_4, age_5, age_6, age_7, age_8)
end
They could pass an array but simply they didn't. I love automation and hate to repeatedly add these variables to and array like this
ages = [age_1, age_2, age_3 ,..., age_8]
I would like to use metaprogramming or other ways to loop with a for or each methods to add them variables to an array like this:
(1..8).each do |index| do
ages << "age_" + index #value of age_[index] get saved to ages
end
P.S. I know I can use copy and paste but this is only for doing automation stuff with Ruby.
"Some programmer" should remember that you can pass in arrays. This sort of method signature is really obnoxious to work with for a multitude of reasons, some of them you've already discovered.
One way to refactor this method and preserve functionality is to just take in varargs:
def age_entry(*ages)
end
Now those values are put in an array for you but you can call the method the same way as before. As a plus you can specify more or fewer entries.
Variables with names like x1, x2 and so on are violations of the Zero, One or Infinity Rule and are a sign you need to think about the problem differently.
You don’t need any metaprogramming here. Just splat them:
ages = [age_1, age_2, age_3 ,..., age_8]
# ⇓ HERE
age_entry(*ages)
If you want to collect age_(1..8) into the array, assuming all local vars are defined, use Kernel#binding:
b = binding
ages = (1..8).map { |i| b.local_variable_get("age_#{i}") }
Suppose the method is as follows.
def oldest(age_bill, age_barb, age_trixie)
puts "Barb is #{age_barb} years old"
[age_bill, age_barb, age_trixie].max
end
oldest(35, 97, 29)
#=> 97
As well as the calculation in the penultimate line (which the OP wishes to avoid), this method requires knowledge of an individual method argument (age_barb). The following is one way to accomplishing both requirements.
def oldest(age_bill, age_barb, age_trixie)
puts "Barb is #{age_barb} years old"
b = binding
args = method(__method__).parameters.map { |arg| b.local_variable_get(arg[1]) }
args.max
end
#=> 97
Barb is 97 years old
Here
args
#=> [35, 97, 29]
My code is supposed to print integers in an array.
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return x end }
puts ints
It gives me an error in the 2nd line - in 'block in <main>': unexpected return (LocalJumpError)
When I remove the return, the code works exactly as desired.
To find the mistake in my understanding of blocks, I read related posts post1 and post2. But, I am not able to figure out how exactly are methods and blocks being called and why my approach is incorrect.
Is there some call stack diagram explanation for this ? Any simple explanation ?
I am confused because I have only programmed in Java before.
You generally don't need to worry exactly what blocks are to use them.
In this situation, return will return from the outside scope, e.g. if these lines were in a method, then from that method. It's the same as if you put a return statement inside a loop in Java.
Additional tips:
select is used to create a copied array where only the elements satisfying the condition inside the block are selected:
only_ints = odds_n_ends.select { |x| x.is_a?(Integer) }
You're using it as a loop to "pass back" variables that are integers, in which case you'd do:
only_ints = []
odds_n_ends.each { |x| if x.is_a?(Integer) then only_ints << x end }
If you try to wrap your code in a method then it won't give you an error:
def some_method
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return true end }
puts ints
end
puts some_method
This code output is true. But wait, where's puts ints??? Ruby didn't reach that. When you put return inside a Proc, then you're returning in the scope of the entire method. In your example, you didn't have any method in which you put your code, so after it encountered 'return', it didn't know where to 'jump to', where to continue to.
Array#select basically works this way: For each element of the array (represented with |x| in your code), it evaluates the block you've just put in and if the block evaluates to true, then that element will be included in the new array. Try removing 'return' from the second line and your code will work:
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then true end }
However, this isn't the most Ruby-ish way, you don't have to tell Ruby to explicitly return true. Blocks (the code between the {} ) are just like methods, with the last expression being the return value of the method. So this will work just as well:
ints = odds_n_ends.select { |x| if x.is_a?(Integer) } # imagine the code between {} is
#a method, just without name like 'def is_a_integer?' with the value of the last expression
#being returned.
Btw, there's a more elegant way to solve your problem:
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.grep(Integer)
puts ints
See this link. It basically states:
Returns an array of every element in enum for which Pattern ===
element.
To understand Pattern === element, simply imagine that Pattern is a set (let's say a set of Integers). Element might or might not be an element of that set (an integer). How to find out? Use ===. If you type in Ruby:
puts Integer === 34
it will evalute to true. If you put:
puts Integer === 'hey'
it will evalute to false.
Hope this helped!
In ruby a method always returns it's last statement, so in generall you do not need to return unless you want to return prematurely.
In your case you do not need to return anything, as select will create a new array with just the elements that return true for the given block. As ruby automatically returns it's last statement using
{ |x| x.is_a?(Integer) }
would be sufficient. (Additionally you would want to return true and not x if you think about "return what select expects", but as ruby treats not nil as true it also works...)
Another thing that is important is to understand a key difference of procs (& blocks) and lambdas which is causing your problem:
Using return in a Proc will return the method the proc is used in.
Using return in a Lambdas will return it's value like a method.
Think of procs as code pieces you inject in a method and of lambdas as anonymous methods.
Good and easy to comprehend read: Understanding Ruby Blocks, Procs and Lambdas
When passing blocks to methods you should simply put the value you want to be returned as the last statement, which can also be in an if-else clause and ruby will use the last actually reached statement.
For Fibers we have got classic example: generating of Fibonacci numbers
fib = Fiber.new do
x, y = 0, 1
loop do
Fiber.yield y
x,y = y,x+y
end
end
Why do we need Fibers here? I can rewrite this with just the same Proc (closure, actually)
def clsr
x, y = 0, 1
Proc.new do
x, y = y, x + y
x
end
end
So
10.times { puts fib.resume }
and
prc = clsr
10.times { puts prc.call }
will return just the same result.
So what are the advantages of fibers. What kind of stuff I can write with Fibers I can't do with lambdas and other cool Ruby features?
Fibers are something you will probably never use directly in application-level code. They are a flow-control primitive which you can use to build other abstractions, which you then use in higher-level code.
Probably the #1 use of fibers in Ruby is to implement Enumerators, which are a core Ruby class in Ruby 1.9. These are incredibly useful.
In Ruby 1.9, if you call almost any iterator method on the core classes, without passing a block, it will return an Enumerator.
irb(main):001:0> [1,2,3].reverse_each
=> #<Enumerator: [1, 2, 3]:reverse_each>
irb(main):002:0> "abc".chars
=> #<Enumerator: "abc":chars>
irb(main):003:0> 1.upto(10)
=> #<Enumerator: 1:upto(10)>
These Enumerators are Enumerable objects, and their each methods yield the elements which would have been yielded by the original iterator method, had it been called with a block. In the example I just gave, the Enumerator returned by reverse_each has a each method which yields 3,2,1. The Enumerator returned by chars yields "c","b","a" (and so on). BUT, unlike the original iterator method, the Enumerator can also return the elements one by one if you call next on it repeatedly:
irb(main):001:0> e = "abc".chars
=> #<Enumerator: "abc":chars>
irb(main):002:0> e.next
=> "a"
irb(main):003:0> e.next
=> "b"
irb(main):004:0> e.next
=> "c"
You may have heard of "internal iterators" and "external iterators" (a good description of both is given in the "Gang of Four" Design Patterns book). The above example shows that Enumerators can be used to turn an internal iterator into an external one.
This is one way to make your own enumerators:
class SomeClass
def an_iterator
# note the 'return enum_for...' pattern; it's very useful
# enum_for is an Object method
# so even for iterators which don't return an Enumerator when called
# with no block, you can easily get one by calling 'enum_for'
return enum_for(:an_iterator) if not block_given?
yield 1
yield 2
yield 3
end
end
Let's try it:
e = SomeClass.new.an_iterator
e.next # => 1
e.next # => 2
e.next # => 3
Wait a minute... does anything seem strange there? You wrote the yield statements in an_iterator as straight-line code, but the Enumerator can run them one at a time. In between calls to next, the execution of an_iterator is "frozen". Each time you call next, it continues running down to the following yield statement, and then "freezes" again.
Can you guess how this is implemented? The Enumerator wraps the call to an_iterator in a fiber, and passes a block which suspends the fiber. So every time an_iterator yields to the block, the fiber which it is running on is suspended, and execution continues on the main thread. Next time you call next, it passes control to the fiber, the block returns, and an_iterator continues where it left off.
It would be instructive to think of what would be required to do this without fibers. EVERY class which wanted to provide both internal and external iterators would have to contain explicit code to keep track of state between calls to next. Each call to next would have to check that state, and update it before returning a value. With fibers, we can automatically convert any internal iterator to an external one.
This doesn't have to do with fibers persay, but let me mention one more thing you can do with Enumerators: they allow you to apply higher-order Enumerable methods to other iterators other than each. Think about it: normally all the Enumerable methods, including map, select, include?, inject, and so on, all work on the elements yielded by each. But what if an object has other iterators other than each?
irb(main):001:0> "Hello".chars.select { |c| c =~ /[A-Z]/ }
=> ["H"]
irb(main):002:0> "Hello".bytes.sort
=> [72, 101, 108, 108, 111]
Calling the iterator with no block returns an Enumerator, and then you can call other Enumerable methods on that.
Getting back to fibers, have you used the take method from Enumerable?
class InfiniteSeries
include Enumerable
def each
i = 0
loop { yield(i += 1) }
end
end
If anything calls that each method, it looks like it should never return, right? Check this out:
InfiniteSeries.new.take(10) # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
I don't know if this uses fibers under the hood, but it could. Fibers can be used to implement infinite lists and lazy evaluation of a series. For an example of some lazy methods defined with Enumerators, I have defined some here: https://github.com/alexdowad/showcase/blob/master/ruby-core/collections.rb
You can also build a general-purpose coroutine facility using fibers. I've never used coroutines in any of my programs yet, but it's a good concept to know.
I hope this gives you some idea of the possibilities. As I said at the beginning, fibers are a low-level flow-control primitive. They make it possible to maintain multiple control-flow "positions" within your program (like different "bookmarks" in the pages of a book) and switch between them as desired. Since arbitrary code can run in a fiber, you can call into 3rd-party code on a fiber, and then "freeze" it and continue doing something else when it calls back into code you control.
Imagine something like this: you are writing a server program which will service many clients. A complete interaction with a client involves going through a series of steps, but each connection is transient, and you have to remember state for each client between connections. (Sound like web programming?)
Rather than explicitly storing that state, and checking it each time a client connects (to see what the next "step" they have to do is), you could maintain a fiber for each client. After identifying the client, you would retrieve their fiber and re-start it. Then at the end of each connection, you would suspend the fiber and store it again. This way, you could write straight-line code to implement all the logic for a complete interaction, including all the steps (just as you naturally would if your program was made to run locally).
I'm sure there's many reasons why such a thing may not be practical (at least for now), but again I'm just trying to show you some of the possibilities. Who knows; once you get the concept, you may come up with some totally new application which no-one else has thought of yet!
Unlike closures, which have a defined entry and exit point, fibers can preserve their state and return (yield) many times:
f = Fiber.new do
puts 'some code'
param = Fiber.yield 'return' # sent parameter, received parameter
puts "received param: #{param}"
Fiber.yield #nothing sent, nothing received
puts 'etc'
end
puts f.resume
f.resume 'param'
f.resume
prints this:
some code
return
received param: param
etc
Implementation of this logic with other ruby features will be less readable.
With this feature, good fibers usage is to do manual cooperative scheduling (as Threads replacement). Ilya Grigorik has a good example on how to turn an asynchronous library (eventmachine in this case) into what looks like a synchronous API without losing the advantages of IO-scheduling of the asynchronous execution. Here is the link.
I often plug pre-configured lambdas into enumerable methods like 'map', 'select' etc.
but the behavior of 'inject' seems to be different.
e.g. with
mult4 = lambda {|item| item * 4 }
then
(5..10).map &mult4
gives me
[20, 24, 28, 32, 36, 40]
However, if I make a 2-parameter lambda for use with an inject like so,
multL = lambda {|product, n| product * n }
I want to be able to say
(5..10).inject(2) &multL
since 'inject' has an optional single parameter for the initial value,
but that gives me ...
irb(main):027:0> (5..10).inject(2) &multL
LocalJumpError: no block given
from (irb):27:in `inject'
from (irb):27
However, if I stuff the '&multL' into a second parameter to inject, then it works.
irb(main):028:0> (5..10).inject(2, &multL)
=> 302400
My question is "why does that work and not the previous attempt?"
So the reason that
(5..10).map &mult4
works and
(5..10).inject(2) &multL
doesn't is that ruby parens are implicit in the first case, so it really means
(5..10).map(&mult4)
if you wanted, for the second case you could use
(5..10).inject 2, &multL
The outside the parens trick only works for passing blocks to a method, not lambda objects.