I'm just learning about Ruby, and am having trouble seeing the point of the so-called "block argument" (which can be appended to method invocations).
AFAICT, the "block argument" works like any run-of-the-mill callback argument in other programming languages (or in Ruby itself, for that matter), but are more limited in that one can attach at most one "block argument" to a method invocation, while there's no upper limit on the number of callback arguments a method/function can be designed to accept.
(In case clarification is needed, by "callback" all I mean is a function F that another function G receives (as one of its arguments) and in turn calls.)
I figure that there must be something that one can do with a block argument that can't be done just as easily with a callback (otherwise, it's hard to justify supporting a special syntax for block arguments), but I can't figure out what this "something" could be.
My question is just that:
What can be done with a "block argument" that couldn't be done with regular callback?
EDIT: An earlier comment (now deleted) said that block arguments are better described as "closures" than as "callbacks". In my book, closures are a special case of callbacks. One can, if one wants, replace "callback" with "closure" in my post. The post's question still remains (unless, of course, "block arguments" were the only way to create closures in Ruby, but if this were the case, it in itself would raise more questions than it answers).
I figure that there must be something that one can do with a block argument that can't be done just as easily with a callback (otherwise,
Yes. Blocks are a sort of "syntactic sugar", but they are also functionally quite different from "callback function" in a language like JavaScript.
For one thing, the return keyword functions very differently than it does in functions and methods both in Ruby and other languages.
Inside a block, return jumps out of the containing method, while in a method return jumps out of (obviously) the method.
This is important for the following case:
def find_by_email(users, search_email)
users.each do |user|
# return all the way out of find_by_email
return user if user.email == search_email
end
nil
end
Here, we're using each to iterate over a collection. If some condition is me inside the block, the user is returned all the way out of the containing method.
This doesn't work with a function. Compare the "identical" JavaScript code, which doesn't work as intended:
function findUserByEmail(users, searchEmail) {
users.forEach(function (user) {
if (user.email == searchEmail) {
// return out of `forEach`
return user;
}
});
// broken
}
I don't think anything can be done with blocks that can't be done with passing functions (such as in javascript) .
I think that the creators of ruby figured that in 95% of cases, you want to pass only one callback to a function, not more. So they created very nice syntax for that:
Post.all.map { |post| puts post.title }
Compare to javascript
$(document).on('click', function() {
DO SOMETHING
}
To sum: I think that passing blocks is a syntax sugar in ruby, comparable to passing functions in js but nicer looking. In the majority of cases you will want to pass one block (or callback) anyway.
Related
I'm analyzing a block of code written in ruby.
I don't know the language and I need to understand an operation.
def restore
m = ObjectName.where(prop: User.where(email: 'admin#email.com').first.element_id).last
m.todo!
m.waiting!
...
end
what "m.todo!" and "m.waiting!" are doing?
I cannot understand if it is assigning a "true" value or a value that is the opposite of the current one like: m.todo = !m.todo
Thank you very much
! and ? are valid parts of a method name in Ruby. They don't have any special meaning, though ! is conventionally used for mutative or destructive actions, and ? is conventionally used for predicate methods.
In this example, there are two methods named todo! and waiting! being called - nothing fancier. If I had to guess, those are methods which simply perform a combined "update a state variable and save" operation (hence, mutative).
In Ruby, foo.bar is the syntax for a message send. It will first evaluate the expression foo (which is either dereferencing a local variable or a receiverless message send to the implicit receiver self) and then send the message bar to the resulting object.
Once you know what message send in Ruby looks like, it is easy to see what m.todo! does: It will first evaluate the expression m (which is either dereferencing a local variable or a receiverless message send to the implicit receiver self) and then send the message todo! to the resulting object.
Method names ending in ! are typically used to mark the "more surprising" of a pair of methods. So, if you have two Methods, both of which do similar things, then the one with the bang at the end is the "more surprising" one. A good example are Process::exit and Process::exit!. Both exit the currently running Ruby process, but the "normal" version (i.e. the one without the bang) runs the exit handlers normally, whereas the "surprising" Version exits immediately without running the exit handlers.
Note: there seems to be a lot of misunderstanding About the naming convention for bang methods. So, let me be clear:
Bang methods have absolutely nothing to do with mutation or destruction. It is simply about surprise. See the Process::exit! example above which has nothing to do with mutation.
Bang methods are always paired with a non-bang method. They mark the "more surprising" variant of a pair of methods. If there is no pair of methods, there is no bang. See, for example Array#collect!, which does have a bang because it is the more surprising variant of Array#collect, since it mutates its receiver; however, Array#append does not have a bang even though it also mutates its receiver because there is no corresponding "less surprising" method.
what "m.todo!" and "m.waiting!" are doing? I cannot understand if it is assigning a "true" value or a value that is the opposite of the current one like: m.todo = !m.todo
They do whatever the author of those methods wants. You will have to look that up in the documentation. Those are not methods of the Ruby core or standard library.
I have the following ruby method: a single do iteration without any break, next, or return. Here, cats is an array of cat objects; is_cat_red evaluates to true if cat has a color property of red.
def get_non_red_cats cats
cats.each do |cat|
!is_cat_red?(cat)
end
end
What does the method return (what does the loop evaluate to)?
This is some unusual code and it depends entirely on what the cats method does. You can pass a block to any Ruby method and that method can get executed zero more more times at any point between immediately and the end of the program's execution.
The return value is whatever cats returns, which is not clear from this snippet.
Imagine this in JavaScript terms as that language is a lot less ambiguous:
function get_non_red_cats(cats) {
return cats(function(cat) {
return !is_cat_red?(cat);
}
}
Where this shows that cats is just a function that, potentially, takes a function. It might ignore your function, too.
Now if this is cats.each that changes things as that's probably the Enumerable each method which has well-defined behaviour.
In that case the return value is whatever cats is.
There is no loop in your code. Ruby has two kinds of loops: while and for/in. (Actually, the latter is just syntactic sugar for each.)
In Ruby, an expression evaluates to the value of the last sub-expression evaluated inside the expression. A message send evaluates to the return value of the method that was executed as a result of the message send. The return value of a method is either explicitly the value of the return expression that ended the method execution or implicitly the value of the last expression evaluated inside the method body. (Note that the last expression evaluated inside the body is also what a module or class definition expression evaluates to. A method definition expression however evaluates to a Symbol denoting the name of the method.)
So, what does get_non_red_cats return? Well, there is no return in it, so it returns the value of the last expression evaluated inside the method body. The last expression evaluated inside the method body is a message send of the message each to the object referenced by the parameter binding cats. Ergo, the return value of get_non_red_cats is the return value of the method that gets executed as a result of sending the each message to cats.
And that is all we positively know.
We can make some assumptions, though. In general, each should return self. That's what all implementations of each in the entire core library and standard library do, and it is part of the standard "Iterable" Protocol in Ruby. It would be highly unusual and highly confusing if that were not the case. So, we can assume that whatever implementation of each ends up being executed, it will return self, i.e. the receiver of the message send, i.e. the object referenced by the parameter binding cats.
In other words: the method get_non_red_cats simply returns whatever was passed in as an argument. It is a pretty boring method. In fact, it is the identity method, which is pretty much the most boring method possible.
However, it could have a side-effect. You didn't ask about side-effects, only the return value, but let's look at it anyway.
Since each is supposed to simply return its receiver, it is in some sense also an identity method and thus extremely boring. However, each is generally supposed to evaluate the block it is passed, passing each element of the collection in turn as an argument. But, it ignores the value that the block evaluates to; the block is evaluated purely for its side-effect. Note that each with a block that has no side-effect makes no sense whatsoever. If the block has no side-effect, then the only thing interesting about the block is its value, but each ignores the block's value, and simply returns self.
foo.each do
# something that has no side-effect
end
is fully equivalent to
foo
Another Ruby convention is that message sends that end in a question mark ? should be used for asking questions (duh!) I.e. a message send that ends in a question mark should return something that is suitable to used as a conditional. It also generally shouldn't have a side-effect. (This is called the Command-Query Separation Principle and is a fundamental design principle of Object-Oriented Software Construction.)
And lastly, the ! unary prefix operator, when applied to something that is intended to be used in a conditional (i.e. a boolean value or something equivalent) is generally not supposed to have side-effect. Ergo, since the message send in the block ends with a question mark, it is not supposed to have a side-effect, and the ! operator is also not supposed to have a side-effect, we can assume that the entire block has no side-effect.
This, in turn, means that each shouldn't have a side-effect, and thus get_non_red_cats doesn't have a side-effect. As a result, the only other thing get_non_red_cats can do, is return a value, and it very likely simply returns the value that was passed in.
Ergo, the entire method is equivalent to
def get_non_red_cats(cats)
cats
end
All of this is assuming that the author followed standard Ruby conventions. If she didn't, then this method could do and return anything whatsoever, it could format your harddrive, launch a nuclear attack, return 42, or do absolutely nothing at all.
I have a need to decipher some Ruby code. Being a Python dev, I am having hard time making sense to some of the syntax.
I need to deal with some (mostly clean and readable) Sinatra code. I started with a Sinatra tutorial, and it looks something like this:
get '/' do
"Hello, World!"
end
Now, I know that in Ruby you don't need parentheses to call a function. So if I were to try to understand the above, I would say:
get is a function that takes as its first argument the route.
'/' is the first argument
do ... end block is an anonymous function
Please correct me if I am wrong above, and explain in detail anything I might be missing.
Also they say that Sinatra is a DSL -- does this mean that it is parsing some special syntax that is not official Ruby?
do ... end (or { ... }) is a block, a very important concept in Ruby. It was noticed that very often functions that take other functions as parameter (map, filter, grep, timeout...) very often accept a single function. So the Ruby designer decided to make a special syntax for it.
It is often said that in Ruby, everything is an object. This is not quite true: code is not an object. Code can be wrapped into an object. But Ruby blocks are pure code - not an object, not a first-order value at all. Blocks are a piece of code associated with a function call.
Your code snippet is equivalent to this:
self.get('/') do
return "Hello, World!"
end
The get method takes one parameter and a block; not two parameters. In a hypothetical example where get did take two parameters, we would have to write something like this:
get('/', lambda { "Hello, World" })
or
get('/', Proc.new { "Hello, World" })
but notice that the way we wrap code into objects involves calling methods lambda and Proc.new - and giving them a block (and zero parameters)!
There are many tutorials on "Ruby blocks", so I will not link any particular one.
Because of the block syntax, Ruby is very good at making dialects (still fully syntactic Ruby) that express certain concepts very neatly. Sinatra uses the get... "syntax" (but actually just a method call) to describe a web server; Rake uses task... "syntax" to describe build processes; RSpec, a testing framework, has its own DSL (that is still Ruby) that describes desired behaviours.
After some reading, I understood the code blocks.
Ruby code blocks are simple. They are 'closures'. There's two ways to write a block
do |x|
do_something(x)
end
{|x| do_something(x) }
The |x| is the argument that gets passed to the code within the block.
The crucial bit to grasping code blocks is to understand how they are used with methods.
In Ruby, methods are a bit different.
In addition to arguments, any method can accept a code block.
Code blocks are NOT arguments, but they are a separate entity that can be passed to a method along with arguments
A method can choose not to call the code block, in which case, any code block that was passed is ignored
If a method calls a code block, then it is necessary to pass it when calling the method, or otherwise Ruby will complain.
yield within a method executes the code block
For more on code blocks read this: http://mixandgo.com/blog/mastering-ruby-blocks-in-less-than-5-minutes
Here's a snippet of code from the pickaxe book:
def count_frequency(word_list) counts = Hash.new(0)
for word in word_list
counts[word] += 1
end
counts
end
The counts at the end sets the return value of the method. The value returned is the value of the last calculation.
However, are there not cases where we don't care what the return value of a method is? For example, I have a pair of nested each loops that draw a checkerboard to console. The values of the calculations are fairly meaningless outside the method. I just want a checkerboard drawn.
Is it bad to leave the return value up to circumstance, or should I always be trying to explicitly design methods that return meaningful values?
You don't have to care about the return value if that method is not used as such with a certain expected value. Nothing to worry about.
But for your counts example, returning that value is the whole point of the method. If the method didn't return that value, then it is meaningless, and you definitely need that counts at the end.
There are some cases when the return value is not the main purpose of the method but you still want to return a certain value. One such case is when the method is intended to be used in a jQuery-style method chain like this:
some_object.do_this(args).do_that(args).then_do_this
In such case, it is important that you return the receiver. This happens in certain libraries or frameworks, but unless you specifically intent it to be used that way, you don't necessarily have to do it that way.
No, the return value is not necessary when the method isn't supposed to return a meaningful value, just like most other programming languages.
In fact, one of the most common methods, puts, returns nil.
#puts "hello"
hello
=> nil
No.
In Ruby, every expression returns a value, even if it is just nil. Not just methods; every line you write. In the case of methods, the value returned is the last value evaluated before it exits. The meaning of that value is up to you. If you document that the method has no return value, then even though it does return a value it is undefined; not part of the API and the caller would be wise not to make use of it.
For example, even nil can have proper meaning if you document it; it is often used to signal that a resource could not be found. However, if a method's sole purpose is to perform a side effect like writing to a file, it will probably something that has no real meaning; puts returns nil.
Theoretically, if you document clearly that the return value is meaningless, then you could just incidentally return whatever the last expression in the method happens to evaluate to.
Practically, however, nobody reads documentation, so, if your method does return something, then people will come to depend on it. Also, depending on what exactly it is that you are "accidentally" returning, you might leak private internal implementation details of your method or you might even break encapsulation of your object by e.g. returning the value of a private instance variable.
Take the defined? unary prefix operator, for example. It is specified as returning either a trueish or a falseish value. However, on MRI, it does not just return any trueish value, it actually returns a String describing the kind of expression that is asked about (e.g. 'local-variable', 'method', etc.) And people have become so dependent on this return value that all other Ruby implementations just have to mimic it, even though it is nowhere documented. Now, it turns out that for MRI this information is trivially available, but for JRuby it is not, and keeping this information around incurs a performance penalty.
The E programming language is a purely expression-based language like Ruby or Lisp. Everything is an expression, there are no statements. Everything returns a value. However, unlike those other languages, the implicit return value of a subroutine is not the value of the last expression evaluated inside the subroutine, it is nil. You must explicitly return a value if you want to return something meaningful. That is because the creator of E believes that it is too dangerous to accidentally return something you didn't want. (E is explicitly designed for security, safety, integrity and reliability.)
The following Ruby code
def a(b,c) b+c end
is the same as follows with Python
def a(b,c): return b+c
It looks like that ruby has the special storage(stack or something) that stores the final evaluation result and returns the value when a function is called.
If so, what's the name of the stack, and how can I get that stack?
If not, how does the Ruby code work without returning something?
It's not that magic, Ruby just returns the value returned by the operation that does at the end.
It's synctactic sugar that it's implemented just at parsing level: a statement that calculates something implicitly returns itself without any keyword..
to clarify it a little bit you can imagine both abstract syntax trees of the two snippets: they won't be different.
I don't think it's a stack. The final evaluation of the function is simply the return value, plain and simple. Just your everyday Ruby syntactic sugar.
I don't see any reason why a stack should be required to return a result. A simple pointer to a memory location would be sufficient. I'd guess that would usually be returned in a register, such as EAX.
You get the return value of a function by assigning the function's value to a variable (or doing something else with it). That's the way it was intended to be used, and the only way that works.
Not returning anything is really easy: The called function doesn't put anything into the return location (whatever it may be) and the caller ignores it.
Actually, return is special here, not the standard behavior. Consider:
def foo(ary)
ary.each do |e|
return true if e == 2
end
end
This code actually has more then one stack frame (at least the on for #foo, the one for Array#each and the one for the anonymous function passed to #each). What return does: it does a jump to the stack frame of the outermost lexical scope it is called in (the end of foo) and returns the given value. If you play a lot with anonymous functions, you will find that return is no allowed in all context, while just returning the last computed value is.
So I would recommend never to use return if you don't need it for precisely that reason: breaking and returning from a running iteration.