# Variables On the previous page, you learned about data types. They are an essential first half to learning one of the fundamental concepts in any programming language: variables. ## Why Use Variables? When programming, you typically need to store information/data in places. A variable gives you a way to pass and edit this information around, whether it is numbers, text, etc. ## Using A Variable How you use a variable depends on what it is of course. But let's look at an example that utilizes variables: ```rust fn main() { str myText; myText = "Hello World!"; str myOtherText = "This is more text!"; println(myText); println(myOtherText); } ``` Output: ``` Hello World! This is more text! ``` ### Understanding The Code * We declare a variable (named "myText") by specifying its type and then the name of what we will call the variable. Here, we are saying that there is a variable called "myText" and it "is an" `str`. * Using an assignment operator such as `=`, we give the variable a value. * It is also possible to declare and assign a variable at the same time. * After this, we could simply print out those variables. And that is how you declare and use basic variables. You should not think of `=` as the math equals, but rather you are assigning a value to this variable at this point in time. ## Operators What's cool about variables is the fact that you can perform operations on them to either manipulate current variables, or form new values entirely. For example, you can add two number variables together to produce a new number, which you could store in a new variable, store it to an existing one, or even not store it at all and throw the result out of the window. ### General Operators These operators can be applied to any variable(s)/values to produce a new value. | Operator | Name | Usage | Description | | -------- | ---- | ----- | ----------- | | + | Add | a + b | Returns the sum of two items. | | - | Sub | a - b | Returns the difference of two items. | | * | Mul | a * b | Returns the product of two items. | | / | Div | a / b | Returns the result of division of two items. | | % | Mod | a % b | Returns the remainder of the result of the division of two items. | | ** | Exp | a ** b | Returns `a` to the power of `b`. | | .. | Range | a .. b | Returns an iterable item that is defined by the range between `a` inclusive and `b` exclusive. | | ..= | RangeEq | a ..= b | Returns an iterable item that is defined by the range between `a` and `b` inclusively. | | & | BitAnd | a & b | Returns the bitwise and operation of two items. | | \| | BitOr | a \| b | Returns the bitwise or operation of two items. | | ^ | BitXor | a ^ b | Returns the bitwise exclusive or operation of two items. | | ~ | BitNot | ~a | Returns the bitwise not of an item. | | << | Lshift | a << b | Shifts `a` to the left by `b` bits. | | >> | Rshift | a >> b | Shifts `a` to the right by `b` bits. | | + | Pos | +a | Modifies a value with positive (does nothing to a value, usually used to convert a value to a number). | | - | Neg | -a | Modifies a value to be negative. | | ++ | Inc | ++a; a++ | Increment the value of a. | | `--` | Dec | `--a`; `a--` | Decrement the value of a. | | * | Dereference | *a | Given that `a` is a pointer, this will return the value the pointer points to. | | & | AddressOf | &a | Returns a pointer that points to `a`. | | @ | AsAssignableReference | @a | If `a` is a reference, make it so the reference is accessed. | | && | And | a && b | Returns `true` if, and only if, both `a` and `b` are `true`. | | \|\| | Or | a \|\| b | Returns `true` if, and only if, either `a` and `b` are `true`. | | !& | Nand | !& | a !& b | Returns `true` if, and only if, both `a` and `b` are `false`. | | !\| | Nor | !\| | a !\| b | Returns `true` if, and only if, neither `a` or `b` are `true`. | | ! | Not | !a | Returns `true` if, and only if, `a` is `false`. | | == | Eq | a == b | Returns `true` if, and only if, `a` is equal to `b`. | | != | Neq | a != b | Returns `true` if, and only if, `a` is not equal to `b`. | | > | Gt | a > b | Returns `true` if, and only if, `a` is greater than `b`. | | < | Lt | a < b | Returns `true` if, and only if, `a` is less than `b`. | | >= | Ge | a >= b | Returns `true` if, and only if, `a` is greater than or equal to `b`. | | <= | Le | a <= b | Returns `true` if, and only if, `a` is less than or equal to `b`. | | <=> | Cmp | a <=> b | Returns a value based on comparing `a` and `b` (depends on type). A negative result means `a` is less than `b`, zero means the two are equal, and a positive result means `a` is greater than `b`. | | ?: | Cond | a ? b : c | If `a` is `true` return `b`, else, return `c`. | | ?? | False | a ?? b | If `a` is false, return `b`, else, return `a`. | | !? | Success Or Die | a !? b | This is a shorthand for `if (a) toAssign = a; else return a;`. Basically, either the value of `a` is returned if its true or otherwise we exit out of the function and return whatever `b` is. This is useful for propogating errors. If `b` is not present, we return exit the function with `a` instead. | | => | Lambda | a => b | The value of `a` is equal to the result of expression `b`. | | , | Comma | a, b, ... | Form a tuple with `a` in the first element, `b` in the second, etc. Expressions that result in `void` are NOT included. | | . | Dot | a.b | Access member `b` from struct `a`. | | [] | Index | a[b] | Access index `b` from `a`. | ### Assignment Operators These operators are "not static", as in they modify the value of the left-hand variable. All operators are in the form `a {OP} b`. | Operator | Equivalent | | -------- | ---------- | | = | Set `a` to a copy of `b` (copy assignment). | | := | Set `a` to be the new owner of the data in `b` (move assignment). | | += | a = a + b | | -= | a = a - b | | *= | a = a * b | | /= | a = a / b | | %= | a = a % b | | **= | Raises `a` to the `b`th power. | | &= | a = a & b | | \|= | a = a \| b | | ^= | a = a ^ b | | ~= | Flips the bits in `a` specified by `b`. | | <<= | a = a << b | | >>= | a = a >> b | | &&= | a = a && b | | \|\|= | a = a \|\| b | | !&= | a = a !& b | | !\|= | a = a !\| b | | ??= | a = a ?? b | ### Operator Precedence You may have remembered in elementary school learning PEMDAS, or the order of operations (parenthesis, exponents, multiply/divide, addition/subtraction). Asylum also obeys an order of operations, the higher on the table, the higher the precedence (same row is on the same level): | Operators | | --------- | | (x) | | x.y, x++, `x--` | | +x, -x, !x, ~x, ++x, --x, &x, *x, @x, x[y] | | x..y, x..=y | | x ** y | | x * y, x / y, x % y | | x + y, x - y | | x >> y, x << y | | x > y, x < y, x >= y, x <= y, x <=> y | | x == y, x != y | | x & y | | x ^ y | | x \| y | | x && y, x !& y, x !\| y | | x \|\| y | | x ?? y, x !? y | | x ? y : z | | x, y | | x => y | Remember to use parenthesis when in doubt! It makes code easier to read. ### Preserving Data With Operators What happens when you use these different operators on differing or similar types? For example, let's look at the following code: ```rust fn main() { println(5 / 2); println(5.0 / 2); } ``` Output: ``` 2 2.5 ``` What just happened? Well it turns out that since `5` and `2` are both integers, the result must be an integer. This led to the decimal portion being completely ignored! But `5.0` is a floating-point number. Even though `2` is a decimal number, since an operation is being done with an integer and a floating-poing number, the computer will calculate the result that involves losing less information. So for example, an `s32` added with an `s64` will produce an `s64` as it loses less information. Despite the technicalities of floating-point numbers, a floating-point or fixed-point number is always said to be "bigger". ## A More Complex Example As you can tell, there are quite a lot of different operators. Each will be discussed in more detail later, but for now, let's see an example that utilizes some: ```rust // Here we have a function that solves for x = (-b +/- sqrt(b^2 - 4ac)) / 2a, which is better known as the standard quadratic formula. // It is also worth noting that we are allowed to return multiple values at once in a tuple as shown: fn quadraticFormula(float a, float b, float c) -> float, float { float innerPart = b * b - 4 * a * c; // Calculate the interior part of the square root. innerPart **= 0.5; // Apply the square root by raising to the .5th power. return -b + innerPart, -b - innerPart // Return the final results (the comma creates a tuple that is returned). } ``` ## Access Modifers Before we learn about custom data types using structs, we first must learn about access modifiers: | Modifier | Name | Functions/Members Recognizable Outside Of Namespace | Member Accessible Outside Of Struct | Member Accessible By Derived Structs | | -------- | ---- | --------------------------------------------------- | ----------------------------------- | ------------------------------------ | | pub | Public | Yes | Yes | Yes | | pro | Protected | No | No | Yes | | pub pro | Public Protected | Yes | No | Yes | | pri | Private | No | No | No | Do not worry too much if these are confusing for now. They will be used in practice by this walkthrough later. For now, just know that `pub` is short for `public`, `pro` is short for `protected`, etc. and that the default accessibility of any function or member is `pub`. ## Struct Variables Remember structs from earlier? What if we actually wanted to use them? We can define a variable that "is" our struct like we define any other variable. We could then access the members of our `struct` by using a `.`: ```rust struct Color { byte red; byte green; byte blue; } struct Car { pub str licensePlate; // Specifying accessibility for an item. Of course this is redundant here. pub Color rgbColor; pub: // Specifying accessibility for members that follow. int year; str model; } fn main() { Car car; car.licensePlate = "TOY1234"; car.rgbColor.red = car.rgbColor.green = 70; // You can set multiple variables to the same value too! car.year = 2017; } ``` But what happens to the variables we did not set? In Asylum, the rule of thumb is that everything is inialized to either be `0`, empty, or whatever the default value is if it exists: ```rust println(car.model); println(car.rgbColor.blue); ``` Output: ``` 0 ``` The first line is an empty line if that is not clear. ### Initialization Of course, setting the initial variables the above way is a little messy. Luckily, there is a shorthand using curly brackets for such: ```rust fn main() { Car car = Car { licensePlate: "TOY1234", rgbColor: Color { red: 70, green: 70 }, year: 2017 }; } ``` This above code is equivalent, and much cleaner. ## Challenges 1. Make a program that prints the sum of two variables to produce "Hello World!". 2. Initialize the `Color` struct in both ways to both produce white (white has red, green, and blue set to 255). 3. Create a function to solve for `c` in the Pythagorean Theorem (`a^2 + b^2 = c^2`). 4. What is the result of `8 / 3`? 5. What is the result of `4 * (2 + 1) % 3`? ## Challenge Solutions * [Solution 1](solutions/variables1.md) * [Solution 2](solutions/variables2.md) * [Solution 3](solutions/variables3.md) * [Solution 4](solutions/variables4.md) * [Solution 5](solutions/variables5.md)