def test
!!session[:test]
end
!! - what does this do? can we remove it and still assume it will work the same?
That would be the double bang (or bang bang).
It's not really an operator in itself. It is really two ! operators together...which performs double negation. It is used to make sure you're working with a boolean value.
The first ! coerces its operand to a boolean value, then negates it. The second ! negates the negated value. The sum effect is to coerce the operand to a boolean type. So if you change it then the method won't be returning a boolean anymore, it will be returning whatever is in the hash for that symbol. Nothing will change if you remove it, but the advantage from using !! is you can't abuse the method call to get the object from the session.
To address your second question, your method will change subtly if you remove the double negation since you'll be returning the object instead of TrueClass or FalseClass.
The !! is generally frowned upon unless you explicitly need boolean values (for example, if you're building out an API). Since Ruby evaluates any non-nil and non-false value as truthy, it's usually safe just to return the object in question so that you can call its methods.
Related
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.
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.)
Sometimes I see methods in Ruby that have "?" and "!" at the end of them, e.g:
name = "sample_string"
name.reverse
name.reverse!
name.is_binary_data?
I was wondering what their purpose is? Are they just syntax sugarcoating?
It's "just sugarcoating" for readability, but they do have common meanings:
Methods ending in ! perform some permanent or potentially dangerous change; for example:
Enumerable#sort returns a sorted version of the object while Enumerable#sort! sorts it in place.
In Rails, ActiveRecord::Base#save returns false if saving failed, while ActiveRecord::Base#save! raises an exception.
Kernel::exit causes a script to exit, while Kernel::exit! does so immediately, bypassing any exit handlers.
Methods ending in ? return a boolean, which makes the code flow even more intuitively like a sentence — if number.zero? reads like "if the number is zero", but if number.zero just looks weird.
In your example, name.reverse evaluates to a reversed string, but only after the name.reverse! line does the name variable actually contain the reversed name. name.is_binary_data? looks like "is name binary data?".
Question mark indicates that the method returns boolean. Already answered here:
What does the question mark operator mean in Ruby?
The bang indicates that the method acts on the object itself. Already answered here:
Why are exclamation marks used in Ruby methods?
In Ruby the ? means that the method is going to return a boolean and the ! modifies the object it was called on. They are there to improve readability when looking at the code.
In contrast to the – I suppose – majority of programming languages ...
Ruby, methods are allowed to end with question marks or exclamation marks.
By convention, methods that answer questions (i.e. Array#empty? returns true if the receiver is empty) end in question marks.
Potentially “dangerous” methods (ie methods that modify self or the arguments, exit! etc.) by convention end with exclamation marks.
From: http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/, Section Funny method names
Beware, this isn't always the case. Take for example, Ruby Array#concat http://docs.ruby-lang.org/en/2.0.0/Array.html#method-i-concat.
Where you can get burnt badly is something like MyActiveRecordModel.column_names.concat([url]). Later calls related to MyActiveRecordModel will try to look for a column of 'url' for MyActiveRecordModel and throw.
Instead you must clone it before doing the concat. Fortunately my test suite caught this one, but.. heads up!
Is the keyword unless the same as if?
When do you use ??
I've seen:
if someobject?
I know it checks against nil correct?
Is the keyword 'unless' the same as 'if' ?
No, it's the opposite.
unless foo is the same as if !foo
if someobject?
I know it checks against nil correct?
No it calls a method named someobject?. I.e. the ? is just part of the method name.
? can be used in methodnames, but only as the last character. Conventionally it is used to name methods which return a boolean value (i.e. either true or false).
? can also be used as part of the conditional operator condition ? then_part : else_part, but that's not how it is used in your example.
unless is actually the opposite of if. unless condition is equivalent to if !condition.
Which one you use depends on what feels more natural to the intention you're expressing in code.
e.g.
unless file_exists?
# create file
end
vs.
if !file_exists?
# create file
end
Regarding ?, there is a convention for boolean methods in Ruby to end with a ?.
This statement:
unless conditional expression
Is the equivalent to:
if not (conditional expression)
In Ruby you can end your method names with a question mark which is normally used to show that it is a boolean method.
With Rails a check against nil would look like this:
someobject.nil?
This calls the nil?() method of the object, which returns true for NilObject and false for anything else.
I think the convention for ?-suffix is to use it when naming a method that returns a boolean value. It is not a special character, but is used to make the name of the method easier to understand, or at least I think that's what the intention was. It's to make it clear that the method is like asking a question: it shouldn't change anything, only return some kind of status...
There's also !-suffix that I think by convention means that the method may have side-effects or may modify the object it is called on (rather than return a modified copy). Either way, the ! is to make you think carefully about calling such a method and to make sure you understand what that method does.
I don't think anything enforces these conventions (I've never tried to break them) so of course you could abuse them horribly, but your fellow developers would not be happy working with your code.
for unless see here: http://railstips.org/blog/archives/2008/12/01/unless-the-abused-ruby-conditional/
if someobject?
The appending of a '?' here only means that it returns a boolean.
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.