1
\$\begingroup\$

Task: Implement a function which loops from 1 to 100 and prints "Fizz" if the counter is divisible by 3. Prints "Buzz" if the counter is divisible by 5 and "FizzBuzz", when the counter is divisible by 3 and 5.

The instructor gave me the hint, that it's solvable using the ternary operator. Otherwise I would have used an if-then-else approach.

My solution:

def fizz_buzz
 for i in 1...100
 puts i % 3 == 0 ? i % 5 == 0 ? "FizzBuzz" : "Fizz" : i % 5 == 0 ? "Buzz" : i
 end
end

What's your opinion about the approach? Would you still consider it as readable?

I personally consider the readability hard on the border.

Which approach would you prefer and why?

asked Jun 25, 2023 at 9:00
\$\endgroup\$
1
  • \$\begingroup\$ As I envision a dual-if: How would you do if-else? \$\endgroup\$ Commented Jun 26, 2023 at 6:29

4 Answers 4

4
\$\begingroup\$

Ternary statement is cleaner and often faster to comprehend than if/else; especially true for languages with ceremony syntax, such as curly braces. And I like nested ternary statements (or is it singular?) but it's important to format to help the reader with logic flow. Assume the reader knows the operator structure and resist over-indentation resulting eye boggling pseudo if/else.

def fizz_buzz
 for i in 1...100
 puts i % 3 == 0 ? i % 5 == 0 ? "FizzBuzz" : "Fizz" : 
 i % 5 == 0 ? "Buzz" : i
 end
end
answered Jun 26, 2023 at 6:24
\$\endgroup\$
3
  • \$\begingroup\$ (I'd use parentheses rather than multiple spaces to indicate association.) \$\endgroup\$ Commented Jun 26, 2023 at 6:44
  • \$\begingroup\$ hmmm... I hesitate. I've not used parenthesis except as necessary for operator precedence. Here it serves to signal AND and/or OR and that also feels like "wink, wink, I'm an if/ else." I like your suggestion of inline if's better. \$\endgroup\$ Commented Jun 26, 2023 at 7:10
  • \$\begingroup\$ Space update: I think the spacing (see above) does not help. It is too subtle unless the spacing is exaggerated. In any case it doesn't feel like it's adding to understanding. \$\endgroup\$ Commented Jun 26, 2023 at 20:20
2
\$\begingroup\$

No nested if's (and no ternary operators):

def fizzbuzz
 (1..100).each do |n|
 res = ""
 res << "Fizz" if n % 5 == 0
 res << "Buzz" if n % 3 == 0
 res << n.to_s if res.empty?
 puts res
 end
end

With one extra line of code this transforms to a FizzBuzzBazz.

answered Sep 17, 2023 at 21:23
\$\endgroup\$
2
  • \$\begingroup\$ The observation here seems to be "Don't use ternary conditional", but it's not clear why you say that. And I don't get the bit about nested if, since the code under review has no ifs at all. \$\endgroup\$ Commented Sep 18, 2023 at 9:31
  • \$\begingroup\$ This example shows that ifs without nested branching can increase clarity even compared to ternary statements. Further, the Ruby-esque "trailing IF" not only complements clarity but emphasizes the result-value over the condition that emits that value. One could say it coveys a precedence or preference of returnable values. Again it is about what you want to communicate and emphasize about the code. \$\endgroup\$ Commented Jan 21, 2024 at 23:17
2
\$\begingroup\$

In all the cases except the one where performance is a top priority, I'd prefer the most readable approach:

def fizz_buzz
 100.times do |i|
 if i % 3 == 0 && i % 5 == 0
 puts "FizzBuzz"
 elsif i % 3 == 0
 puts "Fizz"
 elsif i % 5 == 0
 puts "Buzz"
 else
 puts i
 end
 end
end

This code immediately tells you that there are 4 cases, you may easily see the conditions for each of them, all the outcomes are clear and the code is still very simple. Other programmers (or future you) will spend almost no time to read and understand it.

Some people will say that this code is not optimal because it does more checks than the required minimum, but that's usually much less important than readability. It'll certainly take several additional nanoseconds, but in most cases it is negligible. For example, in web development (where Ruby is mostly used), typical response times are in tens or hundreds of milliseconds. Developer time, however, costs a lot. Caring about code readability pays

Also, notice that i % 3 == 0 && i % 5 == 0 is the same as i % 15 == 0, but I'd suggest not to make this replacement either, because i % 3 == 0 && i % 5 == 0 is more intent-revealing

I suggest reading "99 bottles of OOP" by Sandi Metz for a deeper perspective on that.

answered Dec 11, 2023 at 20:26
\$\endgroup\$
2
  • 1
    \$\begingroup\$ "... but I'd suggest not to make this replacement either, because i % 3 == 0 && i % 5 == 0 is more intent-revealing" One could also add a comment to explain if one wanted to opt for fewer operations. \$\endgroup\$ Commented Dec 11, 2023 at 21:53
  • 1
    \$\begingroup\$ Right, something like i % 15 == 0 # both 3 & 5 will be even more readable. \$\endgroup\$ Commented Dec 11, 2023 at 22:07
1
\$\begingroup\$

A post just to suggest a different formatting of radarbob's suggestion

def fizz_buzz
 for i in 1...100
 puts i % 3 == 0 ? i % 5 == 0 ? "FizzBuzz" : "Fizz"
 : i % 5 == 0 ? "Buzz" : i
 end
end
community wiki

\$\endgroup\$
3
  • \$\begingroup\$ I never coded ruby in earnest. \$\endgroup\$ Commented Jun 27, 2023 at 18:56
  • \$\begingroup\$ The more one learns of Ruby the more one enjoys it and indeed love it in comparison to others. "Everything is an object" is freeing; syntax is refreshingly clean. \$\endgroup\$ Commented Jun 27, 2023 at 23:30
  • \$\begingroup\$ I'd suggest your format highlights " i % 3"s TRUE : FALSE clauses and my answer emphasizes "I % 3" OR "i % 5". Both good. It's about what you want to say to the reader. \$\endgroup\$ Commented Jun 27, 2023 at 23:37

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.