3

Notice how the while version evaluates the expression, but the if version does not.

begin
  puts 'hi'
  1
end while false
# => hi
# => nil 

begin 
  puts 'hi'
  1
end if false
# => nil 

But if we use an expression without begin ... end it will not eagerly evaluate it.

puts 'hi' while false
# => nil 

Is there a reason for this seeming discrepancy?

jshen
  • 11,507
  • 7
  • 37
  • 59

3 Answers3

3

The begin-end-while (also called do-while in other languages) is supposed to run the block of code at least once (therefore leading to the printing of "hi") and repeat it as long as the condition is met.

while X
    Y
end

is not equal to:

begin
    Y
end while X

The first will never execute the Y block of code if the condition X is never met. The second will, firstly, evaluate the block of code Y once and then will check if the condition X is met: if it is, then it runs the block Y again and again until the condition X evaluates to false.

A normal begin-end-if block, instead, is just considered like any other if block: it will be ignored (or just not executed) if the conditional expression evaluates to false.

if X
    Y 
end

is, instead, equal to:

begin
    Y
end if X

which is the same as:

Y if X
Community
  • 1
  • 1
Shoe
  • 74,840
  • 36
  • 166
  • 272
  • 2
    Your link has a link to Matz saying that he regrets this feature. http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/6745 – jshen Aug 14 '13 at 20:36
  • @jshen, yup, you should use `loop do` instead. – Shoe Aug 14 '13 at 20:45
0

The postfix notation is just a shorthand for having the conditional beforehand. This is "rewritten" by the interpreter for the condition to be beforehand.

However, a do-while loop is its own loop type. It is not just a shorthand for having the while() up front.

xaxxon
  • 19,189
  • 5
  • 50
  • 80
-2

You are assuming that begin .. end is a compound statement, but it isn't, begin starts a region with exception handling and end just marks the other boundary of that region. The contents of the begin...end block are still multiple statements.

Ruby doesn't need compound statements because it has programmer-friendly block terminators. But you can make them with (...), so try something like:

(
  puts 'hi'
  123
) if false
DigitalRoss
  • 143,651
  • 25
  • 248
  • 329