Does using curly braces go against the "Ruby way"? - ruby

I've been using Ruby for about two weeks, and I've not been programming for too terribly long, but I'm coming at the language from a C-style background (C++, C#, etc). Anyway - a good friend and mentor of mine was looking at some Ruby that I'd written the other day, and he told me that he'd smack me if he caught me using curly braces in Ruby again.
Well, I just found out about Builder yesterday, via this About.com article, and the example that they have posted uses curly braces. Is there a different way to do this, or do you have to use curly braces with Builder?
This may seem like a minor point, but I'm new to Ruby, and I don't want to let myself develop any bad habits. What do you guys think?

While some people go with "braces for one-liners, do-end for multi-liners", I personally find the following rule the most logical:
use do-end when your block has side-effects (typically, with each and related methods) and
use braces when your block is without side-effects (map, inject and alike)
This logic goes well with method chaining issue that Matt wrote about.
One benefit of this approach is that it is going to make you think about side-effects every time you write a block, and they are very important, although sometimes overlooked by coders with no functional programming background.
Another way to put it, without involving side-effects terminology would be:
use do-end for blocks that perform
use { and } for blocks that return
Here are couple of articles with more info:
http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc
http://talklikeaduck.denhaven2.com/2007/10/02/ruby-blocks-do-or-brace

Idiomatic ruby is
method_name {|param| param.do_something} # squigglies for one liners
# do/end for multi-line
method_name do |param|
param.do_something
end
One reason for this is for chaining, foo.map {|f| f.num}.reduce(0) {|memo, i| memo + i} looks nicer then hanging a method call off of an end like
foo.map do |f|
f.num
end.reduce(0) do |memo, i|
memo + i
end
There is just something strange about calling a method off of end, even though syntactically the two are equivalent.

The usual convention is { ... } blocks for one-liners and do ... end for multi-liners. I generally follow this convention but should I ever be king I think I would use do .. end more often.
An occasional issue with {} is that {} binds more tightly than do end so the only way to write a poetry-mode block for a method that also has parameters is to use do end, otherwise the block will be part of the parameter and will not be not passed directly to the method.
def f x
yield x
end
f 123 do |n| p n end # works
f 123 { |n| p n } # does not work
f(123) { |n| p n } # works, of course
Of course, if you wanted to attach a block to a parameter in poetry mode, then you win with {} followed by do end.
def g ; p ['g', yield] end
def f x; p ['f', yield] end
f g { 2 } do 3 end
["g", 2]
["f", 3]
Finally, and contrary to some of the advice you have received here, a ; is not needed before end.

"The Ruby way" doesn't advocate any specific style. If they didn't want you to have the option to use curly braces, it wouldn't be in the language. That said, conform to your team's coding style (if you're working with a team).
Most Ruby code I've seen uses end in place of curly braces, but I don't use Ruby so I can't say for sure that this is the preferred style. Ruby has more than one way of doing things -- you can use whichever way pleases you (within reason).

Related

Handle ARGV in Ruby without if...else block

In a blog post about unconditional programming Michael Feathers shows how limiting if statements can be used as a tool for reducing code complexity.
He uses a specific example to illustrate his point. Now, I've been thinking about other specific examples that could help me learn more about unconditional/ifless/forless programming.
For example in this cat clone there is an if..else block:
#!/usr/bin/env ruby
if ARGV.length > 0
ARGV.each do |f|
puts File.read(f)
end
else
puts STDIN.read
end
It turns out ruby has ARGF which makes this program much simpler:
#!/usr/bin/env ruby
puts ARGF.read
I'm wondering if ARGF didn't exist how could the above example be refactored so there is no if..else block?
Also interested in links to other illustrative specific examples.
Technically you can,
inputs = { ARGV => ARGV.map { |f| File.open(f) }, [] => [STDIN] }[ARGV]
inputs.map(&:read).map(&method(:puts))
Though that's code golf and too clever for its own good.
Still, how does it work?
It uses a hash to store two alternatives.
Map ARGV to an array of open files
Map [] to an array with STDIN, effectively overwriting the ARGV entry if it is empty
Access ARGV in the hash, which returns [STDIN] if it is empty
Read all open inputs and print them
Don't write that code though.
As mentioned in my answer to your other question, unconditional programming is not about avoiding if expressions at all costs but about striving for readable and intention revealing code. And sometimes that just means using an if expression.
You can't always get rid of a conditional (maybe with an insane number of classes) and Michael Feathers isn't advocating that. Instead it's sort of a backlash against overuse of conditionals. We've all seen nightmare code that's endless chains of nested if/elsif/else and so has he.
Moreover, people do routinely nest conditionals inside of conditionals. Some of the worst code I've ever seen is a cavernous nightmare of nested conditions with odd bits of work interspersed within them. I suppose that the real problem with control structures is that they are often mixed with the work. I'm sure there's some way that we can see this as a form of single responsibility violation.
Rather than slavishly try to eliminate the condition, you could simplify your code by first creating an array of IO objects from ARGV, and use STDIN if that list is empty.
io = ARGV.map { |f| File.new(f) };
io = [STDIN] if !io.length;
Then your code can do what it likes with io.
While this has strictly the same number of conditionals, it eliminates the if/else block and thus a branch: the code is linear. More importantly, since it separates gathering data from using it, you can put it in a function and reuse it further reducing complexity. Once it's in a function, we can take advantage of early return.
# I don't have a really good name for this, but it's a
# common enough idiom. Perl provides the same feature as <>
def arg_files
return ARGV.map { |f| File.new(f) } if ARGV.length;
return [STDIN];
end
Now that it's in a function, your code to cat all the files or stdin becomes very simple.
arg_files.each { |f| puts f.read }
First, although the principle is good, you have to consider other things that are more importants such as readability and perhaps speed of execution.
That said, you could monkeypatch the String class to add a read method and put STDIN and the arguments in an array and start reading from the beginning until the end of the array minus 1, so stopping before STDIN if there are arguments and go on until -1 (the end) if there are no arguments.
class String
def read
File.read self if File.exist? self
end
end
puts [*ARGV, STDIN][0..ARGV.length-1].map{|a| a.read}
Before someone notices that I still use an if to check if a File exists, you should have used two if's in your example to check this also and if you don't, use a rescue to properly inform the user.
EDIT: if you would use the patch, read about the possible problems at these links
http://blog.jayfields.com/2008/04/alternatives-for-redefining-methods.html
http://www.justinweiss.com/articles/3-ways-to-monkey-patch-without-making-a-mess/
Since the read method isn't part of String the solutions using alias and super are not necessary, if you plan to use a Module, here is how to do that
module ReadString
def read
File.read self if File.exist? self
end
end
class String
include ReadString
end
EDIT: just read about a safe way to monkey patch, for your documentation see https://solidfoundationwebdev.com/blog/posts/writing-clean-monkey-patches-fixing-kaminari-1-0-0-argumenterror-comparison-of-fixnum-with-string-failed?utm_source=rubyweekly&utm_medium=email

Is it possible to write a single-statement for loop in two lines with Ruby?

Often when programming in Ruby, I find myself writing small for loops with a single statement in the body. For example...
for number in 1..10
puts number
end
In other languages like C, Java or Kotlin (for example), I'd be able to write the same code in two lines. For example...
// Kotlin
for (number in 1..10)
println(number)
In the above example, the ending of the loop body is inferred due to the lack of curly braces.
Does Ruby have a way to imitate this "single-statement" style of "for loop"?
Here are some of [my options/your potential replies], along with my thoughts on them.
You could append ; end to the body to end it on the same line.
This is true, and pretty sufficient, but I'd like to know if there's a more idiomatic approach.
This seems unnecessarily picky. Why would you ever want to do this?
You may think I'm being too picky. You may also think what I'm trying to do is un-idiomatic (if that's even a word). I totally understand, but I'd still love to know if it's do-able!
Doing this could let us write code that's even just a tiny bit nicer to read. And for programmers, readability matters.
Sure, you're looking for each, Range#each in this particular case:
(1..10).each { |number| puts number }
For more complex iterations use do - end block syntax. For example
(1..10).each do |number|
puts number
some_method_call(number)
Rails.logger.info("The #{number} is used")
something_else
end
To find more check out Ruby documentation, in particular, see Enumerable.
There is a vanishingly tiny number of cases, where any self-respecting Ruby programmer would even write an explicit loop at all. The number of cases where that loop is a for loop is exactly zero. There is no "more idiomatic" way to write a for loop, because for loops are non-idiomatic, period.
There is an even shorter syntax.
If you are just calling one method on each object you can use & syntax.
(1..3).collect(&:odd?) # => [true, false, true]
This is the same as
(1..3).collect { |each| each.odd? } # => [true, false, true]
This is the preferred way of writing loops in Ruby.
You'll quickly get used to both & and {} block syntax and the enumeration methods defined in Enumerable module. Some useful methods are
each which evaluates the block for each element
collect which create new array with the result from each block
detect which returns the first element for which block results true
select which create new array with elements for which block results true
inject which applies "folding" operation, eg sum = (1..10).inject { |a, b| a + b }
Fun fact, style guides for production code usually ban for loops at all because of a subtle but dangerous scoping issue. See more here, https://stackoverflow.com/a/41308451/24468

Best practices in Ruby for loop

I came across three ways of writing a loop.
the_count = [1, 2, 3, 4, 5]
for loop 1
for number in the_count
puts "This is count #{number}"
end
for loop 2
the_count.each do |count|
puts "The counter is at: #{count}"
end
for loop 3
the_count.each {|i| puts "I got #{i}"}
Are there situations in which one way is a good practice or better solution than the other two? The first one is the most similar to the ones in other languages, and for me, the third one looks unorderly.
The first option is generally discouraged. It is possible in ruby to be more friendly towards developers coming from other languages (as they recognize the syntax) but it behaves a bit strange regarding variable visibility. Generally, you should avoid this variant everywhere and use only one of the block variants.
The advantage of the two other variants is that it works the same for all methods accepting a block, e.g. map, reduce, take_while and others.
The two bottom variants are mostly equivalent You use the each method and provide it with a block. The each method calls the block once for each element in the array.
Which one you use is mostly up to preference. Most people tend to use the one with braces for simple blocks which don't require a line-break. If you want to use a line-break in your block, e.g. if you have multiple statements there, you should use the do...end variant. This makes your code more readable.
There are other slightly more nuanced opinions on when you should use one or the other (e.g. some always use the braces form when writing functional block, i.e. ones which don't affect the outside of the block even when they are longer), but if you follow this above advice, you will please at least 98% of all ruby developers reading your code.
Thus, in conclusion, avoid the for i in ... variants (the same counts for while, until, ...) and always use the block-form. Use the do...end of block for complex blocks and the braces-form for simple one-line blocks.
When you use the the block form, you should however be aware of the slight differences in priority when chaining methods.
This
foo bar { |i| puts i }
is equivalent to
foo(bar{|i| puts i})
while
foo bar do |i|
puts i
end
is equivalent to
foo(bar) { |i| puts i }
As you can see, in the braces form, the block is passed to the right-most method while in the do...end form, the block is passed to the left-most method. You can always resolve the ambiguity with parenthesis though.
It should be noted that this is trade-off between idiomatic Ruby (solutions 2 and 3) and performant Ruby (using while loops, because for …in uses each under the hood) as pointed out in Yet Another Language Speed Test: Counting Primes:
Notably, it should be mentioned that writing idiomatic Python and Ruby results in much slower code than that used here. Ranges bad. While loops good.
While it's generally encouraged to opt for idiomatic Ruby, there are perfectly valid situations where you want to ignore that advice.

When, if ever, to use the Ruby keyword "for"

I personally like to iterate using the for keyword in Ruby since it reads very clean, from my eye. I generally assume that for may be an alias to Enumerable#each, but I do not know whether is is correct. In the most basic example:
for i in (1..10)
puts i
end
behaves the same as
(1..10).each do |i|
puts i
end
just without creating a new variable scope. Moreover, ruby-doc says
The for loop is rarely used in modern ruby programs.
which makes me feel there is a specific, technical reason against the usage. Does it matter that there's no new variable scope? In what way?
behaves the same as
This is incorrect. for is built on top of each, but it is semantically distinct:
array = %w(a b c d)
array.each { |character| }
defined? character # nil
for character in array; end
defined? character # "local-variable"
The for keyword doesn't introduce a new scope. Any variables introduced inside the block remain visible outside of it; as if it was written inline.
You should take this fact into account when you decide which form to use.

Ruby's yield feature in relation to computer science

I recently discovered Ruby's blocks and yielding features, and I was wondering: where does this fit in terms of computer science theory? Is it a functional programming technique, or something more specific?
Ruby's yield is not an iterator like in C# and Python. yield itself is actually a really simple concept once you understand how blocks work in Ruby.
Yes, blocks are a functional programming feature, even though Ruby is not properly a functional language. In fact, Ruby uses the method lambda to create block objects, which is borrowed from Lisp's syntax for creating anonymous functions — which is what blocks are. From a computer science standpoint, Ruby's blocks (and Lisp's lambda functions) are closures. In Ruby, methods usually take only one block. (You can pass more, but it's awkward.)
The yield keyword in Ruby is just a way of calling a block that's been given to a method. These two examples are equivalent:
def with_log
output = yield # We're calling our block here with yield
puts "Returned value is #{output}"
end
def with_log(&stuff_to_do) # the & tells Ruby to convert into
# an object without calling lambda
output = stuff_to_do.call # We're explicitly calling the block here
puts "Returned value is #{output}"
end
In the first case, we're just assuming there's a block and say to call it. In the other, Ruby wraps the block in an object and passes it as an argument. The first is more efficient and readable, but they're effectively the same. You'd call either one like this:
with_log do
a = 5
other_num = gets.to_i
#my_var = a + other_num
end
And it would print the value that wound up getting assigned to #my_var. (OK, so that's a completely stupid function, but I think you get the idea.)
Blocks are used for a lot of things in Ruby. Almost every place you'd use a loop in a language like Java, it's replaced in Ruby with methods that take blocks. For example,
[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value} # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]
As Andrew noted, it's also commonly used for opening files and many other places. Basically anytime you have a standard function that could use some custom logic (like sorting an array or processing a file), you'll use a block. There are other uses too, but this answer is already so long I'm afraid it will cause heart attacks in readers with weaker constitutions. Hopefully this clears up the confusion on this topic.
There's more to yield and blocks than mere looping.
The series Enumerating enumerable has a series of things you can do with enumerations, such as asking if a statement is true for any member of a group, or if it's true for all the members, or searching for any or all members meeting a certain condition.
Blocks are also useful for variable scope. Rather than merely being convenient, it can help with good design. For example, the code
File.open("filename", "w") do |f|
f.puts "text"
end
ensures that the file stream is closed when you're finished with it, even if an exception occurs, and that the variable is out of scope once you're finished with it.
A casual google didn't come up with a good blog post about blocks and yields in ruby. I don't know why.
Response to comment:
I suspect it gets closed because of the block ending, not because the variable goes out of scope.
My understanding is that nothing special happens when the last variable pointing to an object goes out of scope, apart from that object being eligible for garbage collection. I don't know how to confirm this, though.
I can show that the file object gets closed before it gets garbage collected, which usually doesn't happen immediately. In the following example, you can see that a file object is closed in the second puts statement, but it hasn't been garbage collected.
g = nil
File.open("/dev/null") do |f|
puts f.inspect # #<File:/dev/null>
puts f.object_id # Some number like 70233884832420
g = f
end
puts g.inspect # #<File:/dev/null (closed)>
puts g.object_id # The exact same number as the one printed out above,
# indicating that g points to the exact same object that f pointed to
I think the yield statement originated from the CLU language. I always wonder if the character from Tron was named after CLU too....
I think 'coroutine' is the keyword you're looking for.
E.g. http://en.wikipedia.org/wiki/Yield
Yield in computing and information science:
in computer science, a point of return (and re-entry) of a coroutine

Resources