Can someone explain respond_to? :each? - ruby

Can someone help me understand the following code?
array = [1,2,3,4];
if array.respond_to? :each
puts "1234"
else
puts "5678"
end
I can understand the result of the code, but what is the syntax of :each?
Is :each a global method? Why can we write it like this? Or how I can find out about it?

:each is a Symbol, which is kind of like a String but more limited, and more efficient in comparisons for equality. It is not a method; it does happen to be a method name.
respond_to? is a method defined on Object, which (almost) all Ruby objects ultimately inherit from.
When you say [1, 2, 3, 4].each, it will send the message :each to the Array object [1, 2, 3, 4]. The Array class object is aware that its instances will know what to do when they receive such a message, and thus Array.respond_to?(:each) return true. Basically, if array.respond_to?(:each) is false, then array.each will raise an error. [Note that, as p11y notes in comments, if array is really an Array, then this will always return true. But programmers can lie, and array does not have to be an Array; for example: array = "not an Array, fooled you!"]
[1, 2, 3, 4].respond_to? :each is equivalent to [1, 2, 3, 4].respond_to?(:each).
On a side note, semicolons are only ever required in Ruby if you want to stuff several statements on one line. Unlike in C, for example, where semicolon is a statement terminator, in Ruby it is statement separator. It is thus bad style to write array = [1, 2, 3, 4];.

Related

Can you pass arguments to the method in `&method(:method_ name)` in ruby? [duplicate]

I am aware of the shorthand for map that looks like:
[1, 2, 3, 4].map(&:to_s)
> ["1", "2", "3", "4"]
I was told this is shorthand for:
[1, 2, 3, 4].map{|i| i.to_s}
This makes perfect sense. My question is this: It seems there should be an easier way to write:
[1, 2, 3, 4].map{|x| f.call(x)}
for some procedure f. I know the way I just typed isn't all that long to begin with, but I'd contend that neither is the previous example for which the shorthand exists. This example just seems like the complement to the first example: Rather than calling i's to_s method for every i, I wish to call f for every x.
Does such a shorthand exist?
Unfortunately this shorthand notation (which calls "Symbol#to_proc") does not have a way to pass arguments to the method or block being called, so you couldn't even do the following:
array_of_strings.map(&:include, 'l') #=> this would fail
BUT, you are in luck because you don't actually need this shortcut to do what you are trying to do. The ampersand can convert a Proc or Lambda into a block, and vice-versa:
my_routine = Proc.new { |str| str.upcase }
%w{ one two three }.map &my_routine #=> ['ONE', 'TWO', 'THREE']
Note the lack of the colon before my_routine. This is because we don't want to convert the :my_routine symbol into a proc by finding the method and calling .method on it, rather we want to convert the my_routine Proc into a block and pass it to map.
Knowing this, you can even map a native Ruby method:
%w{ one two three }.map &method(:p)
The method method would take the p method and convert it into a Proc, and the & converts it into a block that gets passed to map. As a result, each item gets printed. This is the equivalent of this:
%w{ one two three }.map { |s| p s }
As of Ruby 2.7, numbered parameters (_1, _2, etc) are supported. This syntax can be cryptic, especially with more than one parameter, but it can be useful for simple situations.
[1, 2, 3, 4].map { f.call(_1) }

How does ruby unpack arguments passed into Proc?

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.

Enumerator chain starting with find

There's on case of enumerator chain I can't get my head around:
[1, 2, 3, 4, 5].find.map { |x| x * x }
#=> [1, 4, 9, 16, 25]
This returns the array of initial value squares, but I would expect it to return just the [1]
I tried to deconstruct everything and this is what I achieved: .map is called on a find enumerator for the original array. It calls each on itself to get values for iteration. each on enumerator delegates iteration to method for which enumerator was created, i.e. find. find gets first element of array, yields it up, and it keeps being yielded until it reaches the block in the example. The value gets squared, block returns it, underlying each block in map definition returns [1], it drops down to the find, and since it's true in a boolean sense, I expect find to return at this point, effectively ending iteration, but somehow it keeps feeding values from the array all the way up to the map block.
This is not a real-world example, I'm just trying to understand how to read these chains correctly, and this case got me confused.
UPD
Since it was suggested several times that find being called without a block returns 'default' enumerator, here's an example:
[1, 2, 3, 4, 5].find
#=> #<Enumerator: [1, 2, 3, 4, 5]:find>
[1, 2, 3, 4, 5].find.each { |x| x < 4 }
#=> 1
Ok, I finally figured it out.
The reason find does not terminate the iteration after the first value is processed by block, is that collect_i iterator within collect aka map method of Enumerable module explicitly returns nil after every iteration, no matter what was the returning value of a block provided with a call to map or collect. Here it is, taken from enum.c:
static VALUE
collect_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
{
rb_ary_push(ary, enum_yield(argc, argv));
return Qnil;
}
So internal call to find on the initial array always gets nil as a result of yielding a value, and thus doesn't stop iteration until the last element is processed. This is easy to prove by downloading ruby as archive and modifying this function like this:
static VALUE
collect_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, ary))
{
rb_ary_push(ary, enum_yield(argc, argv));
return ary;
}
After saving and building ruby from modified source, we get this:
irb(main):001:0> [1,2,3,4,5].find.map { |x| x*x }
=> [1]
Another interesting thing, is that Rubinius implements collect exactly like this, so I think there's a chance that MRI and Rubinius produce different results for this statement. I don't have a working Rubinius installation right now, but I will check for this when I'll have an oppoprtunity and update this post with result.
Not sure if this will ever be of any use to anyone, except maybe for satisfying one's curiosity, but still :)

How do you get the class of an underlying object in a Ruby enumerable?

a = [4, 5, 3]
e = a.each
e.class #=> Enumerator
e.first.class #=> Fixnum
How do you find out if e is an enumerator for an array, hash or other type?
Working in Ruby 1.9.2
You can't (easily).*
Nor should you be able to. Enumerators aren't meant to care about what's contained within them, they're meant to iterate over something. You probably shouldn't be passing around enumerators anyway: just pass around the actual object.
Though, you could do nasty things like parse [].each.inspect with regex for either [] or {}, or the case where it's another type like #<Set: {}>. But this is just so horrible. I suggest re-thinking why you want to do this—and then not doing it.
* Note that the non-easy programmatic way would be to write C code using the Ruby C API and tap into the actual object pointer within the enumerator. This needs to be done because Enumerator is written in C, and causes doing things like [].each.instance_variables to return [].
Not that I propose that this is appropriate or in any way a good idea, but you CAN inspect an enumerator and potentially get some information that would give you a hint to the underlying object. This of course, begs the question of why you would want to do this...
a = [1,2,3,4]
=> [1, 2, 3, 4]
e = a.each
=> #<Enumerator: ...>
e.inspect
=> "<#Enumerator: [1, 2, 3, 4]:each>"
a = { :foo => "bar" }
=> {:foo=>"bar"}
e = a.each
=> #<Enumerator: ...>
e.inspect
=> "#<Enumerator: {:foo=>\"bar\"}:each>"
You can then use a regexp to try to tease out information about the underlying object. There are probably occasions for which this won't work (it does work for ranges). I'd emphasize again that there's probably no good reason to do this.
I would tentatively say that this can't be done. There doesn't seem to be any requirement, when creating an Enumerator, to actually reference the source object itself, only to tell the Enumerator how to get to the next, current, etc... values

Other Ruby Map Shorthand Notation

I am aware of the shorthand for map that looks like:
[1, 2, 3, 4].map(&:to_s)
> ["1", "2", "3", "4"]
I was told this is shorthand for:
[1, 2, 3, 4].map{|i| i.to_s}
This makes perfect sense. My question is this: It seems there should be an easier way to write:
[1, 2, 3, 4].map{|x| f.call(x)}
for some procedure f. I know the way I just typed isn't all that long to begin with, but I'd contend that neither is the previous example for which the shorthand exists. This example just seems like the complement to the first example: Rather than calling i's to_s method for every i, I wish to call f for every x.
Does such a shorthand exist?
Unfortunately this shorthand notation (which calls "Symbol#to_proc") does not have a way to pass arguments to the method or block being called, so you couldn't even do the following:
array_of_strings.map(&:include, 'l') #=> this would fail
BUT, you are in luck because you don't actually need this shortcut to do what you are trying to do. The ampersand can convert a Proc or Lambda into a block, and vice-versa:
my_routine = Proc.new { |str| str.upcase }
%w{ one two three }.map &my_routine #=> ['ONE', 'TWO', 'THREE']
Note the lack of the colon before my_routine. This is because we don't want to convert the :my_routine symbol into a proc by finding the method and calling .method on it, rather we want to convert the my_routine Proc into a block and pass it to map.
Knowing this, you can even map a native Ruby method:
%w{ one two three }.map &method(:p)
The method method would take the p method and convert it into a Proc, and the & converts it into a block that gets passed to map. As a result, each item gets printed. This is the equivalent of this:
%w{ one two three }.map { |s| p s }
As of Ruby 2.7, numbered parameters (_1, _2, etc) are supported. This syntax can be cryptic, especially with more than one parameter, but it can be useful for simple situations.
[1, 2, 3, 4].map { f.call(_1) }

Resources