Ruby: unless vs if not - ruby

I find myself preferring if not rather than unless. Is there a proper way to write that sort of condition? How do people generally feel about unless?

I hope this helps you: https://github.com/rubocop-hq/ruby-style-guide#if-vs-unless
Prefer unless over if for negative conditions (or control flow ||).
# bad
do_something if !some_condition
# bad
do_something if not some_condition
# good
do_something unless some_condition
I personally agree with what's written there choosing unless something over if !something for modifiers and simple ones and when there's an else prefer if.

I use unless every time, except when there is an else clause.
So, I'll use
unless blah_blah
...
end
but if there is an else condition, I'll use if not (or if !)
if !blah_blah
...
else
...
end
After using if ! for years and years and years, it actually took me a while to get used to unless. Nowadays I prefer it in every case where reading it out loud sounds natural.
I'm also a fan of using a trailing unless
increment_by_one unless max_value_reached I'm using these method/variable names obviously as a readability example - the code's structure should basically follow that pattern, in my opinion.
In a broader sense, the structure should be: take_action unless exception_applies

if not condition is rarely used. Ruby programmers (usually coming from other languages) tend to prefer the use if !condition.
On the other side, unless is widely use in case there is a single condition and if it sounds readable.
Also see making sense with Ruby unless for further suggestions about unless coding style.

Related

Use parentheses to enclose a block in Ruby?

I have accidentally discovered the Ruby idiom of ||=(),
as in:
def app_logger
#app_logger ||= (
logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
logfile.sync = true
AppLogger.new(logfile)
)
end
I tried to use {} instead of (), but it didn't work. I thought {} is meant to enclose a block.
Is this a known idiom? Is it a good style?
I haven't found much documentation on this kind of use of parentheses. Any pointers would be helpful.
Please note this post is about the use of () this way, not the use of ||=. There are many posts about this latter idiom already.
Like a lot of things in Ruby that can be done, many of them shouldn't be done and this is one of them.
Using brackets to group code when there are already other facilities is potentially confusing and almost certainly contrary to many coding style guides. If I saw this in code I was managing, I'd immediately fix it.
What's best is to use the begin/end markers to make it completely clear what's going on:
def app_logger
#app_logger ||= begin
logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
logfile.sync = true
AppLogger.new(logfile)
end
end
A lot of things in Ruby evaluate down to a single value, and the contents of (...) are apparently one of those things.
Your other example of foo ||= (a=10; a+10) being "nicer" is also rather controversial. This does two assignment and addition, but only conditionally. This one would almost always be better written in long-form with begin/end to make it clear that a+10 is the result.
From a style perspective, hiding the "important" part of that, the a+10, at the end of a line is bad, it can be overlooked. Having it as the last line makes it abundantly clear. This is also why having if statements tacked on the end of long lines is also bad, it hides that the line is only conditionally executed.
Concern for brevity is always trumped by concerns of readability. Saving a couple of bytes on disk is not going to help you one bit when, due to someone misreading your code, they introduce a crippling bug.
That someone could be you in the future when you get caught up in your own cleverness. It's happened to all of us at some point.
In addition to #tadman's answer, I'd counter that writing the method in a more Ruby-like way maintains the readability and keeps it nice and tight:
def app_logger
return #app_logger if #app_logger
logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
logfile.sync = true
#app_logger = AppLogger.new(logfile)
end
For my intent and rationale in writing it this way, see my comment to this answer in response to #fotanus's comment.
Our brains become conditioned to see patterns as we learn to program and learn new languages. Whether the patterns are in hexcode emitted by a debugger or C, Perl, Python, Java or Ruby, we still see patterns. When we're used to seeing them we tend to want to change code to resemble those familiar constructs. That's why Perl and C programmers tend to write Java, Python and Ruby like C and Perl at first. The "beauty is in the eye of the beholder", but that same beauty is a weed when it's out of place, just as wild-flowers are out of place in formal gardens or the middle of a fairway. We should write in the vernacular of the programming language, because that is the way of speaking expected by those who live in that land.
Something to remember is, though we, personally, might be a code-studly monster who can reduce code from multiple lines down to a single character, what will keep me in a job is the ability to write code other people can understand, without necessarily having to be of the same caliber. Code crunching invariably reaches a point of diminishing returns, well before it has been reduced to its minimal size, especially when that code is running in a production environment and is being maintained by junior programmers and there is a need to extend or debug it, and the clock is ticking. Minutes = dollars where I work, and the dollars have really big multipliers, which causes the walls to leak managers like cockroaches when a bug-bomb goes off. (Oh... did I call managers cockroaches? Whatever.)
Being called the morning after an event and being thanked for writing code that made it easy for them to debug/fix or amend/extend is a whole lot better than being called at 2:45AM and asked to get online to help. I value my sleep and that of my coding-partners and push for maintainable code as our #1 priority.
That's my $0.02.
Parentheses are really ugly for in my opinion. Why you don't delegate logic behind creating logger to method?
def app_logger
#app_logger ||= instantiate_app_logger
end
def instantiate_app_logger
logfile = File.open(::Rails.root.join(LOG_FILE), 'a')
logfile.sync = true
AppLogger.new(logfile)
end
But I am afraid that it breaks some OOP, your code also. Why AppLoger class can't open file based on passed path and turning syncing on? It will be so much cleaner.

Ruby features that are risky to use

As a Ruby programmer did you feel any time about any feature which is a bit risky to use, may be because of it's strange behaviour? It might be well documented but hard to find while debugging or counterintuitive to remember?
I generally try to stay away from String#gsub!. The doc says "Performs the substitutions of String#gsub in place, returning str, or nil if no substitutions were performed." So if there's nothing to substitute then it'll return nil. Practically I didn't see any use case where this comes handy.
SO, with your experience, is there anything else you'd like to add?
Using return in a lambda, Proc or block. The semantics are well defined, but you will get it wrong, and you will get a LocalJumpError.
The meta programming features of Ruby can be used in very dangerous ways. I've seen code that attempts to runtime-redefine common methods on code classes like String, or Array, and while I can see this being MAYBE acceptable for a tiny temporary script, I don't think it is remotely a good idea in a complex application with many dependancies, or many maintainers.
Well, the most widely abused dangerous feature of Ruby is certainly evaling strings. In vast majority of cases (if not all) it can be avoided using other methods, usually define_method, const_get, const_set etc.
throw/catch (not the same as begin/rescue!) is basically GOTO, and that could be considered to be a risky feature to use in any language.

Should 'if' statement always have an 'else' clause? [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
This may be a religious argument, but it has been debated ad-nauseum here at my work whether all IF statements should include an ELSE clause - even if the ELSE clause only contains a comment stating that it was 'intentionally left blank'.
I have heard arguments for both sides:
The 'For' camp - ensures that the code has actually addressed whether the condition requires an ELSE clause
The 'Against' camp - code is harder to read, adds too much noise
I am interested in any other points of view as I have to resolve this debate with an answer that would satisfy both parties.
Seems like useless typing to me... and a possible cause for confusion. If you don't need it, don't put it!
No. If you don't need to run any code on the else side, you don't need an else clause.
It is clear by the responses here that no one feels an unused else is needed. I have never heard nor read of such a thing. The more important issue before you is dealing with co-workers/developers who somehow believe adamantly that this is how If Then is to be used.
It sounds like you are not the senior person in this scenario so you cannot simply decree it to be so. I suggest asking the "empty else" parties to show where such a process is suggested in a book (blogs don't count) about development. Better yet, in 3 books about development. I have read my share of programming books across programming languages since 1982 and I have never seen such a suggestion.
This way you are not telling them that they are wrong which they could take personally. Instead you are willing to accept such a position but would like to see some documentation. The onus is on them to find the proof. Either they find it or they are left to argue that every programming book ever written is wrong while only they are right.
Good luck.
The golden rule: put it in if it makes your code clearer and easier to understand, and leave it out otherwise. An experienced programmer will be able to make these judgements on a case-by-case basis.
Are you talking about Algol-derived languages?
In Lisp, I'd say yes: every IF should have an else-clause. Otherwise, you should be using WHEN.
As you say, this may be a question of style, but I would not dream of putting in empty else-blocks in my code just because "every if-block should have one". In my opinion, it adds nothing else than some more characters in the code and one more point (of very little value) to spend time on during code reviews.
Requiring an else stinks. Use it when needed. All programmers understand the construct and the implication of a missing else. It's like a pointless comment that echoes the code. It's plain daft IMO.
I tend to use "early if" statements as means of reducing the level of nested braces (or indentation in Python) like so:
if (inParam == null) {
return;
}
if (inParam.Value < 0) {
throw new ArgumentException(...,...);
}
// Else ... from here on my if statements are simpler since I got here.
Of course, .Net 4.0 now has code contracts, which is great! But, most languages do not have that just yet, so "early ifs" (for the lack of better term) are great precisely because they eliminate a number of else clauses and nested ifs. I do not think it is beneficial to have an else clause in high-level languages ... heck, even in assembly! The idea is: if you checked and did not jump, then the condition was false and we can carry on. Makes logical sense to me ...
EDIT: Check out this article as well to see why else clauses are not of much help:
http://www.codinghorror.com/blog/2006/01/flattening-arrow-code.html
"ensures that the codes has actually
addressed whether the condition
requires an ELSE clause"
This is no more true than requiring a catch clause in every method ensures that all possible exceptions has been properly handled.
No. Guard conditions are a great example. You could nest the rest of the method logic in else clauses but it could get ugly really quickly.
Having an "else" with just an empty line of a code comment can usually mean the developer thought-through the condition and has a better idea of what execution path is actually taken at a given time. All recent compilers will remove the "else" and the comment, so you are not slowing software execution.
Unless I am reading the other responses incorrectly, it looks like most folks are objecting to the time it takes to declare their thoughts in the code and would rather just do it.
SQL Server 2000, 2005 at least.
IF 1 = 1
BEGIN
PRINT 'doing something productive'
END
ELSE
BEGIN
--Just sitting here
END
Msg 102, Level 15, State 1, Line 8
Incorrect syntax near 'END'.
You have to have a meaningful statement, which means a dummy assign or return data to client. I suppose I could use WAITFOR DELAY...
Haskell's if is always ternary. So else is mandatory.
if (thereIsSomeThingToDoInTheElse)
{
putAnElseClause();
}
else
{
// intentionally left blank
}
If your code is complex enough that this becomes an issue, you should probably be rethinking your approach to the problem. Break what you're doing down into smaller simpler functions where it should be unbelievably obvious what the if statements are doing.
If you can't break it down into smaller functions, or you find yourself nesting more than one if statement inside another, Using if statements for your conditional logic are probably not a good fit. Consider switches, lookup tables (if the only difference between your conditions is the value of some constant), or decision tables instead.
If you've already done all this, then you are quibbling over something so unbelievably trivial it's hardly worth your time to argue it.
One of the few possible situations where this might be a good idea is where you have several nested if statements, but fewer else clauses. The language will specify which if the else matches, but this may not always be clear to the reader. Of course, where you put content in curly brackets, nesting will be obvious, so there's no ambiguity. This make this a bit of an artificial case, but still possibly worth mentioning. Also, if your code is this complicated, there's probably a clearer way of writing it.
There are situations where using an optional syntax element when not required can improve readability or prevent future errors. A typical case are the brackets around one-sentence conditionals:
Doing
if(foo){
bar
}
instead of
if(foo)
bar
could eventually prevent
if(foo)
bar
dot
I can't really think of any language I know where omitting an unnecessary else can lead to potential errors :-?
there are a lot of "words" telling you the way to programming such as DRY
in this case i'd use YAGNI.. you aint gonna need it..
so following this you shouldn't write the else.
anyhow in my opinion it makes it harder to read and understand the code.. the more you write the harder to understand the code is
edit:
here are the links you requested:
http://en.wikipedia.org/wiki/YAGNI
http://en.wikipedia.org/wiki/Don%27t_repeat_yourself

How to make Ruby's N ends look better?

As I write some scripts, I usually reach a point where my code looks like this :
end
end
end
end
end
end
I don't know about you, but this look very ugly to me. Can something be done about this?
Don't nest your code so much? Refactor to use more methods? Use blocks passed to other routines instead?
Generally speaking, deep nesting is an indicator that a method is getting too complex and should be broken up. It can help for implicit structural documentation too, by naming the inner compound statements according to their refactored methods.
The advice to break up into smaller pieces is good. But if you need a lot of nested blocks like that, you can label the end keywords with comments.
end # End conditional statement
end # End method declaration
end # End class declaration
Still ugly, but at least clearer.
The other options previously mentioned are preferable.
If those inner blocks do something easy to name (and maybe reusable?), why not refactor them into small separate functions ? Then you'd end up with much shorter sequences of end's.
Otherwise another approach is using Python :-)
Try to use small, testable functions. Not only are your functions and more importantly logic easy to test, but your code becomes way more readable.
I have seen nested "{ }" blocks and 4-space soft tabs and:
end;end;end;end
I suppose this saves vertical space, but I don't recommend, The above comments on avoiding deep nesting and commenting your block-ending lines are the valid approaches. Maybe deep nesting is to avoid method call overhead for things that need speeding up, but readability almost always trumps that kind of "optimization"
If you're happy to compile your own Ruby, you could use ennnnnnnd style syntax (link is to RubyKaigi talk). Unfortunately for you, this has been suggested and rejected by Ruby core.

Are there any Ruby language features you avoid?

It seems to me like Ruby has a lot of syntactic flexibility, and many things may be written in several ways.
Are there any language features/syntactic sugar/coding conventions that you avoid as a Ruby programmer for clarity? I am asking about things that you choose not to use on purpose, not stuff you still have to learn.
If your answer is, "I use everything!," do you ever comment code that would be otherwise obvious if the reader knows the relevant Ruby syntax?
[I'm particularly interested in Ruby in a RoR context, but everything is welcome.]
The whole range of "$" globals (see Pickaxe2 pp333-336) mostly inherited from Perl, are pretty ghastly, although I have on occasion found myself using $: instead of $LOAD_PATH.
I generally refrain from going overboard with monkey patching because it could lead to some maintainability and readability issues. It's a great feature if used correctly, but it's easy to get carried away.
The for ... in ... loop. It directly compiles to obj.each (and throws a strange error message accordingly) and is totally unnecessary. I don't even see where it improves readability - if you've been around ruby for more than a week, #each should be natural.
This might be obvious but I generally avoid using eval if there's any alternative.
First off: I'll break many of these rules if it's for a short one-off script, or a one-liner on the command line, or in irb. But most of my time is spent in medium sized or larger scripts or applications. So:
Avoid:
using class << self code block for class methods. It's a cute trick, but no better than def self.foo, and less readable (especially after the first page).
for i in collection: Use collection.each instead.
proc {...}: usually lambda {...} is better.
class variables (e.g. ##foo). They are problematic and can usually be replaced with class-level instance variables without much effort.
Anything that causes a warning, and preferably anything that causes a warning when run via the more strict ruby -w. This is especially important if you are writing a gem to be used by others.
'else' on a 'begin ... rescue ... end' block. Personal preference: It's too much of an edge case and so few people even know it exists or how it works to be worth it.
ObjectSpace and GC. You probably don't need to go there. You definitely don't want to go there.
=begin and =end multi-line comments. Personal preference for line-wise comments. These just annoy the hell out of me.
Use it, but sparingly or as a last resort (and comment it appropriately):
eval (or class_eval, etc) when passing in a string. There are some metaprogramming tricks you just can't do without passing in a string. And occasionally, the string version performs dramatically better (and sometimes that matters). Otherwise, I prefer to send in blocks of actual ruby code for my metaprogramming. eval can be avoided entirely for many metaprogramming tasks.
Adding or redefining methods on classes which were not created by me and may be used by code outside my control; a.k.a. monkey-patching. This rule is mostly for larger codebases and libraries; I'll gladly and quickly make an exception for small one-off scripts. I'll also make an exception for fixing buggy third-party libraries (although you may shoot yourself in the foot when you upgrade!). Selector namespaces (or something similar) would go a long way to make ruby nice in this regard. That said, sometimes it is worth the trouble. ;-)
Global variables (except for classes). I'll even pass in $stdout as a parameter to my objects or methods, rather than use them directly. It makes re-use of the code much easier and safer. Sometimes you can't avoid it (e.g. $0, $:, $$ and other environmental variables, but even then you can limit your usage).
speaking of which, I prefer to limit my usage of the perlish symbol globals entirely, but if they need to be used more than a little bit, then require "English".
break, redo, next, try: Often they make a block, loop, or method much more elegant than it otherwise could be. Usually they just make you scratch your head for a few minutes when you haven't seen that code for a while.
__END__ for a data-block. Excellent for a small one-file script. Unhelpful for a multi-file app.
Don't use it, but don't really avoid it either:
try/catch
continuations
Things I use often, that others might not care for, or I don't see often:
'and' and 'or' keywords: they have different precedence from && and ||, so you need to be careful with them. I find their different precedence to be very useful.
regex black magic (provided I've got some examples in unit tests for it)
HEREDOC strings
One thing I really loathe is "improper" use of {} and do ... end for blocks. I can't seem to find exactly where I learnt the practice myself but it is generally accepted to do {} for single line blocks and do ... end for multiline blocks.
Proper use:
[1, 2, 3, 4].map {|n| n * n }.inject(1) { |n,product| n * product }
or
[1, 2, 3, 4].inject do |n,product|
n = n * n
product = n * product
end
Improper use:
[1,2,3,4].map do |n| n * n end.inject(1) do |n,product| n * product end
or
[1, 2, 3, 4].inject { |n,product|
n = n * n
product = n * product
}
All of which, of course, will execute giving 576
Avoid chaining too many method calls together. It is very common in Ruby to chain methods together.
user.friends.each {|friend| friend.invite_to_party}
This may seem ok, but breaks Law of Demeter:
More formally, the Law of Demeter for functions requires that a method M of an object O may only invoke the methods of the following kinds of objects:
O itself
M's parameters
any objects created/instantiated
within M
O's direct component objects
The example above isn't perfect and a better solution would be something like this:
user.invite_friends_to_party
The example's problem isn't Ruby's fault but it is very easy to produce code that breaks Law of Demeter and makes code unreadable.
In short, avoid features that decreases code readability. It is a very important that the code you produce is easy to read.
begin nil+234 rescue '' end
above syntax is valid, but you should never use it.

Resources