class MyClass
extend Forwardable
def_delegators :#broker, :add
def subscribe_in_broker
#subscribers.map(&method(:add))
end
end
In this example #subscribers is a Hash and #broker.add takes two arguments: def broker(k,v).
This causes ArgumentError: wrong number of arguments (given 1, expected 2)
Is there a way to use Forwardable or a similar solution without this problem? How can I easily delegate an Array with 2 elements to a method which takes two arguments? What would be the equivalent of writing:
def subscribe_in_broker
#subscribers.map{|k,v| add(k,v) }
end
but using delegation?
It might seem like the block is receiving 2 arguments, but it is actually receiving only a single argument (a 2-element array). Ruby is interpreting the |x, y| as if it was |(x, y)|. The parentheses (which can be omitted here) destructure the single argument into its two pieces.
When you use a & with a method, it also only gets only 1 argument, and if you want to destructure it, you have to be explicit by using a set of parentheses around x and y:
def add((x,y))
end
To be clear, this is a single-argument method that expects the argument to be an array. For example, you call it like this: add([1, 2])
Note: this has nothing to do with delegation, just the fact that Ruby assumes you intend to destructure in one place, while not in another.
It is possible to yield more than one argument to a block (or a method turned into a proc with '&'), but that is not what map does.
It's not obvious to me why hash.map { |x,y| add(x, y) } is not adequate for your purposes. To work around that, you'd need to define your own map function that yields 2 arguments instead of 1, and that seems like overkill for this.
Related
Consider the following:
(1..10).inject{|memo, n| memo + n}
Question:
How does n know that it is supposed to store all the values from 1..10? I'm confused how Ruby is able to understand that n can automatically be associated with (1..10) right away, and memo is just memo.
I know Ruby code blocks aren't the same as the C or Java code blocks--Ruby code blocks work a bit differently. I'm confused as to how variables that are in between the upright pipes '|' will automatically be assigned to parts of an object. For example:
hash1 = {"a" => 111, "b" => 222}
hash2 = {"b" => 333, "c" => 444}
hash1.merge(hash2) {|key, old, new| old}
How do '|key, old, new|' automatically assign themselves in such a way such that when I type 'old' in the code block, it is automatically aware that 'old' refers to the older hash value? I never assigned 'old' to anything, just declared it. Can someone explain how this works?
The parameters for the block are determined by the method definition. The definition for reduce/inject is overloaded (docs) and defined in C, but if you wanted to define it, you could do it like so (note, this doesn't cover all the overloaded cases for the actual reduce definition):
module Enumerable
def my_reduce(memo=nil, &blk)
# if a starting memo is not given, it defaults to the first element
# in the list and that element is skipped for iteration
elements = memo ? self : self[1..-1]
memo ||= self[0]
elements.each { |element| memo = blk.call(memo, element) }
memo
end
end
This method definition determines what values to use for memo and element and calls the blk variable (a block passed to the method) with them in a specific order.
Note, however, that blocks are not like regular methods, because they don't check the number of arguments. For example: (note, this example shows the usage of yield which is another way to pass a block parameter)
def foo
yield 1
end
# The b and c variables here will be nil
foo { |a, b, c| [a,b,c].compact.sum } # => 1
You can also use deconstruction to define variables at the time you run the block, for example if you wanted to reduce over a hash you could do something like this:
# this just copies the hash
{a: 1}.reduce({}) { |memo, (key, val)| memo[key] = val; memo }
How this works is, calling reduce on a hash implicitly calls to_a, which converts it to a list of tuples (e.g. {a: 1}.to_a = [[:a, 1]]). reduce passes each tuple as the second argument to the block. In the place where the block is called, the tuple is deconstructed into separate key and value variables.
A code block is just a function with no name. Like any other function, it can be called multiple times with different arguments. If you have a method
def add(a, b)
a + b
end
How does add know that sometimes a is 5 and sometimes a is 7?
Enumerable#inject simply calls the function once for each element, passing the element as an argument.
It looks a bit like this:
module Enumerable
def inject(memo)
each do |el|
memo = yield memo, el
end
memo
end
end
And memo is just memo
what do you mean, "just memo"? memo and n take whatever values inject passes. And it is implemented to pass accumulator/memo as first argument and current collection element as second argument.
How do '|key, old, new|' automatically assign themselves
They don't "assign themselves". merge assigns them. Or rather, passes those values (key, old value, new value) in that order as block parameters.
If you instead write
hash1.merge(hash2) {|foo, bar, baz| bar}
It'll still work exactly as before. Parameter names mean nothing [here]. It's actual values that matter.
Just to simplify some of the other good answers here:
If you are struggling understanding blocks, an easy way to think of them is as a primitive and temporary method that you are creating and executing in place, and the values between the pipe characters |memo| is simply the argument signature.
There is no special special concept behind the arguments, they are simply there for the method you are invoking to pass a variable to, like calling any other method with an argument. Similar to a method, the arguments are "local" variables within the scope of the block (there are some nuances to this depending on the syntax you use to call the block, but I digress, that is another matter).
The method you pass the block to simply invokes this "temporary method" and passes the arguments to it that it is designed to do. Just like calling a method normally, with some slight differences, such as there are no "required" arguments. If you do not define any arguments to receive, it will happily just not pass them instead of raising an ArgumentError. Likewise, if you define too many arguments for the block to receive, they will simply be nil within the block, no errors for not being defined.
I have code as follows:
def sum(a, b)
a + b
end
puts sum.call 2, 3
I get an error like:
wrong number of arguments (given 0, expected 2) (ArgumentError)
How can I call a function?
EDIT
I want to have a function able to call other one with certain arguments. I've written the code like below but the same error is still displayed.
def sum(a, b)
a + b
end
def kall(func, *args)
send(func, *args)
end
puts kall(sum, 2, 3)
In order to invoke the function sum, just delete the .call call:
def sum(a, b)
a + b
end
sum(1, 2)
# => 3
Other way to call the method is doing:
send(:sum, 1, 2)
Which invokes the method sum on the current context/object with the list of arguments (1, 2).
One more way to call a method is:
method(:sum).call(2, 3)
#=> 5
sum is not a function, it is a method. Methods belong to objects, they aren't objects. Ruby is an object-oriented language, which means you can only store objects in variables, only pass objects as arguments (with the slightly odd exception of blocks), only return objects from methods and only send messages to objects.
You cannot send a message to the sum method, because you can only send messages to objects, and methods aren't objects.
And even if it were possible to send messages to methods, there would still be an ambiguity in your code: Ruby allows you to leave out the argument list to a message send if you don't pass any arguments, therefore
sum
is a valid message send and is (somewhat) equivalent (modulo privacy) to
self.sum()
So, even if it were possible to send messages to methods, Ruby would still think that you try to send the sum message without an argument list.
So, since the problem is that we need an object, there are two things we can do. Firstly, we can use an object to begin with.
You used the term "function" in your question. Well, Ruby doesn't have functions, but it has something close to it: Procs. One solution would be to use a Proc instead of a method:
sum = -> (a, b) { a + b }
sum.(2, 3)
#=> 5
The other solution would be to obtain an object for the method. Ruby's Reflection System has a class called Method which responds to call, instances of which are reflective proxies for methods. You can obtain a Method object by sending the Object#method message to an object, e.g.:
sum = method(:sum)
sum.(2, 3)
#=> 5
You don't need to do .call or anything like that. If the function has no parameters, simply just type the name of the function. And if the function does have parameters, just do myFunction(param1, param2).
def hello
puts 'Hello, World!'
end
def output(string)
puts string
end
# Both of these do the same thing:
hello
hello()
# Doing that with stdout won't work though. It expects one argument, string
output('You can do it with parenthesis')
output 'You can also do it without'
I want a vector containing the result of rolling 10 dice (say). I can do this:
([6]*10).map{|x|rand(x)}
But this gives me a "wrong number of arguments" error:
([6]*10).map(:rand)
Is there a point-free way to pass the one-argument version of rand to map?
This will work:
([6]*10).map(&method(:rand))
This won't:
([6]*10).map(&:rand)
Symbol#to_proc is (roughly) implemented like this:
class Symbol
def to_proc
-> *args { args.first.public_send(self, *args.drop(1)) }
end
end
In other words, it takes the first argument as the receiver and the other arguments as arguments to the method that is named by the Symbol. So, in your case, it is calling
6.rand
over and over.
This "kind of" works, because 6 is an Integer, Integer is an indirect subclass of Object, which mixes in Kernel, which defines rand. But! rand is private, which means it can only be called without an explicit receiver. Also, you aren't passing any arguments, therefore even if it were public, you'd get the behavior of rand without arguments, which is a Float between 0 and 1.
Whereas Method#to_proc passes all arguments to the method (it already has its receiver bound, after all), so in this case, it will call
self.rand(6)
over and over. Which of course works, because self is an Object, Object includes Kernel, and rand is defined in Kernel.
This won't work as well:
([6]*10).map(:rand)
For the simple reason that map doesn't have any parameters, but you are passing an argument.
You can write:
([6]*10).map(&method(:rand))
This would be clean way to write it:
10.times.map { rand(6) }
Writing it this way makes it easier to see what argument is passed to rand.
I need to write a method that takes an unknown number of arguments (hence the *splat) but that passes a yields_with_args spec.
The code:
def eval_block(*args, &block)
raise "NO BLOCK GIVEN!" if block.nil?
block.call(args)
end
The rspec:
it "passes the arguments into the block" do
expect do |block|
eval_block(1, 2, 3, &block)
end.to yield_with_args(1, 2, 3)
end
end
It works, but it yields the array that *splat creates: [1,2,3] vs 1,2,3, and therefore doesn't pass the rspec. Is there another way to pass on multiple arguments through a method in Ruby?
Replace
block.call(args)
with
block.call(*args)
Splat has two functions: collecting arguments to an array when in definition, and distributing an array to arguments in calls. The two are inverse operations: if you expect transparent operation (three arguments go in, three arguments go out), you should distribute what you collected.
I am trying to understand why do we really need lambda or proc in ruby (or any other language for that matter)?
#method
def add a,b
c = a+b
end
#using proc
def add_proc a,b
f = Proc.new {|x,y| x + y }
f.call a,b
end
#using lambda function
def add_lambda a,b
f = lambda {|x,y| x + y}
f.call a,b
end
puts add 1,1
puts add_proc 1,2
puts add_lambda 1,3
I can do a simple addition using: 1. normal function def, 2. using proc and 3. using lambda.
But why and where use lambda in the real world? Any examples where functions cannot be used and lambda should be used.
It's true, you don't need anonymous functions (or lambdas, or whatever you want to call them). But there are a lot of things you don't need. You don't need classes—just pass all the instance variables around to ordinary functions. Then
class Foo
attr_accessor :bar, :baz
def frob(x)
bar = baz*x
end
end
would become
def new_Foo(bar,baz)
[bar,baz]
end
def bar(foo)
foo[0]
end
# Other attribute accessors stripped for brevity's sake
def frob(foo,x)
foo[0] = foo[1]*x
end
Similarly, you don't need any loops except for loop...end with if and break. I could go on and on.1 But you want to program with classes in Ruby. You want to be able to use while loops, or maybe even array.each { |x| ... }, and you want to be able to use unless instead of if not.
Just like these features, anonymous functions are there to help you express things elegantly, concisely, and sensibly. Being able to write some_function(lambda { |x,y| x + f(y) }) is much nicer than having to write
def temp(x,y)
x + f(y)
end
some_function temp
It's much bulkier to have to break off the flow of code to write out a deffed function, which then has to be given a useless name, when it's just as clear to write the operation in-line. It's true that there's nowhere you must use a lambda, but there are lots of places I'd much rather use a lambda.
Ruby solves a lot of the lambda-using cases with blocks: all the functions like each, map, and open which can take a block as an argument are basically taking a special-cased anonymous function. array.map { |x| f(x) + g(x) } is the same as array.map(&lambda { |x| f(x) + g(x) }) (where the & just makes the lambda "special" in the same way that the bare block is). Again, you could write out a separate deffed function every time—but why would you want to?
Languages other than Ruby which support that style of programming don't have blocks, but often support a lighter-weight lambda syntax, such as Haskell's \x -> f x + g x, or C#'s x => f(x) + g(x);2. Any time I have a function which needs to take some abstract behavior, such as map, or each, or on_clicked, I'm going to be thankful for the ability to pass in a lambda instead of a named function, because it's just that much easier. Eventually, you stop thinking of them as somehow special—they're about as exciting as literal syntax for arrays instead of empty().append(1).append(2).append(3). Just another useful part of the language.
1: In the degenerate case, you really only need eight instructions: +-<>[].,. <> move an imaginary "pointer" along an array; +- increment and decrement the integer in the current cell; [] perform a loop-while-non-zero; and ., do input and output. In fact, you really only need just one instruction, such as subleq a b c (subtract a from b and jump to c if the result is less than or equal to zero).
2: I've never actually used C#, so if that syntax is wrong, feel free to correct it.
Blocks are more-or-less the same thing
Well, in Ruby, one doesn't usually use lambda or proc, because blocks are about the same thing and much more convenient.
The uses are infinite, but we can list some typical cases. One normally thinks of functions as lower-level blocks performing a piece of the processing, perhaps written generally and made into a library.
But quite often one wants to automate the wrapper and provide a custom library. Imagine a function that makes an HTTP or HTTPS connection, or a straight TCP one, feeds the I/O to its client, and then closes the connection. Or perhaps just does the same thing with a plain old file.
So in Ruby we would put the function in a library and have it take a block for the user .. the client .. the "caller" to write his application logic.
In another language this would have to be done with a class that implements an interface, or a function pointer. Ruby has blocks, but they are all examples of a lambda-style design pattern.
1) It is just a convenience. You don't need to name certain blocks
special_sort(array, :compare_proc => lambda { |left, right| left.special_param <=> right.special_param }
(imagine if you had to name all these blocks)
2) #lambda is usually used to create clojures:
def generate_multiple_proc(cofactor)
lambda { |element| element * cofactor }
end
[1, 2, 3, 4].map(&generate_multiple_proc(2)) # => [2, 3, 5, 8]
[1, 2, 3, 4].map(&generate_multiple_proc(3)) # => [3, 6, 9, 12]
It comes down to style. Lambdas are a a declarative style, methods are an imperative style. Consider this:
Lambda, blocks, procs, are all different types of closure. Now the question is, when and why to use an anonymous closure. I can answer that - at least in ruby!
Closures contain the lexical context of where they were called from. If you call a method from within a method, you do not get the context of where the method was called. This is due to the way the object chain is stored in the AST.
A Closure (lambda) on the other hand, can be passed WITH lexical context through a method, allowing for lazy evaluation.
Also lambdas naturally lend themselves to recursion and enumeration.
In case of OOP, you should create a function in a class only if there should be such an operation on the class according to your domain modeling.
If you need a quick function which can be written inline such as for comparison etc, use a lambda
Also check these SO posts -
When to use lambda, when to use Proc.new?
C# Lambda expressions: Why should I use them?
When to use a lambda in Ruby on Rails?
They're used as "higher-order" functions. Basically, for cases where you pass one function to another, so that the receiving function can call the passed-in one according to its own logic.
This is common in Ruby for iteration, e.g. some_list.each { |item| ... } to do something to each item of some_list. Although notice here that we don't use the keyword lambda; as noted, a block is basically the same thing.
In Python (since we have a language-agnostic tag on this question) you can't write anything quite like a Ruby block, so the lambda keyword comes up more often. However, you can get a similar "shortcut" effect from list comprehensions and generator expressions.
I found this helpful in understanding the differences:
http://www.robertsosinski.com/2008/12/21/understanding-ruby-blocks-procs-and-lambdas/
But in general the point is sometimes your writing a method but you don't know what you're going to want to do at a certain point in that method, so you let the caller decide.
E.g.:
def iterate_over_two_arrays(arr1, arr2, the_proc)
arr1.each do |x|
arr2.each do |y|
# ok I'm iterating over two arrays, but I could do lots of useful things now
# so I'll leave it up to the caller to decide by passing in a proc
the_proc.call(x,y)
end
end
end
Then instead of writing a iterate_over_two_arrays_and_print_sum method and a iterate_over_two_arrays_and_print_product method you just call:
iterate_over_two_arrays([1,2,3], [4,5,6], Proc.new {|x,y| puts x + y }
or
iterate_over_two_arrays([1,2,3], [4,5,6], Proc.new {|x,y| puts x * y }
so it's more flexible.