# Litt's Lua Laboratory:Lua If Statements (With Snippets)

Copyright (C) 2011 by Steve Litt

See the Troubleshooters.Com Bookstore.

# Introduction

Every computer language has if statements. That's the main way to implement branching. Branching is the jumping to different code depending on some variable or condition.

# If Statement Basics

Lua if statements are pretty simple. The simplest look like this:
`if boolean_expression_evaluates_true then   do_this_code()end`
So only if the boolean expression evaluates true do you do the code. The words if, then and end are keywords. Words if and then delineate the condition to be evaluated for truth or falsehood, while words then and end delineate the code to be run if the condition is true, assuming there are no else or elseif keywords, which are discussed later.

Remember there are only two values in the Lua world that are false: boolean false and nil. Any other value evaluates true.

So what is a boolean expression? It could be almost anything, but here are a few:
• Boolean variable: if continue_flag then whatever end
• Boolean expression: if lineno >= first_good_lineno then whatever end
• Bool expression with negation: if not continue_flag then break end
• Compound bool expression: if bux < 30 and status="basic" then reject_order() end
• Function returning bool: if cust_hasnt_paid() then send_notice() end
• Test for nil in var or fcn return: if not bux then no_money_error() end

# Relational Operators

 == Equal ~= Not equal <= Less than or equal >= Greater than or equal < Less than > Greater than

 Operator Precedence From lowest to highest (from loosest to tightest binding) or Logical or:  Loosest binding and Logical and `< > <= >= ~= ==` Relational operators less than, greater than, less than or equal, greater than or equal, not equal, equal `..` String concatenation `+ -` Arithemetic add and subtract `* /` Arithmetic multiply and divide `not - (unary)` Boolean not and arithmetic unary minus ^ Exponentiation: tightest binding

The way you evaluate an expression is to start at the left and read to the right, and imagine parentheses around the things with tighter precedence. For instance:
 a * 2 + 3 < a + 3 * 4 or a < 25 and a < a * 5 - 4 Original expression (a * 2) + 3 < a + (3 * 4) or a < 25 and a < (a * 5) - 4 * is highest precedence, tightest binding in the expression, so start by putting parentheses around all * ((a * 2) + 3) < (a + (3 * 4)) or a < 25 and a < ((a * 5) - 4) + and - are next highest precidence, so put parentheses around them (((a * 2) + 3) < (a + (3 * 4))) or (a < 25) and (a < ((a * 5) - 4)) Relationals are the next highest priority, so enclose them in parentheses (((a * 2) + 3) < (a + (3 * 4))) or ((a < 25) and (a < ((a * 5) - 4))) And is the next highest, so enclose both sides of the and in parentheses ((((a * 2) + 3) < (a + (3 * 4))) or ((a < 25) and (a < ((a * 5) - 4)))) Last but not least, well, actually yes the least, is or, so put parentheses around both sides of the or. This last set of parentheses enclose the entire expression, so you know you're done.

Precedence is important. Run this program:
`#!/usr/bin/lua print(true or false and true and false)        -- prints trueprint(true or ((false and true) and false))    -- means same as above, prints trueprint((true or false) and (true and false))    -- prints false`
The first statement above uses precedence to decide what to do next. The second statement uses parentheses to explicitly direct Lua to do the same thing as precedence would make it do. The third statement strongarms it away from what precedence would normally indicate, and changes the result.

Unlike C, the combination of Lua precedence rules plus Lua language rules make it likely that you can do what you want without parentheses, but they're always available in case you need them.

# Else and Elseif

A basic if statement takes action only if something is true. But what if you want to take different actions depending on its truth? Then you need an else:
`if boolean_expression_evaluates_true then   do_this_code()else   do_other_code()end`
What if you want to take different actions depending on several boolean statements. Or putting it another way, what if a variable can take on several different values and you want to perform different actions depending on the variable? Watch this:
`if contribution < 20 then   membergroup = "Fan"elseif contribution < 100 then   membergroup = "Supporter"elseif contribution < 500 then   membergroup = "Silver"elseif contribution < 2000 then   membergroup = "Gold"elseif contribution < 5000 then   membergroup = "Platinum"else   membergroup = "Cornerstone"end`
Occasionally you might have elseif without else. For instance:
`if breed = "collie" then   print "Big and fluffy"elseif breed = "greyhound" then   print "Fast"elseif breed = "pug" then   print "Cute"end`
In the preceding, you want to take action for collies, greyhounds and pugs, and take no action on other dogs.

If you're anything like me, you code if statements in a paranoid way. For instance:
`if a < b then  return -1elseif a == b then  return 0elseif a > b then  return 1else  io.stderr:write("Internal error, aborting!")  os.exit(1)end`
Now both you and I know  that a must either be less, equal or more than b, any other situation is clearly impossible, so it's kind of silly to include that last else clause. That's nice, but let the programmer who has never come across an impossible situation cast the first stone. Personally, I often find value in coding for the impossible for the same reason my keyboard has a backspace key -- I sometimes make mistakes.

# Local Variables Within If Statements

Consider the following extremely contrived code:
`if contribution < 20 then   local membergroup1 = "Fan"   return membergroup1elseif contribution < 100 then   local membergroup2 = "Supporter"   return membergroup2elseif contribution < 500 then   local membergroup3 = "Silver"   return membergroup3elseif contribution < 2000 then   local membergroup4 = "Gold"   return membergroup4elseif contribution < 5000 then   local membergroup5 = "Platinum"   return membergroup5else   local membergroup6 = "Cornerstone"   return membergroup6end`
In the preceding code, membergroup3 was in scope only from its declaration until elsif contribution < 2000 then. In general, you figure out your local's scope by finding the smallest block bordered on top by then, do, elseif, else or repeat, and bordered on the bottom by a matching end, elseif, else or until. If there are contained blocks between the local's declaration and the end of its block, it's visible in those contained blocks.

# Short Circuit Logic

Within the rules of precedence, Boolean statements execute left to right until the result is inevitable. The fact that evaluation stops when the result is inevitable enables you to do some fancy programming called short circuit logic, sometimes called short circuit evaluation. The following is a simple and classic use of short circuit logic:
`local myname = tempname or "default"`
In the preceding, if tempname contains a string, you assign the tempname to myname, and evaluate the whole expression. Because the whole expression is a single or, tempname is true unless it is nil, and if tempname is true then obviously the whole or clause is true, and evaluation stops. But if tempname is nil then it evaluates false, the value of the whole expression is still in doubt, so the "default" is evaluated and passed on to myname. This is an often used idiom to handle defaults.

Now here's one with hair and teeth:
`local handle = io.open("junk.jnk", "r") or not print("open failed") and os.exit(1)`
There are better ways to do the preceding -- it's just being used as an example of how short circuit logic can be used to actually perform actions.

The first thing that's done is the io.open(), and it can succeed or fail. If it succeeds it returns a file handle. If it fails it returns nil.

If it returns nil, then the entire expression, which is one big  or with  an embedded and on the right, is in doubt, and will be until the embedded and on the right is evaluated.

So now you go to evaluate the and statement. The print command always succeeds (unless perhaps there's some rare, horrible and unpredictable problem), but it's preceded by not to make it false, so the and is still in doubt and evaluation continues to the os.exit(1), which exits the program.

So the whole expression either gets a handle for file junk.jnk or prints an error message and exits the program. Obviously you'd be better off using the assert() command or explicit code with an if statement. This code was contrived just to demonstrate use of short circuit logic to do work rather than just to set a variable.