Variables are a requirement for us to be able to write programs that can do something useful. So let’s try to get an understanding of what they are. But before that, let’s write a bit of code as it’s easier to reason about something you’ve at least seen before.
First, let’s rewrite the program we learned in the last lesson, but using a variable to hold the greeting. Remember to create a new directory and switch into the new directory to create a new file named something that ends in .odin
. In this file, write the following code.
1package main
2
3import "core:fmt"
4
5main :: proc() {
6 greeting := "Hellope!"
7 fmt.println(greeting)
8}
Save the file and try to run it with odin run .
. If you get any errors, go back and fix them and try again until you get it right. Take note of the output. Compare it to the output of the Hellope!
program in the previous lesson. While you are working on this program, you may want to try to change the value of the variable, just to make sure that everything works as you would expect.
That was so simple that we might as well write another little program. This one adds two numbers together and prints out the sum. Variables are used to store the numbers as well as the sum.
|
|
Again, once you have run this program, you could try changing the value of the variables num1
and num2
and see that in each case, the program behaves like you would expect. You could even change the operator from addition to subtraction (-), multplication (*) or division (/). Of course, the variable name sum
isn’t going to be appropriate with the other operators, but that’s a minor detail at this point.
If you do try the other operators, when you get to division, run one test with num1
being 0 (zero), just to see what happens when you try to run this program. Don’t hesitate to try things out and to take note of how the program behaves under different circumstances. If you get behaviors that are wrong or don’t make sense, chances are you are going to have to come back and fix something.
Let’s write a third little program. This one uses a variable to indicate whether or not the user knows Odin and prints a message based on the value of the variable. You will enounter a new construct that we’ll look at in this lesson: the if
statement.
|
|
Once you have run this program and seen the output, try changing the value of the variable from true
to false
and run the program again. What happens? Apart from true
and false
, are there any other values that the variable knows_odin
could possibly take?
What is a variable?
A variable is some location in the computers memory that has been reserved to hold a specific piece of information; the price of a pair of shoes, your age, the exam scores of all students in a classroom, the name of your pet, etc. It is often compared to a box or a jar with a label on it, describing the contents.
The name variable indicates that it is something that can change over time. That is, the value it holds can change.
All variables have three important properties:
- a type
- a name
- a value
Let’s look at what each of these properties means.
Type
You might have heard that computers think in zeros and ones. This is an oversimplification of what’s really happening. Zeros and ones are really just a way we represent two differnt voltage states that flow through differnt parts of the computer: voltage low and voltage high. If we have multiple wires that each carry either voltage low or voltage high and we represent these two states as 0 and 1, then we can combine the states of each wire to form a larger number, like 10100011, just like we can combine digits together to form a larger number in everyday math. From 5, 6 and 9 we can form 569. The difference is that since each wire can only hold one of two states, it means that each digit in our number will consists only of two digits. This forms the basis of the binary system of counting. We can represent any number in our everyday decimal system as a binary number.
So all the memory cells and the CPU only work with voltage states, which we can think of as being the digits 0 and 1. Not a single memory cell will ever hold a letter of the alphabet, an emoji, a part of a picture, a movie or a song. Yet, we type words on our computers, we watch movies, listen to music and so on. So how does that work? It works because the numbers inside the computer are given meaning by software that interprets them. So for instance, the number 67 might be interpreted as a capital letter “C” by a text editor, as a color value of a single pixel in a drawing program or a movie player, as one tiny slice of a sample in a music player. It is the software that provides the context with which to interpret an individual number.
In essence that is what type is. It is a way of interpreting numbers stored in the computers memory, either as numbers or possibly as something else, like text, sound or pictures.
Odin comes with quite a few types built in and makes it possbile for you, the programmer, to create new types as you need them. We are going to look into all the built-in types as well as how to make our own types in later lessons. For now, in order to keep things simple, we are going to restrict our discussion to only three types, all of which have been used in the three programs above. They are: integers (int
), strings (string
) and booleans (bool
). We’ll introduce other types gradually, as we need them.
At this point, just know that integers are numbers, without a decimal point, like 1, 411 and -73.
Strings can hold words, sentences, numbers, special characters, just about anything. You will use them to hold things like names and messages.
Booleans are a type that can only hold one of two values: true
or false
. As you will soon see, booleans are very useful in programming.
There is a lot more that can be said about types, but this should hopefully be enough for now. We’ll dig deeper only when we need to.
Name
Variables are given names to uniquely identify them. Some programmers will refer to them as identifiers for this reason. Just as parents normally give different names to each one of their children, so too does a programmer give different names to each variable, so that they can be called individually.
Value
Every variable has a value. The possible values it can hold is restricted by the type of the variable. So an integer can hold a 2, the number 1277 or -3. However it can’t hold the word “phone”, because that is a string, not an int.
The value of a variable can change over time. It is the only property that can. The other two stay the same.
Why are variables useful?
Hopefully you have a basic understanding of what a variable is by now. But you may have noticed that by using a variable, our “Hellope!” program has actually become one line of code longer. What on earth do we get in return for that increase in size?
The “Hellope!” program will always print the same message. Yes, you can go into the code and change the message but let’s imagine your program prints “Hellope” 100 times. If you wanted to change the message from “Hellope” to “Hello, world!” you would need to change the message in 100 different places! That is very cumbersome and can easily lead to oversight. With a variable however, you would only need to change the message in one place. Not only is this a whole lot easier and more flexible, it also greatly reduces the risk of oversight.
Variables can also be used to store information that comes from outside the program. As an example, say you wanted a program that asks the user to enter some exam scores and calculates the average score and prints it out? You’d need to use variables to store the exam scores the user enters. What if you wanted to pass in the name of a file to your program and have your program analyze that file and tell you how many words the file contains? You’d need to use variables to pull that off.
What if you simply wanted to print out an appropriate greeting based on the time of the day? You’d probably store the current hour in a variable and use a conditional to determine which greeting to use. In fact, let’s give that a little try, shall we?
Assignment
Earlier I mentioned that the value of a variable can change over time. You have seen several examples of the assignment operator :=
. This is used to create a value and give it a value. If you have already created the variable, you use the =
operator instead. Look at the following example.
1package main
2
3import "core:fmt"
4
5main :: proc() {
6 num1 := 3
7 num2 := 4
8 fmt.println(num1 + num2)
9
10 num1 = 5
11 num2 = 1
12 fmt.println(num1 + num2)
13}
On lines 6 and 7 we create two new variables, num1
and num2
and give them inital values. Therefore, we used :=
. However, on lines 10 and 11 we are just giving new values to the already existing variables, so we use =
instead. Pay attention to this, because the Odin compiler will give you errors if you try to recreate an already existing variable or you try to assign a new value to a variable that does not exist.
There is another operator that looks similar that you will soon get familiar with: the equality operator, ==
. This one uses a double equal sign and is used to test if two variables are equal.
Make sure you understand what each of these means:
- The
:=
operator is used to create a variable and give it an initial value - The
=
operator is used to assign a new value to and existing variable - The
==
operator is used to test two values for equality
Getting the current hour
We want to write a program that says “good morning”, “good afternoon”, “good evening” or “good night”, depending on the time of the day. First we need to think a bit about this. What time should be associate with each greeting? And how do we get the current time of the day?
If this were a job for a client, they would normally tell you what morning, afternoon, evening and night means to them. That is what would be called their requirements. Since we are writing this for ourselves, we get to choose. However, we should probably stick to what is conventional. I’ll use the following:
- from 4am to 12pm is morning
- from 12pm to 5pm is afternoon
- from 5pm to 11pm is evening
- the rest is night
As for getting the time, there is a package called core:time
that we can import (like we import core:fmt
to be able to print things to the terminal window). This gives us a procedure called now
that gives us the current date and time and another procedure called clock_from_time
that we can use to extract time components (hour, minutes and seconds). Let’s start off by seeing if these two procedures will do what we want them to. We’re using some concepts that are likely foreign to you. Don’t worry about them for now-We’ll explore them in a later chapter. For now, try the following little program.
|
|
If you run this program it should print out the current hour. And by the way, the procedure clock_from_time
, as we already said, returns hours, minutes and seconds but we only care about the hours. We discard minutes and seconds by putting underscores (_) in place of variable names.
Notice how, just like in the case with core:fmt
, we have to prefix each procedure from the time
package with it’s name? In this case you are only typing it twice, but if this were a longer program where you had to repeat time
a lot more, it might get tedious. Odin allows you to alias the package name. It would look like this:
1package main
2
3import "core:fmt"
4import t "core:time"
5
6main :: proc() {
7 n := t.now()
8 h, _, _ := t.clock_from_time(n)
9
10 fmt.println(h)
11}
We have now aliased time
to t
. This can be useful, but be careful not to create a naming clash with something else. If the variable n
(for now) had been t
(for time) instead, you would have got errors trying to run, due to a naming clash between the package alias and the variable name.
You will want to run the program at least once during the hours between noon and midnight to see if we get the result in 12-hour or 24-hour time. I ran it on my computer at 1:24pm and got the result 13, which is perfect. That makes it much easier to work with. 12-hour time would require us to find out if it’s AM or PM and would get a bit messier.
Now that we know that the first part of the program works, let’s move on to the next part.
Conditionals
We want to print a greeting that depends on the current hour, which is held in the variable h
. To do this we need the help of an if
statement. We will also use if’s trusty sidekick else
to help us fully accomplish our task.
You already know what “if” means. You use it regularly. “If you’re hungry, eat something”, “If it’s cloudy, carry an umbrella along”, etc. If something is the case, then do something. As you can imagine, with programming we’re just going to have to be a bit more formal. What directly follows the if
statement is a condition, which can be either true
or false
, never anything else. (Now you see the use of the boolean type.) After the conditional comes a block (delimited by a pair of “curly brackets” { and }), containing statements to be run only when the condition is true.
Look at the following code:
if age > 17 {
fmt.println("You may enter")
}
We have a variable age
, which holds some value, let’s imagine it holds 29. We enter a conditional which checks if age is greater than 17. Notice that this statement can only be either true
or false
. Try to find a single number for which this statement is either both true and false at the same time or neither true nor false. You won’t find one.
The fmt.println
statement will only run if the conditon age > 17
is true (which in our case it is). Remember in the previous lesson I said that the default order of execution is from top to bottom? Well, here is a case where we can modify the order of execution, depending on the value of the condition. If age were something like 15, the block right after if age > 17
would be skipped.
But wait, what about if we need to print a different message if the condition is not met? This is where else
comes in handy.
if age > 17 {
fmt.println("You may enter")
} else {
fmt.println("Sorry, you can't enter")
}
In the above code, you are guaranteed that exactly one of the two print statements will run. It will never happen that both are skipped or that both are executed. Either one or the other, depending on the current value of the age
variable.
In hour program we need to go a bit further. We have four different times we need to consider. In order to do that, we can add else if
statments, which is basically a way of saying “if the previous condition wasn’t true, what about this one?” We always end with an else
statement, to capture anything that failed all the tests.
Let’s look at how we could build this, bear in mind that from the first part of our program, the hour is stored in a variable simply called h
. If we add the conditional code directly to that program, we have to wait a long time to see that the condition changes. So we’ll write a different program, test our conditional there, and once we are happy with it, we can copy the code over to the main program.
|
|
A few notes about this. The &&
you see is the logical and. It evaluates to true only when both sides also evaluate to true. The >=
should be read as greater than or equal to. So the first conditional reads “if the current hour is greater than on equal to 4 and less than 12”. I tried to write this code in the way that it is as readable as possible.
You could run this over and over again with different values for h (between 0 and 23) to see that it gives you the appropriate greeting in each case. If you get bored of changing the value of h, saving and running again, here is a version that will report the greeting for all the hours. I’m not going to explain the code at this time, take it as a sign of things to come. (I’m convinced that, by now, you can look at the code and more or less figure out what it’s doing.)
|
|
After running the tests, the code seems to work just fine. The final step is to combine what we wrote previously with what we have just done. The result will look like this.
|
|
Go ahead and try it. It may be a trivial program, but it is also dynamic. It doesn’t print the exact same message each time it is run. And if you’re new to programming, that is a big step.
Once you have a good grasp of the basic building blocks, you will soon be writing longer, more complicated programs.
Final words
Now that we are able to write programs that can act on the value of a variable, we don’t want to limit ourselves to just the time of the day. We’d like to be able to act on information that the user will give us. That is what we will tackle in the next lesson, via command-line arguments.
Exercises
You have learned a few more things, so the exercises are gradually becoming a bit more interesting. A few more lessons and you will be able to write some useful programs. In addition to these exercises, as you become more and more familiar with Odin, I encourage you to come up with your own programs as well.
You can find the answers to the exercises here
Exercise 1
Write a program that prints out the current time (hours:minutes:seconds).
Exercise 2
Modify the following program to print out “Well then, would you like something to drink” if the user is not hungry.
|
|
Once you have verified that it works, try changing the value of the is_hungry
variable to true
to make sure the program works as expected.
Exercise 3
The following program is very similar to the one in exercise 2. Notice, however, the ! before the variable in the if statement.
|
|
After running the program, change the value of is_tired
to true and try again. Based on the results you get, can you figure out what the exclamantion mark before the variable name does? You could remove it and see how that changes the program.
Exercise 4
To compare two integers for equality, use two equal signs (==
). With this in mind, write a program that sets an integer variable called num
. Then use if
, if else
and else
to do the following:
- if the number is greater than 15, print "too large"
- if the number is 3, type "fizz"
- if the number is 5, type "buzz"
- if the number is 15, type "fizz buzz"
- if the number is less than 1, print "to low"
- for any other number, print out the number
Remember that the program will try the if
statement first. Only if that condition is false
will it move on to the first if else
. So you will want to plan out the order in which you want to test things. Run the program several times to see that it behaves correnctly for every number from 0 to 16.
Exercise 5
Modify the time-of-day greeting program to use “good day!” sometime between “good morning” and “good afternoon”. I’ll let you decide the hours in which “good day would be appropriate. When you are done, run the program several times to test that it behaves as expected.
Exercise 6
Just like we can use &&
to say that two conditions must both be true (AND), we can use ||
to say that one of two conditions must be true (OR). Use this information to write a program that creates an integer variable called num
and prints out “out of range” if the value of num
is less than 20 or greater than 40. When you are done, test the program with the following values to ensure that it behaves according to specification:
- 17
- 20
- 33
- 40
- 78
Exercise 7
Write a program that stores the current minute count in a variable. Then print “The hour just started” if minutes is less than or equal to 10 or “We are close to the end of the hour” if minutes is greater than or equal to 50. In any other case, don’t print anything.
Exercise 8
Modify the program in exercises 7 to print “We are well into the hour” if neither of the two conditions is met.
Exericse 9
The following program is meant to print “denied” if the person’s age is less than 18 or greater than 65. However, the program is not working. Fix all the errors and test it to make sure that it behaves correctly for the ages: 17, 18, 19, 50, 64, 65 and 66.
|
|
Notice that there are two diffent types of errors you can run into. First you have errors that cause the Odin compiler to fail. Then you have logical errors. Odin has no problem with those, it will happily run. You need to keep a keen eye on the output to ensure that the program works according to expection. Don’t rush through this exercise, make sure you have found and fixed every problem.
Exercise 10
You can use +
to add to integers together. Write a program that adds the current values of hour, minutes and seconds together and prints out the result.
Exercise 11
In the previous exercise you used the +
operator to add two integers. Is is possible to also add two booleans? What about two strings? Try true + false
or "abc" + "def"
to see if they will work. As usual, take note of the results. If you have previous experience with some other programming language python, then you could contrast Odin with that language when it comes to how +
works with non-numeric types.
Exercise 12
The procedure time.clock_from_time
prints out 24-hour time. Write a program that converts that into 12-hour time instead and prints it out.
Exercises 13
Why doesn’t the following program work?
|
|
Fix the errors so that it can run
Exercise 15
Fix any errors in the follwing program.
|
|
Exercise 16
Write a program that creates a variable and initializes it to “Linux”. Print out a message that says “I use Linux”, using the variable you created.
Change the value of the variable to “NetBSD” and print out the message “I am now using NetBSD”, again using the variable you created.