Hello world, err, lövers! My name is Dale James and I'm writing to introduce you to one of my favourite things you can do in Lua, which is called a Ternary Operation.
I grew up playing video games - my first gaming machine was a Commodore 64 (which I still have, somewhere, with a neat collection of tapes). The more games I played, the more I dreamed of being able to produce my own games. Still to this day whenever I play a game I consider how it was built, what works well and how I could improve it. I have no formal education in programming of any sort, except maybe those 2 lectures I attended for ActionScript, but I'm not sure they count as I remember correcting the lecturer several times. I spent countless hours after school messing with lots of (what I now consider to be) awful frameworks and engines, so you could imagine the rush I got when I first discovered the pure awesomeness that is Löve. No other 2D framework comes close to it in terms of elegance, ease of use, and documentation (oh, that documentation!).
This series of articles, dubbed Lövely Code, is intended to focus on the elegance that blossoms from Löve and Lua. Writing elegant code is very rewarding, fun, and it just looks so darn cool! So, on to Lövely Code #01:
This article assumes that you have a basic knowledge of Lua concepts, particularly data types and expressions.
Many readers may not be aware of the concept of a ternary operator or operation. In Lua we have access to several types of operation - unary, binary and ternary.
A unary operation is an expression with a single operand, or a single 'input value'. According to the Lua 5.1 Manual, Lua features three types of unary operators:
a = -1 --negation b = not x --logical negation c = #"purple" --length, works with tables & strings
A binary operation is an expression with two operands. I bet you can see where this is going. There are lots of binary operators so I'll just list a few of them:
a = 1000 + 337 --need I explain this? b = a or 1337 --if a is nil or false then b becomes 1337 c = b > 9000 --c becomes true if b is over 9000 d = a --also binary! e = "some" .. "thing" --concatenation is actually a binary operator
Now here's the fun part.
As you may have guessed, a ternary operation is one that has three operands. "Three?!" you say? "How does that work? ", you ask, or "Prey tell how this most elusive of operations achieves its resolution, old chap", if you're English like myself, of course I wrote this article whilst wearing my best top hat and monocle, curling my mustache, and eating a lime.
It's actually rather simple. A ternary operation is often used as a substitute for an
In C-like languages there does exist an operator for ternary expressions, but Lua being Lua, we are treated to a much more elegant and human-readable method for creating these most wondrous of wonders; a combination of
or operators makes for a beautifully simple ternary operation.
--a simple if/then/else... if a then x = b else x = c end --is equivalent to: x = a and b or c --three operands!
Whoah! What's going on there?! It's actually pretty simple if you break the expression down and evaluate it in the same manner as the Lua VM. If we check the manual for order of precedence we find that
and is always evaluated before
or. We also know that an
and statement outputs the rightmost operand if the left is
true, and that
or outputs the left unless is it
false. Sound confusing? Let's look at this in a way we can all understand.
I recommend opening up a Lua console and following along. Start a new Lua session and try each line in sequence.
x = a and b or c print(x)
Our original statement. This would actually always evaluate to nil since we have not specified
c, so let's give ourselves some sample values to work with.
a = 11 b = "variable b" c = "variable c"
Now, we're going to use the same expression as above. Before you run the command, take a moment to consider what the output will be...
Ready? Then let's try it!
x = a and b or c print(x)
You should see the output
variable b. What happened is that we said "if
x is equal to
b, otherwise it is equal to
c". We did
a = 11, which in Lua means that
if a then will evaluate to
true. Just like a basic
So what happens if
a is not
true? Go ahead, try it:
x = not a and b or c print(x)
This time you should see the output
variable c. Similarly to before, this is because we said "if
not a is
x is equal to
b, otherwise it is equal to
c". This time,
not a evaluates to
false. Allow me to demonstrate what is going on here (there is no need to input this block into your terminal):
x = not a and b or c --equivalent to x = false and "variable b" or "variable c" --equivalent to x = (false and "variable b") or "variable c" --equivalent to x = false or "variable c" --equivalent to x = "variable c" --tada!
Got it now? This is how a ternary expression works. As you can see, it's actually very simple once you understand the nature of
Let's try another example:
x = a < 10 and b or c
Oh my science. Just what is going on there?! Now we have a binary expression embedded in our ternary expression........! Don't be fooled: this is simple stuff. "How can you say that?!" you yell at me. Well, if we consider that our ternary expression is rather like an
if/then/else we see that it is indeed simple stuff (no need to execute this block either):
if a < 10 then x = b else x = c end
That wasn't so painful was it? So now if we go back and output our new
x, what would we see?
You should see
variable c again. This is because our value
a is greater than 10:
a < 10 = false. Go ahead and change the binary expression to use greater-than:
x = a > 10 and b or c
We are all over this now! We know what's going happen here! Our
x is going to equal
variable b, just like you expected.
One important thing to note when writing ternary operations is that the 'middle' operand cannot be
b in our example) ! This is because of the nature of
or. Try it and see what happens.
x = nil and nil or true x = nil or true x = true --or x = true and nil or true x = nil or true x = true
However, if you need this type of operation, you can simply 'invert' the operands:
x = a == nil and b or a --solved. x = a == nil and b == false or a --don't do this!
Congratulations, you just learned how to write ternary expressions!
Throughout this article I have repeatedly stated that this is a simple concept. In reality, it can be hard to understand at first, but once you get it, it becomes a beautifully simple, elegant way to form expressions in your code.
So where exactly should you be using these most excellent operations?
There is no universal answer. Fear not though, for there are guidelines! Try to avoid convoluted ternary statements, after all we write them for our own sake; use them to make your programs more readable, more elegant, more lövely. An interesting example could be for setting a variable based on whether another exists or not (or setting a default), the condition is also the 'middle' operand:
--if statement basis if a then x = a else x = b end --could also be x = a and a or b --this can be further simplified to (and avoids the caveat!) x = a or b --this binary operation tastes great with functions
Code to die for.
For further reading, as always I recommend lua-users.org which is where I learned how to write these, and many other Lua concepts. You may find there that more complex forms of the ternary operation can be written, but they truly are complex and are (waaaaay) beyond the scope of this document.
I hope you have enjoyed this article, the first in the Lövely Code series.