My background is in PHP and C#, but I'd really like to learn RoR. To that end, I've started reading the official documentation. I have some questions about some code examples.
The first is with iterators:
class Array
def inject(n)
each { |value| n = yield(n, value) }
n
end
def sum
inject(0) { |n, value| n + value }
end
def product
inject(1) { |n, value| n * value }
end
end
I understand that yield
means "execute the associated block here." What's throwing me is the |value| n =
part of the each
. The other blocks make more sense to me as they seem to mimic C# style lambdas:
public int sum(int n, int value)
{
return Inject((n, value) => n + value);
}
But the first example is confusing to me.
The other is with symbols. When would I want to use them? And why can't I do something like:
class Example
attr_reader @member
# more code
end
Symbols are objects that can be passed around like any other Ruby object. They can also be used to pass values to methods, such as in getter and setter methods in class definitions: These are just a few examples of when to use symbols in Ruby.
“Iterators” is the object-oriented concept in Ruby. In more simple words, iterators are the methods which are supported by collections(Arrays, Hashes etc.). Collections are the objects which store a group of data members. Ruby iterators return all the elements of a collection one after another.
Ruby blocks are little anonymous functions that can be passed into methods. Blocks are enclosed in a do / end statement or between brackets {} , and they can have multiple arguments.
The each() is an inbuilt method in Ruby iterates over every element in the range. Syntax: range1.each(|el| block) Parameters: The function accepts a block which specifies the way in which the elements are iterated. Return Value: It returns every elements in the range.
In the inject
or reduce
method, n
represents an accumulated value; this means the result of every iteration is accumulated in the n
variable. This could be, as is in your example, the sum or product of the elements in the array.
yield
returns the result of the block, which is stored in n
and used in the next iterations. This is what makes the result "cumulative."
a = [ 1, 2, 3 ]
a.sum # inject(0) { |n, v| n + v }
# n == 0; n = 0 + 1
# n == 1; n = 1 + 2
# n == 3; n = 3 + 3
=> 6
Also, to compute the sum you could also have written a.reduce :+
. This works for any binary operation. If your method is named symbol
, writing a.reduce :symbol
is the same as writing a.reduce { |n, v| n.symbol v }
.
attr
and company are actually methods. Under the hood, they dynamically define the methods for you. It uses the symbol you passed to work out the names of the instance variable and the methods. :member
results in the @member
instance variable and the member
and member =
methods.
The reason you can't write attr_reader @member
is because @member
isn't an object in itself, nor can it be converted to a symbol; it actually tells ruby to fetch the value of the instance variable @member
of the self
object, which, at class scope, is the class itself.
To illustrate:
class Example
@member = :member
attr_accessor @member
end
e = Example.new
e.member = :value
e.member
=> :value
Remember that accessing unset instance variables yields nil
, and since the attr
method family accepts only symbols, you get: TypeError: nil is not a symbol
.
Regarding Symbol usage, you can sort of use them like strings. They make excellent hash keys because equal symbols always refer to the same object, unlike strings.
:a.object_id == :a.object_id
=> true
'a'.object_id == 'a'.object_id
=> false
They're also commonly used to refer to method names, and can actually be converted to Proc
s, which can be passed to methods. This is what allows us to write things like array.map &:to_s
.
Check out this article for more interpretations of the symbol.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With