Io Programming
Beginner's Guide to Io
Addons and You
Compression
Encryption
Networking
Server
Io Language Pages
- Io To-Do -- Stuff that needs to be done.
- Io Example Code -- Paste your example code here.
- Binding Io to C++ -- Learn how to bind Io using C++.
- Io and CGI -- Accessing Io through CGI
- Io Style Guide -- How to write good Io code.
- Writing Addons -- How to write new Addons.
- Pitfalls -- Some subtle Io pitfalls.
About This Wiki
This work is disjointly licensed under the GNU FDL, the CC BY SA, and Io's license.
The authors of this tutorial are:
- Daniel Ehrenberg (LittleDan)
- Samuel A. Falvo II
- Olle Jonsson (just a note on String concatenation)
And many others who wish to remain anonymous.
A Wikibookian believes this page should be split into smaller pages with a narrower subtopic. You can help by splitting this big page into smaller ones. Please make sure to follow the naming policy. Dividing books into smaller sections can provide more focus and allow each one to do one thing well, which benefits everyone. |
Hello world
When learning to program, the first thing usually learned is how to write a program that prints "Hello, world!" to the console. It gives programmers a feel of how simple programs are structured. Io has many ways to write things to the console, so at times it can be confusing about which one to use. The one that's most often used is the write function. Enter the Io's interactive interpreter (by typing io
at the console) and type the following:
write("Hello, world!\n")
With the interactive interpreter, this should look like:
user@computer:~$ io Io> write("Hello, world!\n") Hello, world! ==> nil
Another way would be:
"Hello, world!\n" print
Some of this makes sense. It looks like write
is telling Io to write something to the console, specifically the stuff after it. The stuff after it is in quotes so it's some text, and it's what's going to be printed. But why are those parentheses there, what's with that \n
at the end of it, and why was there an arrow with the quoted text after it?
The parentheses are telling write
to use the thing within the parentheses, which is called an argument. write
is called a function (remember functions in math?). There might be multiple arguments within the parentheses separated by commas in a single function. The first and only argument for write
, namely "Hello, world!\n"
, is a string (because it's a string of letters).
The \n
at the end of the string is an escape sequence. You can tell that because it begins with a backslash. This particular escape sequence signals a newline, the equivalent of pressing enter. If you just pressed enter in the middle of the string (or at least this type of string -- we'll get to that later), it would confuse Io.
The thing where there's an arrow and then the string that was the argument of the write
function is the value that write
returned. Every function returns a value. With some functions, it makes sense to return something (such as a function to add two numbers), but with other functions, it just returns something simple done with the arguments. In this case, write
returns the special value nil
, indicating it has nothing to return.
Concatenate Strings
Use the double dot operator to concatenate strings. Or, you can use string interpolation, as shown below.
Let's say olle
is a Person
instance, and it has both a first name and a last name:
Io> olle ==> Object_0080B818 do( appendProto(Object_00806B58) lastname := "Jonsson" title := "Developer" firstname := "Olle" )
We want a method to show first and last name with a space in-between:
Io> olle fullname := method(firstname .. " " .. lastname) ==> method(firstname ..(" ") ..(lastname))
or, using string interpolation:
Io> olle fullname := method("#{firstname} #{lastname}" interpolate) ==> method("#{firstname} #{lastname}" interpolate)
Now, calling olle fullname
will yield "Olle Jonsson"
. Looking at the returned method object, we can see how the Io interpreter creates regular message calls (the parentheses) for the method ..()
.
So, this is the new olle
instance:
Io> olle ==> Object_0080B818 do( appendProto(Object_00806B58) fullname := Block_007B5030 lastname := "Jonsson" title := "Developer" firstname := "Olle" )
(Note: only this instance has the fullname
method. You could add the fullname
method to Person
instead, which would make it available to olle
via olle
's prototype, Person
. Also, the firstname and lastname and title could also be moved up to the Person. But this is the way pieces of example code are.)
Simple arithmetic
In Io, you can use arithmetic expressions and they will work correctly. Arithmetic in Io is just like functions, except it uses objects to help. Objects make it so that instead of typing something like +(1, 2), you can type 1+2. More about objects later. + is still a function, though, so it returns a value. This is very useful; it makes it so you can use Io as a simple calculator. Notes about what it's doing are put after two slashes (like this: //).
Io> 1+2 //addition ==> 3 Io> 4-5 //subtraction ==> -1 Io> 7*3 //multiplication ==> 21 Io> 3/6 //division ==> 0.50000 Io> 2**3 //exponents ==> 8 Io> 7%2 //remainder of 7/2 (technically, 7 mod 2) ==> 1
This follows normal order of operations (called precedence) and parentheses can be used. As you'd expect, you can use write
on numbers, but the newline isn't included. You have to use multiple arguments with write
to print multiple things and then it returns all of those things put together. So to print (1/3)**2
, you would write:
write((1/3)**2, "\n")
As you would expect, this prints 0.11111. It returns the string "0.11111\n" because with the write
function, multiple arguments are converted to strings and joined together. Then that value is printed and returned.
Variables
A variable is basically a word that stands for a value. They are somewhat like variables in mathematics, except in mathematics, variables could only be numbers and they were one letter long. In programming, functions, objects, strings, and numbers are all types of variables, but we haven't defined any yet. Many variables, such as write, 3, and "Hello, world!" can already be used, but only some of them can be changed. You can make your own variables using = and :=. Below are some examples of making and using variables:
x := 3 line := "\n" write(x, line)
Can you tell what's happening? The variable x is being set to 3 and the variable line is being set to "\n", which is equivalent to a newline. Then, the contents x and line are being written to the console. Since x is 3 and line is a newline, this prints 3 and then goes to the next line on the console. The function returns "3\n".
In Io, there is a difference between creating and changing the value of variables. If a variable doesn't exist yet, you have to use :=, but if you've already given it an initial value using :=, you can use = for subsequent definitions. Here's an example:
x := 1 incrementor := 2 write("x is ", x, "\n") x = x + incrementor write("but when we added ", incrementor, " to it, it became ", x, "\n")
It may be confusing that sometimes we use := and other times we use =, but you'll get used to it. If you want to, you can always use :=, but when we get into objects later, it will become very inconvenient to keep using :=, so you should probably start using = whenever appropriate.
Programs
Until now, you've been simply been going to Io's interactive interpreter. This prevents you from making larger applications or writing things for others. If you want to write code to be reused, simply put it in a text file and run it with io <filename>
, where <filename> is the name of the file you use. Here's an example of using a file on Linux to store a program:
user@computer:~$ cat > incrementor.io x := 1 incrementor := 2 writeln("x is ", x) x = x + incrementor writeln("but when we added ", incrementor, " to it, it became ", x) user@computer:~$ io incrementor.io x is 1 but when we added 2 to it, it became 3 user@computer:~$
That was the last example we just did. If you noticed, I used a .io file extension. This is in no way mandated, it is merely a convention. Something happened differently this time then when we did it from a file, if you noticed. Unlike before, we didn't see what each function returned. Instead, we only saw what was explicitly output by write
.
If you're on Linux or a similar system (such as Unix, Mac OS X, or Cygwin), you can make it so that your file can be run simply by typing ./yourProgram.io
(where yourProgram.io is the name of your program), without needing to precede it with io
. This can be accomplished by putting a line of code at the beginning of your program and then giving it executable permissions. On Linux, that code is:
#! /usr/bin/env io
It may differ for other systems. To give it executable permissions, simply type the following:
chmod +x yourProgram.io
Again, this may be different on different systems. Once you do this, nothing will change about the actual execution of the code, but you can, for example, just double click on a source code file in a GUI and it will run.
Writing functions
As I said before, functions are just another type of variable, so you can create them using := and change them using =. Functions themselves are created with a function called method
. Here's an example of a function:
add := method(a, b, //function to add 2 numbers a + b ) writeln(add(1, 2)) //writes 3 x := 1 writeln(add(3, x)) //writes 4 x = add(4, 5) //9 writeln(x) //writes 9 x = add(x, 1) //in effect increment x by 1 writeln(x) //writes 10
The function add takes two arguments, a and b, and then returns a + b. It would do exactly the same thing if, instead of a and b, we used the variable names 'this' and 'that', everywhere that a and b were used. In that case, the function would be written as:
add := method(this, that, this + that )
What a function really does is take a list of arguments; then it assigns the arguments to local variables, which are specified when you make the function. Local variables stay in the function you're working in and you can't get to them outside of the function. In the most recent case, those local variables are 'this' and 'that', so the variable 'this' will take the first argument, and the variable 'that' will take the second argument. Then it executes the rest of the function and returns the result. The function can have multiple lines of code and the last line will be the value returned. Here's an example:
examineArgs := method(this, that, writeln("This is ", this, ".") writeln("That is ", that, ".") )
// usage: examineArgs(3, 5) /* writes: This is 3. That is 5. */
x := examineArgs("hi", "bye") /* writes: This is hi. That is bye. */
write(x) /* writes: That is bye. */
Why was x set to "That is bye.\n"? Because that's what examineArgs returned. It returned the value of the last line, the value of write("That is ", that, ".\n"). That was set to "bye", so it printed the string "That is bye.\n" and returned the same string.
If you want to return something before the function ends, you can use the return function. Unlike most functions, you don't need to put parentheses around the argument to call the return function. Here is an example of its usage:
returning := method(this, that, writeln(this) return this writeln(that) ) x := returning(1, 2) //writes "1\n" write(x) //writes 1 with no newline
As you can see, the code after return isn't used at all. Right now, this doesn't seem very useful, but later, when we get into flow control, it will be used very often.
Conditionals
Conditionals in Io are made using the if function:
if(a == 1) then( writeln("a is one") ) else( writeln("a is not one") )
However, the preferred way to write this (without the need for then() and else() messages, so it is faster):
if(a == 1, writeln("a is one"), writeln("a is not one"))