To contents Next chapter

Chapter 1, Getting started

First you need to have Pike installed on your computer. See appendix E "How to install Pike" if this is not already done. It is also vital for the first of the following examples that the Pike binary is in your UNIX search path. If you have problems with this, consult the manual for your shell or go buy a beginners book about UNIX.

1.1 Your first Pike program

int main()
{
    write("hello world\n");
    return 0;
}
Let's call this file hello_world.pike, and then we try to run it:

	$ pike hello_world.pike
	hello world
	$ 
Pretty simple, Let's see what everything means:
int main()
This begins the function main. Before the function name the type of value it returns is declared, in this case int which is the name of the integer number type in Pike. The empty space between the parenthesis indicates that this function takes no arguments. A Pike program has to contain at least one function, the main function. This function is where program execution starts and thus the function from which every other function is called, directly or indirectly. We can say that this function is called by the operating system. Pike is, as many other programming languages, built upon the concept of functions, i.e. what the program does is separated into small portions, or functions, each performing one (perhaps very complex) task. A function declaration consists of certain essential components; the type of the value it will return, the name of the function, the parameters, if any, it takes and the body of the function. A function is also a part of something greater; an object. You can program in Pike without caring about objects, but the programs you write will in fact be objects themselves anyway. Now let's examine the body of main;

{
    write("hello world\n");
    return 0;
}
Within the function body, programming instructions, statements, are grouped together in blocks. A block is a series of statements placed between curly brackets. Every statement has to end in a semicolon. This group of statements will be executed every time the function is called.

write("hello world\n");
The first statement is a call to the builtin function write. This will execute the code in the function write with the arguments as input data. In this case, the constant string hello world\n is sent. Well, not quite. The \n combination corresponds to the newline character. write then writes this string to stdout when executed. Stdout is the standard Unix output channel, usually the screen.

return 0;
This statement exits the function and returns the value zero. Any statements following the return statements will not be executed.

1.2 Improving hello_world.pike

Typing pike hello_world.pike to run our program may seem a bit unpractical. Fortunately, Unix provides us with a way of automating this somewhat. If we modify hello_world.pike to look like this:

#!/usr/local/bin/pike

int main()
{
    write("hello world\n");
    return 0;
}
And then we tell UNIX that hello_world.pike is executable so we can run hello_world.pike without having to bother with running Pike:

	$ chmod +x hello_world.pike
	$ ./hello_world.pike
	hello world
	$ 
N.B.: The hash bang (#!) must be first in the file, not even whitespace is allowed to precede it! The file name after the hash bang must also be the complete file name to the Pike binary, and it may not exceed 30 characters.

1.3 Further improvements

Now, wouldn't it be nice if it said Hello world! instead of hello world ? But of course we don't want to make our program "incompatible" with the old version. Someone might need the program to work like it used to. Therefore we'll add a command line option that will make it type the old hello world. We also have to give the program the ability to choose what it should output based on the command line option. This is what it could look like:

#!/usr/local/bin/pike

int main(int argc, array(string) argv)
{
    if(argc > 1 && argv[1]=="--traditional")
    {
        write("hello world\n"); // old style
    }else{
        write("Hello world!\n"); // new style
    }
    return 0;
}
Let's run it:

	$ chmod +x hello_world.pike
	$ ./hello_world.pike
	Hello world!
	$ ./hello_world.pike --traditional
	hello world
	$ 
What is new in this version, then?
int main(int argc, array(string) argv)
In this version the space between the parenthesis has been filled. What it means is that main now takes two arguments. One is called argc, and is of the type int. The other is called argv and is a an array of strings.

The arguments to main are taken from the command line when the Pike program is executed. The first argument, argc, is how many words were written on the command line (including the command itself) and argv is an array formed by these words.

if(argc > 1 && argv[1] == "--traditional")
{
    write("hello world\n"); // old style
}else{
    write("Hello world!\n"); // new style
}
This is an if-else statement, it will execute what's between the first set of brackets if the expression between the parenthesis evaluate to something other than zero. Otherwise what's between the second set of brackets will be executed. Let's look at that expression:

argc > 1 && argv[1] == "--traditional"
Loosely translated, this means: argc is greater than one, and the second element in the array argv is equal to the string --traditional. Since argc is the number of words on the command line the first part is true only if there was anything after the program invocation.

Also note the comments:

write("hello world\n"); // old style
The // begins a comment which continues to the end of the line. Comments will be ignored by the computer when it reads the code. This allows to inform whoever might read your code (like yourself) of what the program does to make it easier to understand. Comments are also allowed to look like C-style comments, i.e. /* ... */, which can extend over several lines. The // comment only extends to the end of the line.

1.4 Control structures

The first thing to understand about Pike is that just like any other programming language it executes one piece of code at a time. Most of the time it simply executes code line by line working its way downwards. Just executing a long list of instructions is not enough to make an interesting program however. Therefore we have control structures to make Pike execute pieces of code in more interesting orders than from top to bottom.

We have already seen an example of the if statement:

if( expression )
    statement1;
else
    statement2;
if simply evaluates the expression and if the result is true it executes statement1, otherwise it executes statement2. If you have no need for statement2 you can leave out the whole else part like this:
if( expression )
    statement1;
In this case statement1 is evaluated if expression is true, otherwise nothing is evaluated.

Note for beginners: go back to our first example and make sure you understand what if does.

Another very simple control structure is the while statement:

while( expression )
    statement;
This statement evaluates expression and if it is found to be true it evaluates statement. After that it starts over and evaluates expression again. This continues until expression is no longer true. This type of control structure is called a loop and is fundamental to all interesting programming.

1.5 Functions

Another control structure we have already seen is the function. A function is simply a block of Pike code that can be executed with different arguments from different places in the program. A function is declared like this:
modifiers type name(type varname1, type varname2, ...)
{
    statements
}
The modifiers are optional. See
section 6.8 "Modifiers" for more details about modifiers. The type specifies what kind of data the function returns. For example, the word int would signify that the function returns an integer number. The name is used to identify the function when calling it. The names between the parenthesis are the arguments to the function. They will be defined as local variables inside the function. Each variable will be declared to contain values of the preceding type. The three dots signifies that you can have anything from zero to 256 arguments to a function. The statements between the brackets are the function body. Those statements will be executed whenever the function is called.

Example:

int sqr(int x) { return x*x; }
This line defines a function called sqr to take one argument of the type int and also returns an int. The code itself returns the argument multiplied by itself. To call this function from somewhere in the code you could simply put: sqr(17) and that would return the integer value 289.

As the example above shows, return is used to specify the return value of a function. The value after return must be of the type specified before the function name. If the function is specified to return void, nothing at all should be written after return. Note that when a return statement is executed, the function will finish immediately. Any statements following the return will be ignored.

There are many more control structures, they will all be described in a later chapter devoted only to control structures.

1.6 True and false

Throughout this chapter the words true and false have been used without any explanation to what they mean. Pike has a fairly simple way of looking at this. The number 0 is false and everything else is true. (Except when using operator overloading as I will explain in a later chapter.)

1.7 Data Types

As you saw in our first examples we have to indicate the type of value returned by a function or contained in a variable. We used integers (int), strings (string), and arrays (with the * notation). The others are mapping, mixed, void, float, multiset, function, object and program. Neither mixed nor void are really types, void signifies that no value should be returned and mixed that the return value can be of any type, or that the variable can contain any type of value. Function, object and program are all types related to object orientation. We will not discuss the last three in any great detail here,
Int
The integer type stores a signed integer. It is 32 bit or 64 depending on architecture.
Float
This variable type stores a floating point number.
Array
Arrays are basically a place to store a number of other values. Arrays in Pike are allocated blocks of values. They are dynamically allocated and do not need to be declared as in C. The values in the array can be set when creating the array like this:
arr=({1,2,3});
Or, if you have already created an array, you can change the values in the array like this:
arr [ ind ] = data;
This sets entry number ind in the array arr to data. ind must be an integer. The first index of an array is 0 (zero). A negative index will count from the end of the array rather than from the beginning, -1 being the last element. To declare that a variable is an array we simply type array in front of the variable name we want:
array i;
We can also declare several array variables on the same line:
array i, j;
If we want to specify that the variable should hold an array of strings, we would write:
array (string) i;
String
A string contains a sequence of characters, a text, i.e. a word, a sentence or a book. Note that this is not simply the letters A to Z; special characters, null characters, newlines and so on can all be stored in a string. Any 8-bit character is allowed. String is a basic type in Pike, it is not an array of char like it is in C. This means that you cannot assign new values to individual characters in a string. Also, all strings are "shared", i.e. if the same string is used in several places, it will be stored in memory only once. When writing a string in a program, you enclose it in double quotes. To write special characters you need to use the following syntax:
\nnewline
\rcarriage return
\ttab
\bbackspace
\"" (quotation character)
\\\ (literal backslash)
Mapping
A mapping is basically an array that can be indexed on any type, not just integers. It can also be seen as a way of linking data (usually strings) together. It consists of a lot of index-data pairs which are linked together in such a way that map[index1] returns data1. A mapping can be created in a way similar to arrays:
mapping(string:string) map=(["five":"good", "ten":"excellent"]);
You can also set that data by writing map["five"]="good". If you try to set an index in a mapping that isn't already present in the mapping it will be added as well.
Multiset
A multiset is basically a mapping without data values. When referring to an index in the multiset a 1 (one) will be returned if the index is present and 0 (zero) otherwise.


To contents Next chapter