Many times you want to use a bit of basic logic to determine what to do. Usually you want to compare two values to see if some relationship between them is true. Based on the result of this comparison, you want to do one thing or another. This is where the logic operators come in handy. There are several functions that all act relatively the same in the BasicLogic class. Essentially, they compare certain values, then return a boolean.
Note: The examples in this tutorial primarily use operators, see the page on Operators for a refresher, if the operators are unclear.
Let's take the
lt() function into consideration (
lt returns true if the value on the left is less than the value on the right. In a typical
algebra class, when comparing two numbers, you would write something like this:
x < y
Assuming x is 3 and y is 4, this statement is true. However, if we swap the values, and make x 4 and y 3, the statement is false. Written in code, it would look like this:
All the functions in the BasicLogic class return a boolean based on certain conditions. You should be familiar with the lt (less than
lte (less than or equals to
<=), gt (greater than
gte (greater than or equals
from a basic algebra class that covers inequalities.
Some of the functions you may not have seen before if you haven't taken a logic or programming class are the boolean logic operators. For a full discussion of boolean logic, you may wish to read up on wikipedia for more information, however a basic treatment is covered below.
The three main operators: and (
&&), or (
||), and not (
are the building blocks for more complicated logic statements.
These functions deal with the overall truth value of a construct, not individual bits (see the bit_and and bit_or functions).
&&) returns true if all the parameters resolve to true:
||) returns true if any of the parameters are true
!) returns the opposite truth value of the parameter:
xor() returns true if both parameters are different
For convenience, there are also the nand, nor, xnor functions, which are equivalent respectively to not(and()), not(or()), and not(xor()).
The three bitwise functions bit_and, bit_or, and bit_not work similarly to
not, but they only work with integers, and they work on a
binary level to determine the bitwise equivalent of two or more integers, and return that integer.
Again, a full discussion of how bitwise operations work is beyond the scope of this article, but some examples are below:
Bitwise operations are useful for storing many boolean values as a single integer, among other uses. It may be useful to note that integers are stored as 64 bit two's compliment values.
urshift are also available. lshift(value, bitsToShift) is the general format for all three.
Now that we have established that some conditions are true or not, we may want to do different
things depending. This is where the
if() function comes in. We are creating "code branches"
when we use if and other conditional statements, which means that sometimes code will not get run.
The syntax of the if statements is as follows:
The condition and code to run if true are required, but the code to run if false ("else") is optional. If it is left off, and the condition is false, void is returned. Only one branch of code is executed here. If condition resolves to true (which may itself contain more complex code), then the second argument is evaluated and returned, otherwise the third argument is evaluated and returned. Note that the other code branch is not even evaluated, that is, it is skipped entirely.
The "old style" of if was a fully functional syntax, though that syntax is still useful for ternary statements. In most languages, this is the condition ? true : false syntax.
if technically returns a value. If
the value in each block is a single, returning value, that value will be returned. As a convention, only if a
ternary operator is desired should you use the functional syntax. The following code works as expected:
If the @condition is true, then 1 is assigned to @var, otherwise 2 is.
Truth value testing
The following are considered to evaluate to true:
- The keyword and boolean value
- Any non-empty string
- Any number different from 0
Anything else, including arrays, are considered false.
if/else if/else chains can be formed as well, if multiple conditions need to be checked. Using only if/else would quickly get messy if you have multiple values to check for. Instead, you may use the else if chain.
In this usage, the
vals will be evaluated from top to bottom, and once the first val is true,
the corresponding code will be run. If none of the vals are true, then nothing in the chain will run.
In this usage, we can imagine a "default" case. If at least one of the
is true, then it will behave the same. However, if none of the vals are true, then the
final code block will be run instead. This is the final "else" clause of the statement.
ifelse() function is the non-brace way to do if/else if/else chains, though
its usage is not recommended, as it is less readable. Internally, if/else if/else chains are
converted to it still, however.
A switch statement works by simplifying comparisons. Unlike if/else if/else, switch checks to see if some value is equal to another value, then running that code, instead of just seeing if the value itself is true. Switch statements can actually be written using if chains, so to demonstrate, here is the same code written both ways:
As you can see, it's a bit less code using the switch statement, but the results can be achieved either way. Sometimes you may want to do a different type of comparison, other than equals, so you have to use if/else if/else chains. As with if/else if/else chains, a "default" condition can be stated, in the event none of the given conditions are satisfied. When possible, however, switch statements should be used, as they can be better optimized by the compiler.
Sometimes you may want to run some code given that the value equals one of any number of values. In this case, you may specify multiple cases, and if the value equals any of the values specified, the corresponding code is run.
Though you can technically use non-string and non-integer values as the comparison types, it is not recommended, and in fact, arrays may not be used at all. When writing code, you should only use integers and strings whenever possible.
Slices may also be used, and if so, if the test value falls within the range of the slice, that code block is run.
Unlike many other languages, no
break() is strictly necessary. Code blocks are run starting with the case statement,
running until the next case. Only if a case should be ignored must you use break(), otherwise code will merge with the following case.
For instance, say we want nothing to happen should the value = 2.
Had we left the break() out, case 2 and the default case would have merged together. In all other cases, break() is optional.
Using break() is still recommeneded however, even though it is technically optional. Consider the following example.
In this example, if @v is 1, we msg out 1, and if @v is 2, we message out 2. Consider however, if we comment out line 3,
msg('1'). We might expect that the code
simply won't message anything at all if @v is 1. This is incorrect. Due to the way fallthroughs work, it will simply change it to a combined case 1 and 2. We can
add a bit more code to ensure that this won't happen:
Now, if we comment out
msg('1'), as expected, nothing happens when @v is 1.
switch also has a pure functional syntax, but it is not recommended for use in new code.