Related
Trying to understand ruby's complexity, but makes no sense so far.
5.times(method(:puts))
Gives error, that doesn't make a lot of sense. Do I have some kind of syntax error or is it not possible to do in ruby?
ArgumentError: wrong number of arguments (given 1, expected 0)
from (irb):78:in `times'
I am trying to do something similar to
[0, 1, 2, 3, 4].forEach(console.log)
and
java.util.stream.IntStream.range(0, 5).forEach(System.out::println);
At the same time these do work:
method(:puts).call(1)
# and
5.times { |i| puts i }
times takes a block argument, which is distinguished from "regular" arguments by an ampersand. You can either pass it an explicit block
5.times { |x| puts x }
or you can pass it a value with &
5.times(&method(:puts))
Having the block argument treated differently allows us to write methods that look and act a lot like built-in statements. For instance, an infinite loop in Ruby can be written as
loop {
# fun stuff happening in here
}
But loop is a method in the core library, not a built-in keyword. We could've written that loop function ourselves. Enumerable and other modules make heavy use of block arguments to provide friendlier syntax, which is one of the primary goals of Ruby as a language.
a_proc = Proc.new {|a,b,*c| p c; c.collect {|i| i*b }}
puts a_proc[2,2,4,3]
Code above is pretty intuitive according to https://ruby-doc.org/core-2.2.0/Proc.html, a_proc[2,2,4,3] is just a syntax sugar for a_proc.call(2,2,4,3) to hide “call”
But the following (works well) confused me a lot
a=[2,2,4,3]
puts a_proc.call(a)
puts a_proc.call(*a)
It seems very different from a normal function call, cause it doesn't check the number arguments passed in.
However, as expected the method calling semantics will raise an error if using parameters likewise
def foo(a,b,*c)
c.collect{|i| i*b}
end
foo([1,2,3,4]) #`block in <main>': wrong number of arguments (given 1, expected 2+) (ArgumentError)
foo(*[1,2,3,4]) #works as expected
I do not think such an inconsistency as a design glitch, so any insights on this will be appreciated.
Blocks use different semantics than methods for binding arguments to parameters.
Block semantics are more similar to assignment semantics than to method semantics in this regard. In fact, in older versions of Ruby, blocks literally used assignment for parameter binding, you could write something like this:
class Foo; def bar=(val) puts 'setter called!' end end
some_proc = Proc.new {|$foo, #foo, foo.bar|}
some_proc.call(1, 2, 3)
# setter called!
$foo #=> 1
#foo #=> 2
Thankfully, this is no longer the case since Ruby 1.9. However, some semantics have been retained:
If a block has multiple parameters but receives only a single argument, the argument will be sent a to_ary message (if it isn't an Array already) and the parameters will be bound to the elements of the Array
If a block receives more arguments than it has parameters, it ignores the extra arguments
If a block receives fewer arguments than it has parameters, the extra parameters are bound to nil
Note: #1 is what makes Hash#each work so beautifully, otherwise, you'd always have to deconstruct the array that it passes to the block.
In short, block parameters are bound much the same way as with multiple assignment. You can imagine assignment without setters, indexers, globals, instance variables, and class variables, only local variables, and that is pretty much how parameter binding for blocks work: copy&paste the parameter list from the block, copy&paste the argument list from the yield, put an = sign in between and you get the idea.
Now, you aren't actually talking about a block, though, you are talking about a Proc. For that, you need to know something important: there are two kinds of Procs, which unfortunately are implemented using the same class. (IMO, they should have been two different classes.) One kind is called a lambda and the other kind is usually called a proc (confusingly, since both are Procs).
Procs behave like blocks, both when it comes to parameter binding and argument passing (i.e. the afore-described assignment semantics) and also when it comes to the behavior of return (it returns from the closest lexically enclosing method).
Lambdas behave like methods, both when it comes to parameter binding and argument passing (i.e. strict argument checking) and also when it comes to the behavior of return (it returns from the lambda itself).
A simple mnemonic: "block" and "proc" rhyme, "method" and "lambda" are both Greek.
A small remark to your question:
a_proc[2,2,4,3] is just a syntax sugar for a_proc.call(2,2,4,3) to hide “call”
This is not syntactic sugar. Rather, Proc simply defines the [] method to behave identically to call.
What is syntactic sugar is this:
a_proc.(2, 2, 4, 3)
Every occurrence of
foo.(bar, baz)
gets interpreted as
foo.call(bar, baz)
I believe what might be confusing you are some of the properties of Procs. If they are given a single array argument, they will automatically splat it. Also, ruby blocks in general have some interesting ways of handling block arguments. The behavior you're expecting is what you will get with a Lambda. I suggest reading Proc.lambda? documentation and be careful when calling a ruby block with an array.
Now, let's start with the splat operator and then move to how ruby handles block arguments:
def foo(a, b, *c)
c.map { |i| i * b } # Prefer to use map alias over collect
end
foo([1, 2, 3, 4]) # `block in <main>': wrong number of arguments (given 1, expected 2+) (ArgumentError)
foo(*[1, 2, 3, 4]) # works as expected
So in your argument error, it makes sense: def foo() takes at least two arguments: a, b, and however many with *c. The * is the splat operator. It will turn an array into individual arguments, or in the reverse case here, a variable amount of arguments into an array. So when you say foo([1,2,3,4]), you are giving foo one argument, a, and it is [1,2,3,4]. You are not setting b or *c. What would work is foo(1, 1, 1, 2, 3, 4]) for example because you are setting a, b, and c. This would be the same thing: foo(1, 1, *[1,2,3,4]).
Now foo(*[1, 2, 3, 4]) works as expected because the splat operator (*) is turning that into foo(1, 2, 3, 4) or equivalently foo(1, 2, *[3, 4])
Okay, so now that we have the splat operator covered, let's look back at the following code (I made some minor changes):
a_proc = Proc.new { |a, b, *c| c.map { |i| i * b }}
a = [1, 2, 3, 4]
puts a_proc.call(a)
puts a_proc.call(*a)
Remember that if blocks/procs are given a single array argument they will automatically splat it. So if you have an array of arrays arrays = [[1, 1], [2, 2], [3, 3]] and you do arrays.each { |a, b| puts "#{a}:#{b}" } you are going to get 1:1, 2:2, and 3:3 as the output. As each element is passed as the argument to the block, it sees that it is an array and splats it, assigning the elements to as many of the given block variables as it can. Instead of just putting that array in a such as a = [1, 1]; b = nil, you get a = 1; b = 1. It's doing the same thing with the proc.
a_proc.call([1, 2, 3, 4]) is turned into Proc.new { |1, 2, [3, 4]| c.map { |i| i * b }} and will output [6, 8]. It splits up the arguments automatically it's own.
What's the fastest way in Ruby to get the first enumerable element for which a block returns true?
For example:
arr = [12, 88, 107, 500]
arr.select {|num| num > 100 }.first # => 107
I'd like to do this without running through the entire array, as select will, since I only need the first match.
I know I could do an each and break on success, but I thought there was a native method for doing this; I just haven't found it in the documentation.
Several core ruby classes, including Array and Hash include the Enumerable module which provides many useful methods to work with these enumerations.
This module provides the find or detect methods which do exactly what you want to achieve:
arr = [12, 88, 107, 500]
arr.find { |num| num > 100 } # => 107
Both method names are synonyms to each other and do exactly the same.
arr.find{|el| el>100} #107 (or detect; it's in the Enumerable module.)
I remember this using by thinking of ActiveRecord.find, which gets you the first record and ActiveRecord.select, which you use when you're getting all of them.
Not a perfect comparison but might be enough to help remember.
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.
I want to use min(5,10), or Math.max(4,7). Are there functions to this effect in Ruby?
You can do
[5, 10].min
or
[4, 7].max
They come from the Enumerable module, so anything that includes Enumerable will have those methods available.
v2.4 introduces own Array#min and Array#max, which are way faster than Enumerable's methods because they skip calling #each.
#nicholasklick mentions another option, Enumerable#minmax, but this time returning an array of [min, max].
[4, 5, 7, 10].minmax
=> [4, 10]
You can use
[5,10].min
or
[4,7].max
It's a method for Arrays.
All those results generate garbage in a zealous attempt to handle more than two arguments. I'd be curious to see how they perform compared to good 'ol:
def max (a,b)
a>b ? a : b
end
which is, by-the-way, my official answer to your question.
If you need to find the max/min of a hash, you can use #max_by or #min_by
people = {'joe' => 21, 'bill' => 35, 'sally' => 24}
people.min_by { |name, age| age } #=> ["joe", 21]
people.max_by { |name, age| age } #=> ["bill", 35]
In addition to the provided answers, if you want to convert Enumerable#max into a max method that can call a variable number or arguments, like in some other programming languages, you could write:
def max(*values)
values.max
end
Output:
max(7, 1234, 9, -78, 156)
=> 1234
This abuses the properties of the splat operator to create an array object containing all the arguments provided, or an empty array object if no arguments were provided. In the latter case, the method will return nil, since calling Enumerable#max on an empty array object returns nil.
If you want to define this method on the Math module, this should do the trick:
module Math
def self.max(*values)
values.max
end
end
Note that Enumerable.max is, at least, two times slower compared to the ternary operator (?:). See Dave Morse's answer for a simpler and faster method.