diff --git a/browser/about_www.md b/browser/about_www.md new file mode 100644 index 0000000..cac16e2 --- /dev/null +++ b/browser/about_www.md @@ -0,0 +1,32 @@ +# Some Notes About WWW + +* When our simple web browser prints a web page, + it just prints the raw HTML code. + All the things between `<` and `>` + characters are called *tags*, + and they contain commands + that indicate how the rest of the text should be formatted. + To do that well is beyond the scope of this tutorial. + +* Some web addresses don't refer to HTML pages, + but to (among other things) sound clips or pictures. + If you try to access such a web address with this browser, + it will dump the sound or picture on the screen + as if it had been text, + and this will look even uglier than raw HTML code. + Real web browsers check the type of the web page, + and then take the appropriate action depending on that type. + +* If your web browser fails to retrieve a web page + that you think exists, + this may be because you haven't typed the address exactly correct. + For example, + some addresses must have a slash (`/`) at the end. + More advanced web browsers discuss things like this with the web server, + and they usually manage to fix the address for you. + +* You may not get a "failed" message + when you try to retrieve a web page that doesn't exist. + When the web server gets a request for a non-existent page, + it generates a new web page with an error message, + and your web browser receives and shows that page. diff --git a/browser/arguments_and_if.md b/browser/arguments_and_if.md new file mode 100644 index 0000000..5c92c80 --- /dev/null +++ b/browser/arguments_and_if.md @@ -0,0 +1,97 @@ +# Command-line Arguments and if + +Before we let the program actually do anything +with the URL we give to it, +we will improve the program +to let it take the URL as a **command-line argument**. +That is, we want to start the program with the command + +``` +> webbrowser.pike http://pike.ida.liu.se/ +``` + +instead of letting the program ask for the URL. +We add some code for this: + +```pike +#! /usr/local/bin/pike + +// The Very Simple World Wide Web Browser + +int main(int argc, array(string) argv) // 2) +{ + write("Welcome to the Very Simple WWW Browser!\n"); + string url; + if (argc == 2) // 3), 5) + url = argv[1]; // 4) + else // 5) + { // 5) + write("Type the address of the web page:\n"); + url = Stdio.stdin->gets(); + } // 5) + write("URL: " + url + "\n"); + return 0; +} // main +``` + +This program can handle a command-line argument, +but if you don't give one, +it will ask for an URL just as before. + +There are some new things to explain here: + +1. The first line `#! /usr/local/bin/pike` + only works on a Unix system, + as described earlier. + You can remove it if you are using Windows. + +2. We have added `int argc, array(string) argv` + as **parameters** to `main`. + These parameters are like normal variables, + except that they will be assigned some values automatically + when the program starts. + + The variable `argc` has the type `int`, + which means **integer**. + It will contain the number of command-line arguments. + The program name is counted as an argument, + so if you give one argument to the program, + `argc` will have the value **2**. + + The variable `argv` will contain the arguments. + Its type is `array(string)`, + which means **array of strings**. + Each command-line argument is put in a string, + and together they form a list or array. + +3. `argc == 2` is a comparison. + We check if the value of `argc` is **2**. + `==` is an **operator** + that checks if two things are the same. + Some other comparison operators in Pike are `<` (less than), + `>=` (greater than or equal), and `!=` (not same). + +4. `argv[1]` retrieves the element at position number 1 in an array. + The positions are numbered from 0, + so position 1 is actually the second element in the array. + This is the URL given as argument to the program. + `argv[0]` contains the name of the program, + the string `"webbrowser.pike"`. + +5. The `if` statement lets Pike choose between different actions. + It follows the template or pattern + + ```pike + if ( *condition* ) + *something* + else + *something-else* + ``` + + If the *condition* (in our case, that `argc == 2`) is **true**, + Pike will do the *something*. + If the *condition* is **false**, + it will do the *something-else*. + In our program, + there are two **statements** in the *something-else*, + so we must enclose it in curly brackets, `{` and `}`. diff --git a/browser/convenient_syntax.md b/browser/convenient_syntax.md new file mode 100644 index 0000000..a823886 --- /dev/null +++ b/browser/convenient_syntax.md @@ -0,0 +1,55 @@ +# Syntactic Sugar + +## Importing a Module + +If we don't want to write the module name +every time we use something from that module, +an alternative is to **import** the module. +If we import `Protocols.HTTP`, +we can use the data type `Query`, +and the method `get_url`, +without prefixing them with `Protocols.HTTP`: + +```pike +import Protocols.HTTP; + +void handle_url(string this_url) +{ + write("Fetching URL '" + this_url + "'..."); + Query web_page; + web_page = get_url(this_url); + if (web_page == 0) + { + write(" Failed.\n"); + return; + } + write(" Done.\n"); +} // handle_url +``` + +Although you *could* import lots and lots of modules +for the ease of lazy typing, +this mostly isn't a recommended practice, +for obvious reasons of clarity and readability. +There are also some non-obvious reasons to refrain from doing imports. +If someone adds the method `write` to the module `Protocols.HTTP`, +we would call that method instead of the one that writes text to the user. +It also takes longer to start the program, +since Pike must search through all imported modules +to find the methods you use. + +## Initial Values for Variables + +We can give a value to a variable when we define it, +so there is no reason to write: + +```pike + Query web_page; + web_page = get_url(this_url); +``` + +We change it to this: + +```pike + Query web_page = get_url(this_url); +``` diff --git a/browser/fetching_the_page.md b/browser/fetching_the_page.md new file mode 100644 index 0000000..4ca3370 --- /dev/null +++ b/browser/fetching_the_page.md @@ -0,0 +1,123 @@ +# Magic Web Stuff + +Now it's time to start surfing the web! +Perhaps you know that web pages are written +in something called HTML (HyperText Markup Language), +and that the `http` you see in web addresses +like `http://pike.ida.liu.se/` +means HyperText Transfer Protocol. +The HyperText Transfer Protocol is a description +of how web browsers communicate with web servers. + +It is actually a fairly complicated operation +to connect to a web server, +to tell it to send you a web page, +and then to receive that page as the server sends it. +Fortunately for us, +someone has already done this for us. +There is a **module** called `Protocols.HTTP`, +which handles the communication with the web server. +A module is a package of Pike code +that can easily be used by other programmers. + +We rewrite the method `handle_url` +to actually try to fetch the web page, +using the module `Protocols.HTTP`: + +```pike +void handle_url(string this_url) +{ + write("Fetching URL '" + this_url + "'..."); + Protocols.HTTP.Query web_page; + web_page = Protocols.HTTP.get_url(this_url); + if (web_page == 0) + { + write(" Failed!\n"); + return; + } + write(" Done.\n"); +} // handle_url +``` + +The interesting part here is the lines + +```pike + Protocols.HTTP.Query web_page; + web_page = Protocols.HTTP.get_url(this_url); +``` + +First we define the variable `web_page`, +with the data type `Protocols.HTTP.Query`. +Actually, the data type is called `Query`, +and is defined in the module `Protocols.HTTP`, +but we must write it as `Protocols.HTTP.Query` +so Pike knows where to find it. + +A data item of the type `Protocols.HTTP.Query` +contains the result of a web page retrieval: +the text of the web page, +but also some more information, +such as the time when the page was created. + +The actual work is done by the method `Protocols.HTTP.get_url`, +which is actually the method `get_url` in the module `Protocols.HTTP`. +It talks to the web server, +fills a `Query` object with everything it finds, +and returns it. +If it cannot find the web page, it returns zero (**0**) instead. + +Some other things that might need to be explained in this example: + +* We can use single quotes (') inside a string. + If we want to put a double quote (") in a string, + we can do so by prefixing the double quote with a backslash: + + ```pike + "This string contains a \"." + ``` + +* If the web page couldn't be found, + we use the statement + + ```pike + return;` + ``` + + to stop executing the method `handle_url`, + and instead return to where it was called. + This is the same as the + + ```pike + return 0; + ``` + + we have seen in `main`, + except that `handle_url` doesn't return a value. + +* `return` just returns from the method we are in. + If we want to terminate the program, + we can use the built-in function `exit`: + + ```pike + exit(0); + ``` + + This has the same effect as returning **0** from `main`. + +When we run this version of the web browser, it may look something +like this. The user's command is shown in *italics*: + +``` +> webbrowser.pike pike.ida.liu.se +Welcome to the Very Simple WWW Browser! +Fetching URL 'pike.lysator.liu.se'... Done. +``` + +If we try to retrieve a web page that doesn't exist, +the web browser fails: + +``` +> webbrowser.pike cod.lysator.liu.se +Welcome to the Very Simple WWW Browser! +Fetching URL 'cod.ida.liu.se'... Failed! +``` diff --git a/browser/index.md b/browser/index.md new file mode 100644 index 0000000..f1d4f4b --- /dev/null +++ b/browser/index.md @@ -0,0 +1,113 @@ +# Your Second Pike Program + +Your first Pike program, +which was examined above in this tutorial, +was a program that printed "Hello world!" on the screen. +Your second Pike program will be a World Wide Web browser, +just like Firefox, Google Chrome, Safari or Internet Explorer. + +Well, perhaps not *just* like those; +those are all very large programs, +and our browser will be a very small one. +We will just make it advanced enough +to connect to a World Wide Web server, +download a web page, +and then display its markup on the screen. + +We start by creating a file, for example called +`webbrowser.pike`: + +```pike +// The Very Simple World Wide Web Browser + +int main() +{ + write("Welcome to the Very Simple WWW Browser!\n"); + return 0; +} // main +``` + +This is almost the same program as the "hello world" program. +The only difference is that it prints something else, +and that we have added some **comments**. +Two "slash" characters (`//`) means +that the rest of the line is a comment. +Comments are ignored by Pike, +and are intended for humans who read your program. + +Pike has another type of comments, +which start with `/*` and end with `*/`. +Such comments can span several lines: + +```pike +/* +This is also a comment. +For example, you can "comment out" parts +of your program with this type of comment, +so Pike doesn't run those parts. +*/ +``` + +## Variables + +The web browser must be told +which web page it should download and display. +As you may know, +the "addresses" to web pages are called URLs (Uniform Resource Locators), +and they look like `pike.lysator.liu.se` or `http://pike.lysator.liu.se/` +(where the second form is correct, but the first one usually works too). + +We add some code that lets the user type a URL, +stores that URL in a variable, +and also prints it on the screen as confirmation. +The new additions are commented with numbers, +described further below: + +```pike +// The Very Simple World Wide Web Browser + +int main() +{ + write("Welcome to the Very Simple WWW Browser!\n"); + string url; // 1 + write("Type the address of the web page:\n"); + url = Stdio.stdin->gets(); // 2 + write("URL: " + url + "\n"); // 3 + return 0; +} // main +``` + +There are four new things here: + +1. We create a **variable** with the name `url`. + This is called to **define** a variable. + The variable has the type `string`, + which means that we an use it to store strings in. + A string is a sequence of characters. + +2. `Stdio.stdin->gets()` is used to let the user + type some text on the keyboard. + When the user hits the return key, + the text is returned as a string. + (`Stdio.stdin->gets()` calls the method `gets` + in the object `stdin` from the module `Stdio`, + but you don't need to worry about that just yet.) + + We take that string, and store it in the variable. + This is called **assignment**, + or to **assign** a value to the variable. + +3. In the last line with `write`, + we add three strings together: + `"URL: " + url + "\n"` + +When we run the program, it may look something like this. +The user's commands and input are shown after the `>` prompts: + +``` +> pike webbrowser.pike +Welcome to the Very Simple WWW Browser! +Type the address of the web page: +> http://pike.ida.liu.se/ +URL: http://pike.ida.liu.se/ +``` diff --git a/browser/invocation.md b/browser/invocation.md new file mode 100644 index 0000000..5d62836 --- /dev/null +++ b/browser/invocation.md @@ -0,0 +1,53 @@ +# Running the Program + +An appropriate next step would be making your program run +without the need for manually invoking it with the pike parser. +If you are using a Unix system, +such as Linux, Solaris or OS X, +you can make the web browser a free-standing program +by adding: + +```pike +#! /usr/local/bin/pike +``` + +(or "`#! `" followed by +whatever Pike itself happens to be called on your system) +as the very first line in the file, +without any spaces in the part pointing out the path to your pike binary. + +Assuming you want your script to run +with whatever "pike" binary would be run +if "pike" was entered at the prompt, that is, +the first "pike" executable found in the user's path, +a useful and portable alternative is this syntax: + +```pike +#! /usr/bin/env pike +``` + +Either way, +you must finish off the work +by making the file executable: + +``` +> chmod a+x webbrowser.pike +``` + +Now, you can run the web browser just by giving the command: + +``` +> ./webbrowser.pike +``` + +or by clicking on its icon in a graphic file manager. +(If you don't like the extension `.pike`, +you can simply change the name of the file to `webbrowser`, +without the extension.) + +Under Windows, +you can associate the file extension `pike` with the Pike program. +Then you can start the web browser +by clicking on the web browser's icon, +or by giving the command `webbrowser.pike` +in the Command Prompt Window. diff --git a/browser/methods_and_loops.md b/browser/methods_and_loops.md new file mode 100644 index 0000000..c9fb024 --- /dev/null +++ b/browser/methods_and_loops.md @@ -0,0 +1,157 @@ +# Methods and Loops + +We will soon ad the web stuff, +and actually download the web page. +But the method `main` is getting a bit long now, +so perhaps it is time to divide or program +into several methods. +Instead of putting the web stuff in `main`, +we write a method called `handle_url`, +which will do all the handling of a URL. + +```pike +void handle_url(string this_url) +{ + write("URL: " + this_url + "\n"); +} // handle_url +``` + +So far, it only writes the URL on the screen, +just like we did in `main`. + +Some interesting things to note: + +* `main` returns an integer, + to indicate if the program succeeded or not. + We don't care if `handle_url` fails, + so we set the **return type** to `void`, + which means it returns "nothing". + +* `main` had two parameters. + `handle_url` only has one, `this_url`. + `this_url` can contain a string. + +For this method to be executed by Pike, +we must **call** it from `main`. +We replace the statement that printed the URL with: + +```pike +handle_url(url); +``` + +This sends the value in the variable `url`, +which is a local variable in `main`, +to `handle_url`, +where it will be put in the variable `this_url`. +The thing that is sent, `url`, +is usually called an **argument**, +and the variable that receives it, `this_url`, +is usually called a **parameter**. + +A problem with our program is what happens +if the user doesn't give an argument, +and then just hits the return key +when the program asks for a URL. +`Stdio.stdin->gets()` will return an empty sting, +just as it should, +but that is not a valid web address. +If we want the program to keep asking +until it gets a non-empty answer, +we can put the two ask-and-read statements inside a **loop**: + +```pike +do +{ + write("Type the address of the web page:\n"); + url = Stdio.stdin->gets(); +} while (sizeof(url) == 0); +``` + +This is a **do-while loop**, +and such a loop follows the pattern + +```pike +do + *something* +while ( *condition* ); +``` + +The do-while loop will do the *something* at least once, +and then keep doing it as long as the *condition* is true. +First it does the *something*, +then it checks the *condition*, +and then it either leaves the loop and continues after it, +or goes back to the start of the loop and does the *something* again. +In our case, +the *condition* is that `sizeof(url) == 0`, +i e that the string `url` is empty. + +Another problem with our program is +that it only checks if `argc` is 2. +If you give several arguments, +the program will ignore them. +We change the `if` test a bit, +so that it prints an error message +and then terminates the program +if we give too many arguments. +The complete program now looks like this: + +```pike +#! /usr/local/bin/pike + +// The Very Simple World Wide Web Browser + +void handle_url(string this_url) +{ + write("URL: " + this_url + "\n"); +} // handle_url + +int main(int argc, array(string) argv) +{ + write("Welcome to the Very Simple WWW Browser!\n"); + string url; + if (argc == 1) + { + do + { + write("Type the address of the web page:\n"); + url = Stdio.stdin->gets(); + } while (sizeof(url) == 0); + } + else if (argc == 2) + { + url = argv[1]; + } + else + { + write("Too many arguments. Goodbye. Sorry.\n"); + return 1; + } + handle_url(url); + return 0; +} // main +``` + +Note how we have chained two `if` statements together +with an `else if`. + +Neither the curly brackets around `url = argv[1];` +nor those around the `do` loop are necessary, +since they only encircle a single statement each, +but some programmers feel +that it is to be on the safe side having them there either way, +in case they would add yet another statement later on +and forget about adding the braces. +Others feel that +if you have curly brackets around one of the possible cases +in an `if` statement, +you should have curly braces around all of them. +Uniformity makes it easier to grasp +the structure of the whole thing at a glance. + +Also note how the use of **indentation**, +i e the varying amount of white space at the beginning of each line, +makes it easy to follow the "block structure" of the program. +For example, you can easily see +that the **do-while** loop is +inside the first case of the `if` statement. diff --git a/browser/show_page.md b/browser/show_page.md new file mode 100644 index 0000000..cb17706 --- /dev/null +++ b/browser/show_page.md @@ -0,0 +1,68 @@ +# Showing the Page + +A web browser that just prints "Done" instead of the web page +isn't of much use, +so we add some lines at the end of the method `handle_url` +to print the contents of the web page: + +```pike +void handle_url(string this_url) +{ + write("Fetching URL '" + this_url + "'..."); + Query web_page = get_url(this_url); + if (web_page == 0) + { + write(" Failed.\n"); + return; + } + write(" Done.\n"); + write("This is the contents of '" + this_url + "':\n\n"); + string page_contents = web_page->data(); + write(page_contents + "\n"); +} // handle_url +``` + +The interesting part here is the expression + +```pike +web_page->data() +``` + +where we call the method `data` in the data item `web_page`. +This method returns the contents of the web page, +i e the HTML code, as a string. +We then print that string. + +## Methods in data items? + +"But", you say, +"what is all this about a method in a data item? +I thought methods were pieces of code +that were parts of a program?" + +Well, a method *is* a part of a program, +just as we have seen. +But just as the web browser we have written contains methods, +other programs can contain methods. +And the "data type" `Protocols.HTTP.Query` +is actually another program. +The big difference is that it doesn't have a method called `main`, +so it can't be used by itself. +It can only be used as a part of another program, +as we have done here. + +Somewhere on your computer there is a file, +called something like +`/usr/local/pike/8.0.28/lib/modules/Protocols.pmod/HTTP.pmod/Query.pike` +or +`C:\Program Files\Pike\lib\pike\modules\Protocols.pmod\HTTP.pmod\Query.pike`. +This file contains the program `Query` +with all its methods and variables, +among them the method `data`. + +A program like `Query`, +which can be used in other programs in the way we have seen, +is often called a **class**. +You can read more about how to use, and create, +classes in the chapter about +[**object-oriented programming**](../oop/index.md). diff --git a/data_types/basic_types.md b/data_types/basic_types.md new file mode 100644 index 0000000..73b04b0 --- /dev/null +++ b/data_types/basic_types.md @@ -0,0 +1,31 @@ +# Basic Types + +We have already seen integers (`int`) and strings (`string`) +being used in several examples, +but the third basic type, `float`, is new. +A `float`, also called a **real number** or a **floating-point number**, +is different from an integer in that it can have a fraction part: + +```pike +6.783 // This is a floating-point number +17 // This is an integer +17.0 // This is a floating-point number +``` + +Note that Pike differentiates +between integer and floating-point numbers +that happen to be equal to an integer. +If you write `17` in a Pike program you get an integer, +and if you write `17.0` you get a floating-point number. +Inside the computer they look completely different. + +You can define variables like this: + +```pike +int number_of_monkeys; // An integer variable +float z = -16.2; // A floating-point variable +string file_name; // A string variable +mixed x; // A variable for anything +``` + +The data type `mixed` means "any type of value". diff --git a/data_types/container_types.md b/data_types/container_types.md new file mode 100644 index 0000000..ab1cc18 --- /dev/null +++ b/data_types/container_types.md @@ -0,0 +1,86 @@ +# Container Types + +Some of the data types are **containers**. +A data item of one of these container types +can contain other data items. + +The simplest of the container types is the **array**. +If a variable is a box where you can put a data item, +an array is a whole sequence of such boxes. +The boxes are numbered, starting with 0, +so in an array with 10 places the first one has number 0, +and the tenth and last one has number 9. +The position numbers are called **indices**. +(One **index**, many indices.) + +You can give an array in your Pike program +by listing its elements inside parenthesis-curly-bracket quotes: + +```pike +({ "geegle", "boogle", "fnordle blordle" }) +({ 12, 17, -3, 8 }) +({ }) +({ 12, 17, 17, "foo", ({ "gleep", "gleep" }) }) +``` + +As you can see, +an array can be empty (containing no elements), +and it can also contain other arrays. +An array can contain elements of different types, +but it is more common with +arrays that only contain one type of element. + +You can define array variables like this: + +```pike +array a; // Array of anything +array(string) b; // Array of strings +array(array(string)) c; // Array of arrays of strings +array(mixed) d; // Array of anything +``` + +Then you can give values to these variables: + +```pike +a = ({ 17, "hello", 3.6 }); +b = ({ "foo", "bar", "fum" }); +c = ({ ({ "John", "Sherlock" }), ({ "Holmes" }) }); +d = c; +``` + +You can access the elements in an array, +either to just get the value or to replace it. +This is usually called **indexing** the array. +Indexing is done by writing the position number, or index, +within square brackets after the array: + +```pike +write(a[0]); // Writes 17 +b[1] = "bloo"; // Replaces "bar" with "bloo" +c[1][0] = b[2]; // Replaces "Holmes" with "fum" +``` + +There are many useful operations that can be done with arrays. +For example, you can add two arrays together: + +```pike +({ 7, 1 }) + ({ 3, 1, 6 }) +``` + +The result of that expression is a new array, +with the elements from the two arrays concatenated: + +```pike +({ 7, 1, 3, 1, 6 }) +``` + +Except for arrays there are two other container types in Pike, +`mapping` and `multiset`. +A set is something where a value is either a member or not, +and a multiset is a set which can contain several copies of the same value. +Mappings are sometimes called dictionaries, +and lets you translate from one value (such as `"beer"`) +to another value (`"cerveza"`). +Academics might know the datatype by the name "associative array", +perl programmers call them "hashes", javascript programmers say "Objects". +Mappings and multisets are explained in a later chapter. diff --git a/data_types/index.md b/data_types/index.md new file mode 100644 index 0000000..311fe0d --- /dev/null +++ b/data_types/index.md @@ -0,0 +1,53 @@ +# An Introduction to Data Types + +# What is a data type? + +Pike works with **data items**, +also called **values**, +such as the integers **17** and **-4717**, +or the string of characters `"Hello world!"`. +Each data item has, or "is", a certain type: +**17** and **-4717** both have the type **integer**, +and `"Hello world!"` has the type **string**. +If we want to refer to the data type **integer** +in a Pike program, +we write `int`. +For the type **string**, +we write `string`. + +Each variable, method, and method parameter also has a type. +The types of these determines which data items +you can put in the variable, +return from the method, +or use as arguments to the method. +An integer variable, created with + +```pike +int i; +``` + +can only contain integer values. +If we try to put something else, +such as a string, +in this variable, +Pike will try to discover the discrepancy and complain about it. +This is called **type checking**. + +`string` and `int` are **built-in types** in Pike. +You can also create your own data types, or **classes**. +We have already seen some examples of this, +for example the class `Query`, +which is part of the module `Protocols.HTTP`, +and which is used to contain the data we get +when we retrieve a page from the World Wide Web. + +We will examine each individual data type in some detail in a later chapter, +but this chapter will give an introduction to data types in general. + +## Different Kinds of Types + +The data types in Pike can be divided into three categories: +the **basic types** (`int`, `float`, and `string`), +the **container types** (`array`, `mapping`, `multiset`), +and then the three types `program`, `object` and `function`. +We will start by looking at the basic types. diff --git a/data_types/other_types.md b/data_types/other_types.md new file mode 100644 index 0000000..c1da83e --- /dev/null +++ b/data_types/other_types.md @@ -0,0 +1,58 @@ +# Object, Program and Function + +These three data types will be described in more detail later, +but here is a short explanation of what they are good for. + +An `object` is an object, +in the object-oriented sense: +the values of a bunch of member variables as defined by a **program** +(or **class**, as a C++, Java or Smalltalk programmer would say). +We say that the object is an instance of the program. + +An object is an instance of a program, +and just as we want to store objects in variables, +and send them back and forth to functions, +we sometimes want to do the same with the **programs**. +For example, we may need a function that creates an instance +(that is, `object`) of any program, +and we must therefore be able to send the program +as an argument to the function. +This is what we use the data type `program` for. + +It may come as a surprise +that there is a special datatype for Pike programs, +but it is actually very useful, +and adds a lot of flexibility to Pike. + +Something else that may surprise you +is that there is a data type for **methods**. +Sometimes you want to refer to "any method". +Take for example the built-in method `map`, +which is used to apply an operation to all the elements in an array. +You call `map` with (at least) two arguments: +the array to go through, +and the method to call for each element: + +```pike +void write_one(int x) +{ + write("Number: " + x + "\n"); +} + +int main() +{ + array(int) all_of_them = ({ 1, 5, -1, 17, 17 }); + map(all_of_them, write_one); + return 0; +} +``` + +Running this code snippet would output: + +``` +Number: 1 +Number: 5 +Number: -1 +Number: 17 +Number: 17 +``` diff --git a/data_types/reference_types.md b/data_types/reference_types.md new file mode 100644 index 0000000..65b45eb --- /dev/null +++ b/data_types/reference_types.md @@ -0,0 +1,205 @@ +# Basic Types and Reference Types + +We have said before that +a variable is a sort of box +that can be used to store a value. +But there is a difference +between what we call "basic" values, such as integers, +and more complex values, such as arrays. +The basic values are stored in the variables, +just as as we can expect, but the complex ones are not. +They are stored somewhere else, +and the variable only contains a reference to the actual data. + +Usually, you don't need to think about this difference, +but there are cases when it is important. + +Here is an example to show exactly what the difference means. +We start by defining an integer variable called `i1`: + +```pike +int i1; +``` + +This variable can now be used to store integer values. +We put the value **5** in `i1`: + +```pike +i1 = 5; +``` + +If we could look inside the computer, +this is what we would see: + +![referencesnot1](referencesnot1.gif) + +*A non-reference variable* + +`i1` is a box, which contains the value **5**. +We now define another integer variable, called `i2`, +and copy the value in `i1` to `i2`: + +```pike +int i2; +i2 = i1; +``` + +This is how it looks now: + +![referencesnot2](referencesnot2.gif) + +*Two non-reference variables, before the change* + +As we might have expected, +there is a **5** in `i1`, +and another **5** in `i2`. +What happens if we change the value of `i2`? + +```pike +i2 = 17; +``` + +Well, again as expected, +the value in the variable `i2` changes. +The value in `i1` of course doesn't: + +![referencesnot3](referencesnot3.gif) + +*Two non-reference variables, after the change* + +But with complex types, such as arrays, +things are a bit different. +To illustrate this, +we define an array variable, `a1`: + +```pike +array(int) a1; +``` + +This variable is of the type "array(int)", +so we can use it to store arrays of integers. +So let's do just that. +We create an array, +and put that array in `a1`: + +```pike +a1 = ({ 19, 3, 5 }); +``` + +Inside the computer, +it now looks like this: + +![references1](references1.gif) + +*A reference variable* + +Note that `a1` doesn't actually contain the array, +it just contains a "pointer" or "reference" to the array. + +What happens if we try to do +the same thing as we did with the integers above, +that is, copy the value to a new variable, +and then change the value in that new variable? + +To show what happens, +we define a new array variable, `a2`, +and try to copy the array `a1` to this new variable: + +```pike +array(int) a2; +a2 = a1; +``` + +This is where things are different. +Remember that the variable `a1` doesn't contain the real array, +but just a reference to it, +and that an expression of the type + +```pike +a2 = a1; +``` + +means "take whatever there is in `a1`, +make a copy of it, and put that copy it in `a2`". +Because of this, +what gets stored in `a2` is a copy of the *reference*, +not of the array: + +![references2](references2.gif) + +*Two reference variables, before the change* + +Note that both `a1` and `a2` now point to the same array. +If we now try to change `a2`, +for example by changing the last element in `a2` from **5** to **17**: + +```pike +a2[2] = 17; +``` + +what will change is the array pointed to by the reference in `a2`: + +![references3](references3.gif) + +*Two reference variables, after the change* + +If we don't think about the fact +that `a1` and `a2` just contain references, +pointing to the same array, +it would seem as if our change to the variable `a2` had, +in some mysterious way, +also changed the contents of the variable `a1`! + +If we want a real copy, +and not just a reference to the same array, +we must create that copy explicitly. +We can use the function `copy_value` for this: + +```pike +a2 = copy_value(a1); +``` + +This will create a copy of the array, +and store a reference to that copy in `a2`: + +![references4](references4.gif) + +*Two reference variables, pointing to different things* + +Note that `copy_value` creates a *recursive* copy, +which means that if the array contains other arrays, +it will create copies of those arrays too, +and so on. +A trick for creating a non-recursive copy of an array +is to add an empty array: + +```pike +a2 = a1 + ({ }); +``` + +The result of the expression `a1 + ({ })` +is a new array that is a copy of `a1`. + +The following data types in Pike are **basic types**, +and are stored in the variables themselves: + +* `int` +* `float` +* `string` + +The following data types in Pike are **reference types**, +and what is stored in the variables +are just references to the data objects: + +* `array` +* `mapping` +* `multiset` +* `program` +* `object` +* `function` + +Note that the same difference applies to method calls. +When you send data to a method as arguments, +and when you return data as the value of the method, +what is actually sent is either the values themselves (for the basic types), +or references (for the reference types). diff --git a/data_types/references1.gif b/data_types/references1.gif new file mode 100644 index 0000000..cad1c33 Binary files /dev/null and b/data_types/references1.gif differ diff --git a/data_types/references2.gif b/data_types/references2.gif new file mode 100644 index 0000000..595af25 Binary files /dev/null and b/data_types/references2.gif differ diff --git a/data_types/references3.gif b/data_types/references3.gif new file mode 100644 index 0000000..6b32b4f Binary files /dev/null and b/data_types/references3.gif differ diff --git a/data_types/references4.gif b/data_types/references4.gif new file mode 100644 index 0000000..0660417 Binary files /dev/null and b/data_types/references4.gif differ diff --git a/data_types/referencesnot1.gif b/data_types/referencesnot1.gif new file mode 100644 index 0000000..f94aaf9 Binary files /dev/null and b/data_types/referencesnot1.gif differ diff --git a/data_types/referencesnot2.gif b/data_types/referencesnot2.gif new file mode 100644 index 0000000..cddf7db Binary files /dev/null and b/data_types/referencesnot2.gif differ diff --git a/data_types/referencesnot3.gif b/data_types/referencesnot3.gif new file mode 100644 index 0000000..ed9ea21 Binary files /dev/null and b/data_types/referencesnot3.gif differ diff --git a/data_types/variable_definitions.md b/data_types/variable_definitions.md new file mode 100644 index 0000000..a379caa --- /dev/null +++ b/data_types/variable_definitions.md @@ -0,0 +1,96 @@ +# Variable Definitions + +## Zero is special + +The value zero (**0**) is a special case. +It is not just an integer value, +but can also be used to mean "no value" for all the types, +and not just integers. +If you create a variable and don't put a value in it, +it starts with the value **0**. + +Some effects of this may be surprising to C programmers: + +```pike +float f; // Now, f contains the **integer** value 0. +f = f + 1;// Now, f contains the **integer** value 1. +f = 0; // Now, f contains the **integer** value 0 again! +f = 0.0; // Now, f contains the **real** value 0.0. +``` + +It's important to note that +the integer value 0 +and the real value 0.0 +are not equal to one another in Pike. +It is also worth noting + that uninitialized strings, +as all other uninitialized variables, +start at 0. +If you don't take this into account, +and write code that successively builds some form of answer, +reply or similar: + +```pike +string accumulate_answer() +{ + string result; + // Probably some code here + result += "Hi!\n"; + // More code goes here + return result; +} +``` + +you will get a string `"0Hi!\n"`, +since Pike will try to make the best of the situation, +adding your string to the integer 0. +Had you instead initialized the variable to `""`, +as in `string result = "";`, +you'd get a better result. + +## How to specify data types + +In general, you just use the name of the data type: + +```pike +int number_of_wolves; +Protocols.HTTP.Query this_web_page; +float simple_plus(float x, float y) { return x + y; } +``` + +You can also use the data type `mixed`, +meaning any type of value: + +```pike +mixed x; +array(mixed) build_array(mixed x) { return ({ x }); } +``` + +The variable `x` can contain any type of value. +The method `build_array` takes an argument of any type, +and returns it inside an array. + +Pike also lets you use "or" notation for datatypes, +saying that a value is one of several possible datatypes: + +```pike +int|string w; + +array(int|string|float) make_array(int|string|float x) +{ + return ({ x }); +} +``` + +The variable `w` can contain either an integer or a string. +The method `make_array` takes an integer, +a string or a floating-point number as argument, +and returns it inside an array. + +If you know that a variable will contain strings or integers, +it is usually better to use `string|int` than `mixed`. +It is slightly longer to write, +but it allows Pike to do type checking +when the program is compiled and executed, +thus helping you to ensure +that your program works as it should. diff --git a/data_types_2/index.md b/data_types_2/index.md new file mode 100644 index 0000000..1b5c410 --- /dev/null +++ b/data_types_2/index.md @@ -0,0 +1,264 @@ +# More About Data Types + +# The Basic Types + +These are the **basic types** in Pike: + +* integer (written `int` in Pike) +* floating-point number (written `float`) +* string (written `string`) + +They are basic in the sense that +data items of these data types +can't contain other data items. +When a data item of a basic type is stored in a variable, +it is the data item itself that is stored, +and not just a reference to it, +as explained earlier. + +## The Data Type `int` + +Integer values can be written in several ways: + +* In decimal (that is, base 10) format, + i e the normal way to write numbers, + such as `78`. + +* In octal (that is, base 8) format, + with a leading `0`, such as `0116` + (which is equal to `78` in decimal notation). + +* In hexadecimal (that is, base 16) format, + with a leading `0x`, such as `0x4e` + (which is also equal to `78` in decimal notation). + +* In binary (ones and zeroes) format, + with aleading `0b`, such as `0b1001110` + (which again is equal to `78` in decimal notation). + +* As a character literal within single quotes, + which will give the Unicode code point for that character. + For example, + `'N'` will give the code point for the character **N** + (which is equal to `78`). + +You can use normal arithmetic operations, +such as addition and multiplication, with integers, +but you can also consider integers +as sequences of bits and, +apply bitwise operations on them. + +For example, +the integer value **247** +is stored internally +as the sequence of bits **11110111**, +and you could left-shift it three positions +with the expression `247 << 3`, +giving the bit pattern **11110111000**, +which is equal to **1976**. + +Integers in Pike can be very large. +For small integers +(usually less than 2 billion or so), +Pike will use the computer's own, +hardware-supported way of representing integers. +For larger integers, +Pike will use "bignums". +These are slower, +but can be arbitrarily large. +Just like the smaller integers, +bignums are represented exactly, +without any rounding errors. + +As a programmer, +you will usually not need to worry +about the difference between bignums and smaller integers. +There may however be some operations, +for example certain methods in certain C modules, +that cannot handle bignums but work with smaller integers. + +Some operations that you can apply to integers: + +* **Check if it is an integer** + + `intp(*something*)` returns **1** + if the value *something* is an integer, + otherwise **0**. + Example: + + ```pike + if (intp(u)) + write("The integer is " + u + ".\n"); + else + write("It is not an integer.\n"); + ``` + +* **Get a random number** + + `random(*limit*)` returns a random value + which is greater or equal to **0** + and less than the integer *limit*. + +* **Reverse the bits** + + `reverse(*integer-value*)` returns an integer + with the bits in the *integer-value* + in reverse order. + +## The Data Type `float` + +Real numbers, +which are numbers that can have a fractional part, +such as **18.34** and **-1000.03**, +are represented in the computer as **floating-point numbers**. +Floating-point numbers can be used +to represent very large numbers, +but with limited precision. +The number of significant digits is the same, +no matter the magnitude of the value. + +You can write floating-point values in two ways, +as usual with decimals, +or in exponential form with an `e`: + +```pike +3.1415926535 +-123.0001 +12.0 +1e6 // 1 times 10 to the power of 6, i e one million +2.0e-6 // 2.0 times 10 to the power of -6, i e two one-millionths +-1.0e-2 // Minus one hundredth +``` + +Some operations that you can apply to floating-point numbers: + +* **Check if it is a floating-point number** + + `floatp(*something*)` returns **1** + if the value *something* is a floating-point number, + otherwise **0**. + +* **Round downwards** + + `floor(*float-value*)` returns the largest integer + that is less than or equal to *float-value*, + but as a floating-point number. + For example, + `floor(7.3)` gives **7.0** + (and not the integer **7**). + If you do want the integer value, + you can use an explicit type conversion: + `(int)7.3` gives you the integer **7**. + +* **Round upwards** + + `ceil(*float-value*)` returns the smallest integer + that is greater than or equal to *float-value*, + as a floating-point number. + For example, + `ceil(7.3)` gives **8.0** + (and not the integer **8**). + +## The Data Type `string` + +Strings are sequences of characters, +and are written within double +quotes (`"`) in Pike: + +```pike +"scorch" +"Hello world!" +"Woe to you, oh Earth and Sea" +"" +``` + +The last one is the empty string. +Special characters, +such as the double quote character, +need to be preceded by a backslash character (`\`): + +* `\"` to get a double quote (`"`) in the string +* `\\` to get a backslash character (`\`) +* `\n` to get a newline character +* `\t` to get a tab character +* `\r` to get a carriage return +* `\0` to get a NUL character, + i e the character with character code **0** + +Here are some examples of strings: + +```pike +"One line\nAnother line\nA third line" +"Strings are written within \" characters." +``` + +You can use Unicode code points +instead of the characters themselves. +If you write `\d` followed by a decimal +(that is, normal base 10) number, +it will be replaced by the character +with that Unicode code point. +The same goes for `\x` followed by a hexadecimal +(base 16) number, +and a single `\` followed by an octal +(that is, base 8) number. +The `\0` is actually an example of this. +These four strings are identical: + +```pike +"Hello world" +"Hello \d119orld" +"Hello \x77orld" +"Hello \167orld" +"\d78""2OH" // "N2OH" +``` + +If the character following your code point number is also a number, +follow your code point with `""`, +to tell Pike that this was the end of your code point, +and the following "2" is its own character, +not another digit of the code point. + +Strings in Pike are what we call "shared", +which means that if two or more strings +contain exactly the same characters, +there will still be only one copy of it in memory. + +Some operations that you can apply to strings: + +* **Check if it is a string** + + `stringp(*something*)` returns **1** + if the value *something* is a string, + otherwise **0**. + +* **Concatenation** + + Strings can be concatenated with the `+` operator: + + ```pike + string s1 = "Hello"; + string s2 = " "; + string s3 = "world!"; + write(s1 + s2 + s3 + "\n"); + ``` + +* **Concatenation of string literals** + + **String literals**, + who are strings within double quotes + that are written in a program, + can be concatenated by just putting them after each other: + + ```pike + write("Hello" " " "world!" + "\n"); + ``` + + (This is, incidentally, + how the terminated numeric escapes above + work under the hood.) + +Pike has many powerful built-in operations +for working with strings. +Read more about those +in the chapter about string handling. diff --git a/fundamentals/index.md b/fundamentals/index.md new file mode 100644 index 0000000..172ce48 --- /dev/null +++ b/fundamentals/index.md @@ -0,0 +1,262 @@ +# Fundamental Concepts + +This tutorial assumes +that you are familiar with some fundamental concepts +that are used in all programming environments. +Look through the list, +and if you don't immediately know what one of the terms means, +you should read the explanation. + +## Program + +A program consists of a set of instructions +that tells the computer how to do something, +plus some data that the program can work with. +Programs can be organized in different ways, +and are often divided into several smaller parts. + +## Data + +The things that your program works with, +such as integers (for example **5** and **-3**) +and character strings (such as "hello" and "Hi there, John!") +are data. + +## Value + +One piece of data (for example the integer **5**) +is sometimes called a **value**, +and sometimes a **data item** or **data object**. +(But the word **object** also has a more specialized meaning +in connection with object-oriented programming. +More about that later.) + +## Variable + +A variable is a sort of box that can be used to store a value. +The variable usually has a name and also a type. +The type determines which values you can put in the variable. + +## Constant + +A constant is in a way the opposite of a **variable**, +but also similar. +A constant is like a variable, +in the sense that it is a sort of box +that can be used to store a value, +and that it has a name. +But once you have defined it, +it can not be changed. +Constants are often used to give names to certain values +in order to make a program easier to understand: +`minimum_income_tax` somewhere in a program +is easier to understand than just `20000`. +Sometimes the term constant is used to include **literals** too. + +## Literal + +A literal is a value of some kind, written in the program. +`"Hello"` is a string literal, +-678` is an integer literal, +and `({ 7, 8, 9 })` is an array literal. +Sometimes the term **constant** is used to include literals too. + +## Identifier + +An identifier is a sequence of characters +that can be used in a program as a name, +of a variable or of something else. +In Pike, an identifier must start with an alphabetical letter +or an underscore character ("_"). +The rest of the characters can be alphabetical letters, +underscores, and digits. +Some valid identifiers in Pike are +`n`, `number_of_9s`, and `DoNotFeedTheMonkey`. + +## Data type + +Values and variables have **data types**. +The value **5** has the data type **integer** +(spelled `int` in Pike), +and **5.14** has the type real number +(which is spelled `float` in Pike). +You can only put values in a variable +if the types of the value and the variable are compatible. + +## Type checking + +Pike has type checking, +which means that Pike keeps track +of the data types of variables and values. +If your program tries to put one type of value +in a variable which was designed to hold another type of value, +Pike may detect this, +and tell you about the problem. + +## Expression + +An expression is a piece of a program that gives a value +when it is executed by the computer. +An example of an expression in Pike is `5 * x + 7`, which means +"take the value of the variable `x`, +multiply it with **5**, +and then add **7**". +The computed result of an expression also has a type, +and in this case the type is `int`. + +## Statement + +A statement is a command that is part of a program, +and that the computer can interpret and execute. + +## Control structure + +The instructions in a program must be executed in the right order, +and this order is expressed using control structures. +Examples of control structures are selection (such as the **if** statement) +and loops (such as the **while** loop). +More about those later. + +## True and false + +Control structures such as **if** do one thing or another, +depending on a condition. +If the condition is true, it does one thing, +and if it is false, it does another thing. +Some languages have special data values, +called "true" and "false", that are used for this. +In Pike, we use the simpler convention that +the value zero (**0**) is interpreted as false, +and everything else is interpreted as true. + +## Truth value + +True and false are sometimes called **truth values**. + +## Block + +A **block** or **compound statement** +is a statement that consists of several other statements. +In Pike, we use the curly brackets "{" and "}" +to group statements into blocks. +Some other languages use the words "begin" and "end". + +## Function + +Most programming languages allow you to divide your program into smaller parts. +These can be called "sub-routines", "procedures", "functions" or "methods". +A function receives some values as input, +and produces some value as output. +A simple example is a function called "plus", +which receives two integers, called "x" and "y", +and returns their sum. +In mathematical notation, +this would be written something like "plus(x, y) = x + y". +In Pike, we write "`int plus(int x, int y) { return x + y; }`". + +## Method + +In object-oriented programming (which is explained more below), +functions belong to a certain class, +and they work mainly with the data belonging to that class. +Such a function, which belongs to a class, +is usually called a "method". +In Pike, all the functions that you define are actually methods. +We will use the term "method" in the rest of this tutorial. + +## Method call + +When one part of program needs to execute another part of the program, +and that other part is a method, +we say that it "calls" that method. +In Pike, we would write "`plus(3, 5)`" +to call the method `plus` mentioned above. +The values 3 and 5 are then sent to the method, +it adds them, and the result 8 is sent back from the method. + +## Argument + +When we call a method we send values to it. +The values that are sent to the method are called "arguments", +or "actual arguments". +In the example with the call to `plus` above, +the arguments are `3` and `5`. + +## Parameter + +A method needs to have some names +that it can use to refer to the argument values +that are sent to it when it is called. +These names are called "parameters" or "formal parameters". +In the example with the method `plus` above, +the parameters are `x` and `y`. +In most programming languages, and in Pike, +the parameters work just like variables which are local in the method, +and which get the arguments as initial values. + +## Local + +A variable that is local in a piece of code, such as a method, +is only available to the code inside that piece. +Other methods can have their own local variables with the same name, +but they are all different variables: +different boxes to store things in. + +## Returning from a method + +When a method has finished what it has to do, +we say that it **returns**. +The program will then continue executing +immediately after the place of the method call. +If the method has produced a value, +we say that we **return that value**. + +## Object-oriented programming + +In object-oriented programming, +we do not only divide the program into subprograms +("functions" or "methods"), +but group data and methods into "classes". +This makes it easier to write programs, +since we can work with one piece (that is, class) at a time. + +## Class + +This is a sort of "module", +used in object-oriented programming. +Usually a class is a description of a type of thing +(such as "cat", "animal" or "Internet connection"), +and it has both data and operations: +animals have a weight and a color, +and the Internet connection can change the connecting speed +and close the connection. +In Pike, the word **program** is sometimes used to mean class. + +## Object + +A class is a description of a type of thing (such as "cat"), +and an object is one such thing (such as one particular cat). +Sometimes we say that an object is an **instance** or a **clone** of a class: +all cats are instances of the cat class. + +## Source code + +The source code is the program itself, +as written by the programmer. +The source code is usually stored in one or more text files. + +## Syntax + +The syntax for a programming language is the grammar for the language, +i e the rules for how the source code is written. +The syntax only describes how the language looks, +not what it actually does. + +## Compilation + +Compiling is the process of translating the source code +to a format that the computer can execute. +This format can be machine code, +which is directly executable by the computer. +It can also be an intermediate format, +which has to be interpreted by another program. diff --git a/hello/alertwindow.gif b/hello/alertwindow.gif new file mode 100644 index 0000000..5d3c8b1 Binary files /dev/null and b/hello/alertwindow.gif differ diff --git a/hello/index.md b/hello/index.md new file mode 100644 index 0000000..408105e --- /dev/null +++ b/hello/index.md @@ -0,0 +1,149 @@ +# First Steps + +It is traditional to start a book or tutorial +about a programming language +with a very simple example: +a program that just writes the text "Hello world!" +on the screen. +Here it is in Pike: + +```pike +int main() +{ + write("Hello world!\n"); + return 0; +} +``` + +To run this program, +you will write it in a text file, +for example called "`hello.pike`", +and then run it. +If you are using a text-based interface, +such as a Unix command shell +or the Command Prompt Window in Windows NT, +you can run the program by typing the command +"`pike hello.pike`". + +If you are using a graphical interface +where the file is shown as an icon, +such as the Windows Explorer, +or a graphical file manager in Unix, +you may be able to run the program +by dragging its icon and dropping it on the Pike interpreter, +or by double-clicking on the program icon. + +All this assumes that Pike has been installed on your computer. + +When you run the program, it will (surprise, surprise) print + +``` +Hello world! +``` + +on the screen. +(In a graphical environment, +this text may pop up in a separate window.) + +## Explaining the "hello world" program + +If we start in the middle of this program, the line + +```pike + write("Hello world!\n"); +``` + +is the central part of the program. +We are using the built-in function `write`, +which prints text to the so-called **standard output**. +The standard output is usually the computer screen. + +Between the parentheses after `write` +we have put the **arguments** that we send to the function. +In this case, +there is only one argument, +the text `"Hello world!\n"`. +The double quotes (`"`) signify that it is a **string**, +i e a sequence of characters. +The combination `\n` is translated to a **newline character**, +so the next thing that is printed on the screen +after the greeting +will come on a different line. + +We cannot let a line like this stand by itself in a program. +It must be contained in a larger construct +called a **function**, or **method**. +We therefore enclose it in the method `main`: + +```pike +int main() +{ + write("Hello world!\n"); +} +``` + +This (as yet unfinished) program means +that there exists a method called `main`, +and that this method will print a greeting +to the standard output as explained before. +The `int` before `main` means that +(besides doing the printing) +the method will also return a value, an integer, +to whatever it is that uses it. +But we have not specified which value it will return, +so we add a line that does this, +finally yielding the complete program: + +```pike +int main() +{ + write("Hello world!\n"); + return 0; +} +``` + +When Pike runs (or "executes") a file like this one, +it always starts by calling `main`. +When `main` is finished, +the program stops executing, +and the returned value is used to indicate +whether the program succeeded to do what it was supposed to do. +Returning the value 0 from `main` means success. + +A semi-colon (`;`) signifies the end of a so-called **statement**. +This program contains two statements: +the use of `write`, +and the returning of a value. +In the good old days, +statements would have been called "program lines", +since you had to have a statement on each line, +but nowadays most programming languages +allow you to write in "free format", +dividing your program into lines +in any way that you feel makes it easy to read. +There are still some constraints: +you can't split words, +and you can't start a new line in the middle of a quoted string. +This is the same program as before, +but rearranged: + +```pike + int +main ( ) {write ( +"Hello world!\n"); return + + 0; } +``` + +Ok, those changes probably didn't make the program +easier to read and understand, +but there are many quite legitimate variations +in how programmers choose to write. +For example, this is another common style: + +```pike +int main() { + write("Hello world!\n"); + return 0; +} +``` diff --git a/hello/interactive.md b/hello/interactive.md new file mode 100644 index 0000000..a2adb48 --- /dev/null +++ b/hello/interactive.md @@ -0,0 +1,70 @@ +# Interactive Pike + +You can use Pike interactively, +which means that you type a line at a time, +letting Pike execute it immediately. +Just start Pike by giving the command `pike`, +without any command line arguments. +Then type a statement, for example: + +``` +> pike +Pike v8.0 release 28 running Hilfe v3.5 (Incremental Pike Frontend) +> write("hello!\n"); +``` + +Pike will then do what you told it to do, +i e print "hello!" on a line: + +``` +> pike +Pike v8.0 release 28 running Hilfe v3.5 (Incremental Pike Frontend) +> write("hello!\n"); +hello! +``` + +Similar to `main`, the built-in function `write` returns a value, +which happens to be the number of characters it has written. +Interactive Pike will also show you this return value: + +``` +> pike +Pike v8.0 release 28 running Hilfe v3.5 (Incremental Pike Frontend) +> write("hello!\n"); +hello! +(1) Result: 7 +> +``` + +The return value from write is the number of characters written, +which in this case is seven characters; +`h`, `e`, `l`, `l`, `o`, the exclamation mark, and the newline character. +The one in parenthesis at the beginning of the line +tells you that this is the first result in the session's history, +if you want to refer to it in subsequent expressions. + +``` +> pike +Pike v8.0 release 28 running Hilfe v3.5 (Incremental Pike Frontend) +> "hello"; +(1) Result: "hello" +> _; +(2) Result: "hello" +> _ + " world!"; +(3) Result: "hello world!" +> __[1]; +(4) Result: "hello" +``` + +For convenience, +the interactive pike session offers two automatic variables: +`_`, which holds the most recent result, and +`__`, which lets you index out any result in session history by id. + +Running Pike interactively like this +can be very useful when testing things, +for example when you are following this tutorial. +It can also be used as a very advanced calculator. +*But beware! +Some things don't work the same way in interactive mode +as they do when you run a Pike program from a file!* diff --git a/hello/window.md b/hello/window.md new file mode 100644 index 0000000..a627d8e --- /dev/null +++ b/hello/window.md @@ -0,0 +1,83 @@ +# I Want My Greeting in a Window! + +Pike has support for graphical user interfaces. +If you have the GTK Pike module installed on your computer, +you can use a slightly modified program to print "Hello world!" +in its own window: + +```pike +int main() +{ + GTK.setup_gtk(); + GTK.Alert("Hello world!"); + return -1; +} +``` + +The statement "`GTK.setup_gtk();`" is a call to a method, +similar to the call to `write` in our first example. +The difference here is that `setup_gtk` +is found in a module called `GTK`, +so we must prefix it with "`GTK.`" +to let Pike know where to look for it. + +The next statement, "`GTK.Alert("Hello world!");`", +creates a small window, an "alert window", +with the text "Hello world!" in it. +The window will look something like this: + +![alertwindow](alertwindow.gif) + +*The window that pops up when the GTK hello-world program is run* + +When you click on the "OK" button, +the window disappears. + +The last statement in `main` is "`return -1;`". +In Pike, a negative return value from `main` means +that the program doesn't stop executing when `main` is finished. +This is necessary here, +since otherwise the program would finish +as soon as it had created the window, +and the window would disappear at once. + +But there is a problem with this program. +The program doesn't stop executing when `main` is finished, +so when does it stop? +Never. +We may close the window, +but the program is still running. +It doesn't actually do anything, +but it is there. + +We can fix the problem like this: + +```pike +int main() +{ + GTK.setup_gtk(); + GTK.Alert("Hello world!") + -> signal_connect("destroy", lambda(){ exit(0); }); + return -1; +} +``` + +To explain this, think that + +```pike +GTK.Alert("Hello world!") +``` + +creates the Alert window. +The Alert window is a thing, or an "object". +It not only pops up on your computer screen, +but you can also let your program do things with this object. +For example, +you can tell the window that when it is destroyed, +it should order the entire program to exit. +This is what the rest of of the statement does +(even if we don't explain the exact details here): + +```pike +-> signal_connect("destroy", lambda(){ exit(0); }); +``` diff --git a/index.md b/index.md new file mode 100644 index 0000000..80e62f0 --- /dev/null +++ b/index.md @@ -0,0 +1,115 @@ +# Pike Beginner's Tutorial + +The first version of this tutorial, +influenced by an old Pike tutorial by Fredrik Hübinette, +was completed by Thomas Padron-McCarthy on February 29, 2000. +Maintenance since then has been in the hands of the pike development team, +and we would hope that you too would want to participate, +helping out and contributing updates, +pointing out what could be improved upon, and how. +Join us! + +OBSERVE: Some of the examples are showing their age +and need to be updated to the latest Pike version. +If you are having problems, +ask for help on the Pike mailing list +or read the reference manual if you feel up to it. + +* [Introduction](introduction/index.md) + * [What is Pike?](introduction/index.md) + * [What Does Pike Look Like?](introduction/first_glance.md) + * [Pike and Some Other Languages](introduction/language_comparison.md) + * [Reading this Tutorial](introduction/reading_this_tutorial.md) + +* [First Steps](hello/index.md) + * [Hello World](hello/index.md) + * [I Want My Greeting in a Window!](hello/window.md) + * [Interactive Pike](hello/interactive.md) + +* [Fundamental Concepts](fundamentals/index.md) + * [Terminology / Glossary](fundamentals/index.md) + +* [Your Second Pike Program](browser/index.md) + * [The Bare Bones](browser/index.md) + * [Running the Program](browser/invocation.md) + * [Command-line Arguments and if](browser/arguments_and_if.md) + * [Methods and Loops](browser/methods_and_loops.md) + * [Magic Web Stuff](browser/fetching_the_page.md) + * [Syntactic Sugar](browser/convenient_syntax.md) + * [Showing the Page](browser/show_page.md) + * [Some Notes About WWW](browser/about_www.md) + +* [An Introduction to Data Types](data_types/index.md) + * [What is a data type?](data_types/index.md) + * [Basic Types](data_types/basic_types.md) + * [Container Types](data_types/container_types.md) + * [Object, Program and Function](data_types/other_types.md) + * [Variable Definitions](data_types/variable_definitions.md) + * [Basic Types and Reference Types](data_types/reference_types.md) + +* [Methods](methods/index.md) + * [An Introduction](methods/index.md) + * [Calling a method](methods/invocation.md) + * [More Advanced Examples](methods/advanced.md) + +* [Object-Oriented Programming](oop/index.md) + * [Object Orientation in General](oop/index.md) + - [Object Orientation in Pike](oop/oo_in_pike.md) + - [Creating and Using Objects](oop/creation_and_usage.md) + - [How to Create a Class](oop/create.md) + - [Classes as Record Types](oop/grouping_data.md) + - [Programs are Classes and Vice Versa](oop/programs.md) + - [Inheritance](oop/inheritance.md) + - [Multiple Inheritance](oop/multiple_inheritance.md) + - [Access control](oop/access_control.md) + +- [Statements](statements/index.md) + - [Choosing between Alternatives](statements/index.md) + - [Repetition (or "Loops")](statements/loops.md) + - [Other Statement Types](statements/others.md) + +- [More About Data Types](data_types_2/index.md) + - [The Basic Types](data_types_2/index.md) + - [Container Types](data_types_2/container_types.md) + - [The Other Reference Types](data_types_2/other_types.md) + +- [Working with Strings](strings/index.md) + - [Operators on Strings](strings/index.md) + - [Built-in Functions for Strings](strings/builtins.md) + - [Composing Strings with sprintf](strings/sprintf.md) + - [Analyzing Strings with sscanf](strings/sscanf.md) + - [Wide Strings](strings/widestrings.md) + +- [Expressions](expressions/index.md) + - [Some Terminology](expressions/index.md) + - [Arithmetical Operations](expressions/arithmetics.md) + - [Operations on Complex Types](expressions/complex_types.md) + - [Comparison](expressions/comparison.md) + - [Logical Expressions](expressions/logical.md) + - [Bitwise Operations](expressions/bitwise.md) + - [Operations on Sets](expressions/set_operations.md) + - [Indexing](expressions/indexing.md) + - [Assignment](expressions/assignment.md) + - [Type Conversions](expressions/casting.md) + - [The Comma Operator](expressions/comma.md) + - [Call and Splice](expressions/call_and_splice.md) + - [Operator Precedence and Associativity](expressions/operator_tables.md) + +- [The Preprocessor](preprocessor/index.md) + - [Preprocessor Directives](preprocessor/index.md) + +- [Modules](modules/index.md) + - [Some Examples of Modules](modules/index.md) + - [How Do You Use a Module?](modules/usage.md) + - [How Do You Create a Module?](modules/creating.md) + - [How Does Pike Find the Modules?](modules/resolving.md) + +- [Errors and Error Handling](error/index.md) + - [Error Messages from Pike](error/index.md) + - [Error Handling: the Concept](error/concept.md) + - [Detecting an Error](error/detection.md) + - [Handling the Error](error/handling.md) + - [Error Codes](error/codes.md) + - [`catch` and `throw`](error/exceptions.md) + +* [Not Covered Here](not_covered/index.md) diff --git a/introduction/first_glance.md b/introduction/first_glance.md new file mode 100644 index 0000000..a16a3d3 --- /dev/null +++ b/introduction/first_glance.md @@ -0,0 +1,39 @@ +# What Does Pike Look Like? + +Here is a small Pike program: + +```pike +int main() +{ + write("Hi there! What's your name?\n"); + string name = Stdio.stdin->gets(); + write("Nice to meet you, " + name + "!\n"); + return 0; +} +``` + +Programmers with some experience +from programming languages such as C, C#, and Java +will not have much trouble understanding what this program does. +Pike looks a lot like those languages, +and for example uses the "curly brackets" "{" and "}" +to organize program code into blocks. +An excerpt from a Pike program usually does the same thing +that a similar-looking program fragment in C, C# and Java would do. +Exactly *how* it is done can be very different, though. + +Even if you have never seen any code in C, C# or Java before, +perhaps it doesn't come as a surprise if I tell you that +the program writes `Hi there! What's your name?` on the screen, +then waits for you to type your name, +and finally tells you that it is nice to meet you? + +All those backslashes (that is, "\") and semicolons (";") +can be a bit confusing at the start. +Getting comfortable with the syntax +(that is, how a program looks on the surface) +is often the most difficult part about learning Pike. +On the other hand, experience shows that +this is the syntax that most people feel is easy and productive +when they have become used to it, +and that is the reason why we keep it as it is. diff --git a/introduction/index.md b/introduction/index.md new file mode 100644 index 0000000..5678880 --- /dev/null +++ b/introduction/index.md @@ -0,0 +1,51 @@ +# Introduction + +## What is Pike? + +Pike is an interpreted, object-oriented programming language. +It looks a bit like C and C++, +but it is much easier to learn and use. +It can be used for small scripts as well as for large programs. + +Pike is + +* high-level and powerful, + which means that even very complex things + are easy to do in Pike, + +* object-oriented, + which means that you can use modern programming techniques + to divide a large program into small pieces, + which are much easier to write + than it would be to write the entire program at once, + +* interpreted, + which means that you don't have to wait + for a program to compile and link + when you want to run it, + +* one of the fastest "scripting" languages available, + +* garbage-collected, + which makes programming much simpler, + and also removes the risk for memory leaks + and other memory-related bugs, + +* easy to extend, + which means that you can create plug-ins, + written in Pike as well as in C or C++, + and integrate them with the rest of Pike. + +Pike can be used to write small and simple scripts, +and also for very large programs: +the World Wide Web servers Roxen WebServer and Caudium +are both written in Pike. +Pike's advanced data types and built-in support for sockets +makes it ideal for use in Internet applications. + +Pike is free software, +distributed under the GNU General Public License (GPL), +GNU Lesser General Public License (LGPL) +and Mozilla Public License (MPL). +Pike is available for many operating systems, +among them Linux, Solaris, OS X and Microsoft Windows. diff --git a/introduction/language_comparison.md b/introduction/language_comparison.md new file mode 100644 index 0000000..482a90f --- /dev/null +++ b/introduction/language_comparison.md @@ -0,0 +1,56 @@ +# Pike and Some Other Languages + +## C++ and C + +Pike looks a lot like C++ on the surface, +but is easier and safer to use. +Since it is interpreted, +it may be slower for some applications. +Pike is more flexible than C++, +and allows for a somewhat less rigid programming style +than what is necessary in C++. +Another difference is that +there are many different C and C++ compilers, +while there is only one implementation of Pike. + +## C# + +Pike is very similar to C#. +In fact, one could easily think that +some engineers at Microsoft and the other companies behind C# were Pike users. +The most noticable difference between the two +is probably that Pike has better standard types than C# +and doesn't require the use of libraries for type conversions et c. +If you are using C#, +you will find Pike very easy to use. + +## Java + +Pike looks a bit like Java on the surface. +Like Java, Pike is translated to an intermediate format, +which is then executed by an interpreter. +Java programs are usually distributed to the user +in this intermediate format, +but with Pike we use the source code. +This is feasible since compilation time, +i e the time it takes to translate the program to the intermediate format, +is near zero in Pike. + +## Perl + +Perl started on Unix systems as a system administration tool. +Both Pike and Perl are good at handling strings, +and both can be used to add functionality to web servers. +Perl is much more widely used than Pike. +Some programmers feel that the syntax of Perl is obscure. + +## Python + +Programs written in Python look very different from Pike programs, +but Python and Pike are similar when it comes to ideas and use. +Python is more widely used and has more libraries available. +Pike on the other hand is faster, +has a more advanced type system, +and has better support for object-oriented programming. +Pike's more C++-like syntax makes it easier to get started with +for programmers who know C++, C or Java. diff --git a/introduction/reading_this_tutorial.md b/introduction/reading_this_tutorial.md new file mode 100644 index 0000000..e9f5b6c --- /dev/null +++ b/introduction/reading_this_tutorial.md @@ -0,0 +1,75 @@ +# Reading this Tutorial + +This tutorial gives an introduction to the language Pike. It is not +a complete reference manual. It does not document the modules and +libraries that come with the Pike distribution, except for what is +necessary to explain the workings of the language itself. We also +assume that Pike has already been installed on your computer. How to +install Pike is explained elsewhere. + +The tutorial is mainly intended for people with at least some +experience of programming, for example from writing some JavaScript on +a web page, or trying to write CGI scripts on a web server in some +language. We assume that you now have a need for, or just an interest +in, using Pike. We also assume that you are willing to spend a few +hours on reading this introduction. We recommend that you try to run +the examples as you read them, since this will help your learning +greatly. + +Even total beginners at programming will be able to understand much +of what is said. If you have never programmed before it is +nevertheless a good idea to read a book or tutorial intended for +beginners. There are some general skills and ways of thinking that are +needed to write good programs, and a language tutorial such as this +one will not cover those in any depth. + +We have tried to make this tutorial platform-independent, meaning +that it will not matter if you are using Pike under Linux, Solaris, +Windows NT, or some other operating system. + +The following conventions for type faces are used: + +* **Boldface** is used for terms that have a special meaning. + Example: + + A **variable** can be seen as a sort of box where you can store a value. + It can also be used to show values, such as **7.3**. + +* `Fixed size` is used for something that is copied verbatim from the computer. + It can be parts of a program, + or something printed by the computer, + or something typed by the user. + Example: + + In Pike, the datatype integer is spelled `int`. + +* *Italics* can be used for emphasis, but also as a placeholder + for other things. + Example: + + In Pike, you can define a variable with "*datatype* *name*;", + where you replace *name* with the name of the variable, + and *datatype* with its type. + +* A bordered section of fixed-size text + represents an interactive session, + where user input is prefixed with a `> ` prompt. + The rest of the session's text is program output: + +``` +Hello, professor. +I see you brought the keys to the ferarri. +> run project 21 +Warming up particle accelerator... +``` + +* A bordered section of fixed-size, syntax-highlighted text + represents pike code. + Sometimes changes are highlighted with an end-of-line comment: + +```pike +void example() +{ + write("Hello!\n"); // This line was changed from the previous example +} +``` diff --git a/methods/advanced.md b/methods/advanced.md new file mode 100644 index 0000000..da5ce5a --- /dev/null +++ b/methods/advanced.md @@ -0,0 +1,57 @@ +# More Advanced Examples + +Here are two more examples of method definitions: + +```pike +int getDex() +{ + int oldDex = Dex; + Dex = 0; + return oldDex; +} + +private void +show_user(int|string id, void|string full_name) +{ + write("Id: " + id + "\n"); + if (full_name) + write("Full name: " + full_name + "\n"); +} +``` + +The method `getDex` returns the value of a non-local variable called `Dex`, +but also changes the value of that variable to zero (**0**). + +The method `show_user` expects to receive either one or two arguments. +The first argument can be either an integer or a string. +The second argument is optional, +but if it is present it must be a string. + +Here are some valid statements that contain calls to the two methods above: + +```pike +getDex(); +show_user(19); +show_user("john"); +show_user(19, "John Doe"); +show_user("john", "John Doe"); +``` + +## Side-effects in Methods + +When working with methods, +you may want to be careful with **side-effects**. +A side-effect is anything that the method causes to change or happen, +except for the returned value. +Sometimes the side-effects are the reason for the method, +and sometimes they are a dangerous misfeature. +In the three examples above, +`getDex` has the side-effect +of setting the value of the non-local variable `Dex` to 0, +and `show_user` has the side-effect +that it writes some text to the standard output. +We can guess that `show_user` has been created just to write that text, +so this side-effect of `show_user` is probably not a problem. +On the other hand, +if a programmer uses `getDex` to get the value of the variable `Dex`, +it could come as a surprise that this method also changes the value. diff --git a/methods/index.md b/methods/index.md new file mode 100644 index 0000000..175f5c0 --- /dev/null +++ b/methods/index.md @@ -0,0 +1,129 @@ +# An Introduction + +# Methods + +Most programming languages allow you +to divide your program into smaller parts. +These can be called +"sub-routines", "procedures", "functions" or "methods". +In Pike, we use the term "method". +Other parts of the program can **call** the method, +i e cause it to be executed. + +## How to create a method + +To create a method, +you must **define** it, +with a **method definition**. +A method definition follows this template: + +```pike +*access-modifiers* *type* *method-name*( *parameter-list* ) +*method-body* +``` + +Here is a description of the various parts in the definition template: + +* The *access-modifiers* are optional. + If they are present, + they control from where this method can be called. + An example of an access-modifier is `private`, + which makes it impossible for other programs to call this method. + +* The *type* is a **data type**, + which specifies the type of the value that the method returns. + It is sometimes called the "return type of the method", + or the "type of the method". + An example of a data type is `string`. + If the type is `void`, + the method is not supposed to return a value. + +* The *method-name* is the name of the method. + This is an identifier, + for example `plus`, `destroy_all_enemy_ships` or `mUndoLatestChange`. + A method should have a name + that correctly describes what the method does: + a method that prints a list of customers + should probably be called something like `print_customers`. + +* The *parameter-list* is a comma-separated list + of the parameters of the method. + A **parameter** acts like a variable, + which is local in the method, + and which gets the corresponding argument value + from the method call as its initial value. + Some examples of parameters are + "`int number_of_cars`" and "`string name`". + A method can have up to 256 parameters. + If the method doesn't expect to receive any argument values, + the *parameter-list* can be empty. + +* The *method-body* is a **block**, + and can contain statements and local definitions. + +Sometimes we talk of the **head** and the **body** of a method. +The body is of course the *method-body* in the template above, +while the head consists of everything in the method definition +except the body. +We can say that the method head +is a description of the method: +its name, which arguments it expects, +and what type of value it will return. +A part of the program that wants to **call** a method, +needs to know about the head of that method, +but not about the body. + +The **method body**, on the other hand, +contains the statements +that will be executed when the method is called. +The body is therefore a description of what, and how, +the method performs whatever it is that it does. + +Here is a simple example of a method definition: + +```pike +float average(float x1, float x2) +{ + return (x1 + x2) / 2; +} +``` + +The method `average` returns the average of its two arguments. +Both the return value and the two parameters are floating-point values. +Here are some valid statements that contain calls to `average`: + +```pike +float x = average(19.0 + 11.0, 10.0); +average(27.13, x + 27.15); +float y = average(1.0, 2.0) + average(6.0, 7.1); +float z = average(1.0, average(2.0, 3.0)); +``` + +When a method has finished what it has to do, +we say that it **returns**. +The program will then continue executing +immediately after the place of the method call. +If the method has produced a value, +we say that we return that value. + +The `return` statement is used to send a value from a method +back to the point from where it was called: + +``` +return *expression*; +``` + +The `return` statement will also cause Pike to leave the method, +and continue execution +immediately after the point where the call to the method was made. +You can have several `return` statements in the same method. +If the method is defined to return `void`, +you can use `return` without a value to leave the method: + +```pike +return; +``` + +If you reach the end of the body of a method, +without having returned first, +the method will return zero as return value. diff --git a/methods/invocation.md b/methods/invocation.md new file mode 100644 index 0000000..1e44934 --- /dev/null +++ b/methods/invocation.md @@ -0,0 +1,56 @@ +# Calling a method + +First of all, +Pike calculates the values of all the arguments. +In the call + +```pike +average(19.0 + 11.0, 10.0); +``` + +the two arguments are calculated, +giving the values **30.0** and **10.0**. +Then the argument values are sent to the method. +If we look at the method head, + +```pike +float average(float x1, float x2) +``` + +we see that it has two formal parameters. +The argument values will be put +in the two parameter variables `x1` and `x2`, +which work as local variables +but with the argument values as initial values. + +Execution will then continue with the body of the method. +In this case, the body is + +```pike +{ + return (x1 + x2) / 2; +} +``` + +The value of `(x1 + x2) / 2` will be calculated, +giving **20.0**. +This value is then returned to the point where the method was called, +and is used as the value of the method-call expression. + +Note that Pike uses "call by value". +This means that Pike always calculates the value of the arguments +before calling a method, +and then it sends those values +(or, more precisely: copies of those values) +to the called method. +This means that in the example + +```pike +average(1.0, average(2.0, 3.0)); +``` + +Pike will first call `average` with the two values **2.0** and **3.0**, +and when `average` has returned the value **2.5**, +it will send the two values **1.0** and **2.5** to `average`. +This second call of `average` will return **1.75**, +and this is the value of the entire expression. diff --git a/not_covered/index.md b/not_covered/index.md new file mode 100644 index 0000000..32e7fba --- /dev/null +++ b/not_covered/index.md @@ -0,0 +1,21 @@ +# Not Covered Here + +Here are some of the things not covered: + +* Many details, for example all the format specifiers to `sprintf` + +* Unnamed functions, with `lambda` + +* Operator functions, such as `'+` + +* Operator overloading in classes + +* `void my_function(mixed ... args)` + +* `at_exit()` + +* Type information with `typeof` + +* `_typeof` and `sprintf("%t", ...)` + +* Time measurement with `gauge` diff --git a/oop/access_control.md b/oop/access_control.md new file mode 100644 index 0000000..2a50e4f --- /dev/null +++ b/oop/access_control.md @@ -0,0 +1,82 @@ +# Access control + +Do you remember about **information hiding**? +In the examples above, +everyone could access all the methods and member variables in all objects. +For example, +it is very easy to lose weight: + +```pike +h->weight -= 10.0; +``` + +Oh? +The hamster only weighed 0.12, +and now it weighs *minus* 9.88? + +We would like to control the access to the member variable `weight`, +so that other classes cannot touch it. +For uses like this, +there are a number of **access modifiers**, +which are written before the data type +in the definition of a method or member variable. +For example, +the weight of an animal +is represented by the member variable `weight`, +defined as: + +```pike +float weight; +``` + +By changing that to + +```pike +private float weight; +``` + +we only allow methods in the same class to access that variable. + +The following access modifiers exist: + +* `public` + + This is the default, + and means that any method can access the member variable, + or call the method. + + +* `private` + + This means that the member variable or method + is only available to methods in the same class. + + +* `static` + + This means that this member variable or method + is only available to methods in the same class, + and in subclasses + (`static` in Pike does not at all + mean the same thing as `static` in C++: + instead, it is similar to `protected` in C++). + +* `local` + + This means that even if this method is overridden + by a method in a subclass, + methods in this class will still use this method. + + +* `final` + + This prevents subclasses from re-defining this method. + +If a class has a constructor +(that is, a method called `create`) +it can be a good idea to declare it `static`. +It is not supposed to be called +except during the construction of the object, +and if it is not `static` +there may be some type incompatibilities +in connection with inheritance. diff --git a/oop/create.md b/oop/create.md new file mode 100644 index 0000000..00d9673 --- /dev/null +++ b/oop/create.md @@ -0,0 +1,59 @@ +# How to Create a Class + +To create a class, +you write a **class definition**, +with all the member variables and methods. +For the class `animal`, +which we have used above, +the class definition may look like this: + +```pike +class animal +{ + string name; + float weight; + + void create(string n, float w) + { + name = n; + weight = w; + } + + void eat(string food) + { + write(name + " eats some " + food + ".\n"); + weight += 0.5; + } +} +``` + +Some explanations about this: + +* A member variable, + such as `name`, + exists once in each cloned object, + not in the class itself. + +* When a method, + such as `eat`, + refers to a member variable, + such as `weight`, + it will use that variable + in the same object that it was called for. + For example, + when we call `my_dog->eat("quiche")`, + it is the `weight` + in the object `my_dog` + that is increased. + +* The method `create` is special. + This method that handles the arguments + that you give when you clone an object. + (C++ programmers would call this a "constructor".) + +* You can also have a method called `destroy`. + This method is what C++ programmers would call the "destructor", + i e a method that is run just before the object disappears. + A destructor is sometimes needed for cleanup, + but much more seldom in Pike than in C++, + since Pike has automatic garbage collection. diff --git a/oop/creation_and_usage.md b/oop/creation_and_usage.md new file mode 100644 index 0000000..03d9268 --- /dev/null +++ b/oop/creation_and_usage.md @@ -0,0 +1,55 @@ +# Creating and Using Objects + +Assuming that we have the class `animal`, +we can define some variables +that can be used to store animals. +Remember that the class is also a **data type**. +We can also create some animals +to put in those variables. +To create an animal, +we use the syntax `*classname*()`, +i e the name of the class +followed by a pair of parentheses. + +```pike +animal some_animal; +some_animal = animal(); +animal my_dog = animal(); +``` + +To access a member variable in an object, +we use the syntax `*object-expression*->*variable-name*`, +i e the object followed by the operator `->` +followed by the name of the variable. + +```pike +my_dog->name = "Fido"; +my_dog->weight = 10.0; +some_animal->name = "Glorbie"; +write("My dog is called " + my_dog->name + ".\n"); +write("Its weight is " + my_dog->weight + ".\n"); +write("That animal is called " + some_animal->name + ".\n"); +``` + +Most objects need some initial values for its member variables. +For example, +every animal needs a name and a weight. +One way to handle this +is to set those variables separately, +as we have done above. +A better way is to design the class +in a way that lets it set the variables +immediately when an object is cloned from the class. +You can then give the values when cloning: + +```pike +animal piglet = animal("Piglet", 6.3); +``` + +We can call a method in an object, +with a similar "`->`" syntax: + +```pike +my_dog->eat("quiche"); // Real dogs eat quiche. +write("Its weight is now " + my_dog->weight + ".\n"); +``` diff --git a/oop/grouping_data.md b/oop/grouping_data.md new file mode 100644 index 0000000..993e4e5 --- /dev/null +++ b/oop/grouping_data.md @@ -0,0 +1,27 @@ +# Classes as Record Types + +Sometimes you just need to group a few values together. +This is called a "record" in Pascal, +and a "struct" in C. +You can use Pike's **class** mechanism for this too. +Just create a class with the data you are interested in: + +```pike +class customer +{ + int number; + string name; + array(string) phone_numbers; +} +``` + +Then use it: + +```pike +array(customer) all_customers = ({ }); +customer c = customer(); +c->number = 18; +c->name = "Ellen Ripley"; +c->phone_numbers = ({ "555-8767", "555-4001" }); +all_customers += ({ c }); +``` diff --git a/oop/index.md b/oop/index.md new file mode 100644 index 0000000..c203380 --- /dev/null +++ b/oop/index.md @@ -0,0 +1,117 @@ +# Object-Oriented Programming + +After half a century or so of computer programming, +we have learned that +**modularization** is a cornerstone of software development. +Modularization, in this context, +means that we divide a big problem into several smaller problems. +Then we write a number of programs or program parts, +each of them solving one of those small problems. + +It is usually easier to jump one foot high ten times, +than it is to jump ten feet high in one jump. +In the same way, +it is usually easier to write ten small programs, +and then integrate them to a complete system, +than it is to write the entire system at once. +(Ok, we may expect some objections against that analogy. +But the idea is the same in both cases, +and it works in practice: +small programs are almost always easier to write than big ones.) + +The small programs or program parts are usually called "modules". +Here, the term "module" is used in this general sense, +but you should make a mental note that in Pike, +the term **module** usually refers to a very specific kind of module, +the plug-in modules of Pike. + +For modularization to work well, +we need something that is called +**information hiding** or **encapsulation**. +This means that we hide the internal structure of each module, +so the rest of the system doesn't need to worry about it. +Think of it this way: + +If we build a locomotive in modules, +we want to build one module at a time, +and then bolt them together. +If the cogwheels and stuff inside those modules are sticking out, +outside the modules, +the cogwheels in one module will jam the cogwheels in another module. +The result is that the modularization doesn't work: +even if we have divided the locomotive into modules, +we still have to think about the cogwheels in all the other modules +when we design the cogwheels in this module. + +It is the same way with programs. +The modules have lots of stuff inside: +variables, loops, data structures. +All of that should be hidden inside the module. +Some programmers believe they should be so well hidden +that it is impossible to look at them. +Others feel that it is enough that you don't *have* to look at them. +Remember: the cogwheels shouldn't be sticking out. + +Obviously, we can't hide *all* the information. +The modules must interact in some way, +for example by sending data to each other. +The (few) things that are visible on the surface of a module, +for others to see and use, +is sometimes called its **interface**. + +So how do we modularize a program? +Which parts should we divide it into? +One way is to look at what it does. +You divide the thing it does into small things, +and you divide those small things into even smaller things. + +An even better way is to look at the *data* +that the program works with: +simple things like integers and strings, +and more complex things that often reflect real-world objects: +persons, aircraft, courses at a university. +Each such thing, +like that person over there, +is called an **object**, +and each *type* of thing, +like "person", is called a **class**. +As you may have guessed, +this is the basis of **object-oriented programming**. + +The class describes the things, +and not only what we know about them, +but also what we can do with them. +For example, a person may have a name and a birthdate, +but a person can also eat, sleep and talk. + +Sometimes we say that +an object is an **instance** or a **clone** of a class: +all persons are instances, or clones, +of the class "person". + +But to use object-oriented programming to its fullest, +we need two more mechanisms: **inheritance** and **polymorphism**. +Thanks to those, +you can easily add features to an existing module. +You can re-use all the work that was put into writing that module, +and just add your new features. + +If you need a class that describes birds, +and you already have a class called "animal" that describes animals, +you can create a new class that **inherits** from the "animal" class. +By inheriting, +a bird has all the attributes of an animal, +and can do everything an animal can do. +Then you just add whatever is specific to birds, +such as flying. +(Except that penguins don't fly, and bats do. +We ignore that for now.) + +**Polymorphism** means that whatever we can do with an animal, +we can also do with a bird. +If we already have some program code that counts animals or sorts them, +we can use the same program code to count or sort birds, +without changing anything. +So not only can we re-use the work that was put into the "animal" class: +we can also re-use the work +that was put into much of the rest of the program. diff --git a/oop/inheritance.md b/oop/inheritance.md new file mode 100644 index 0000000..062a2bb --- /dev/null +++ b/oop/inheritance.md @@ -0,0 +1,169 @@ +# Inheritance + +A class may **inherit** another class. +This means that the inheriting class +(also called **subclass** or **derived class**) +starts with all the methods and member variables that the inherited class, +(also called **superclass** or **base class**) has. +The subclass can then have its own, +additional methods and member variables. + +One situation when inheritance can be useful +is when you want to create two or more classes +that have a common part. +Birds and fishes, +for example, +are different, +with different characteristics, +but they do have much in common. +You can make use of this by creating a class, +for example called "animal", +with the common properties. +Then you define the two subclasses "bird" and "fish", +which inherit from "animal". + +At other times you already have a class +that almost does what you want it to, +but you would like to add something to it. +For example, +a class "connection", +which models an Internet connection, +may have everything you need +except for a time limit +on how long you can be connected. +You could then create a new class, +"restricted_connection", +which inherits from the old connection class, +but with the time limit added. + +In both of these situations, +we have what is sometimes called an **is-a relationship**: +a bird **is an** animal, +a restricted_connection **is a** connection. +We recommend that you use inheritance in this way: +to model is-a relationships. + +You use the keyword `inherit` +to let a class inherit from another class. +For example, +to create the sub-classes `bird` and `fish`, +which both inherit from `animal`, +you would write: + +```pike +class bird +{ + inherit animal; + float max_altitude; + + void fly() + { + write(name + " flies.\n"); + } + + void eat(string food) + { + write(name + " flutters its wings.\n"); + ::eat(food); + } +} + +class fish +{ + inherit animal; + float max_depth; + + void swim() + { + write(name + " swims.\n"); + } +} +``` + +A `bird` like Tweety can do anything an animal can do, +and it has all the data that an animal has. +But it can also fly (the method `fly`), +and it has a maximum altitude +(the member variable `max_altitude`). + +Note that the class `bird` has its own method called `eat`. +There was one in `animal` too, +but the new one **overrides** the old one, +and will be used in all `bird` objects. +If you have a method in the subclass +with the same name as a method in the superclass, +the module in the subclass **hides** or **overrides** +the method in the in superclass. + +If you still want to call the method in the superclass, +you can prefix the name with two colons (`::`). +That is what is done in the `eat` method: +after fluttering its wings at the sight of the food, +the bird will do the actual eating, +and that is done with a call to `::eat`. + +You can now use our two new classes: + +```pike +bird tweety = bird("Tweety", 0.13); +tweety->eat("corn"); +tweety->fly(); +tweety->max_altitude = 180.0; + +fish b = fish("Bubbles", 1.13); +b->eat("fish food"); +b->swim(); + +animal w = fish("Willy", 4000.0); +w->eat("tourists"); +w->swim(); +``` + +One thing that needs explaining is the last line in the example above: + +```pike +w->swim(); +``` + +The variable `w` is of type `animal`, +and that class has no method called `swim`. +But that doesn't matter, +since Pike always looks at the **object** +that is stored in the variable. +In this case, +Pike looks at the contents of the variable `w`, +finds that it is a `fish`, +and then calls the method `swim` in that object. +Looking at the actual object like this +is called **dynamic binding**. +(The opposite, +to just look at the type of the variable +and ignore what's actually in it, +would be called **static binding**.) + +As we said, +we used inheritance to express **is-a relationships**. +But there are other ways of using inheritance, +for example to simply get access to some functionality. +If you write a program that needs to work with +a file on your hard disk, +we could inherit the file-handling class `Stdio.File`, +and then use all the methods in that class +as if you had written them in your own program: + +```pike +inherit Stdio.File; +// ... +read(); +``` + +This works, +but we recommend that you create an object +of the type `Stdio.File` instead, +and call the methods for that object: + +```pike +Stdio.File the_file; +// ... +the_file->read(); +``` diff --git a/oop/multiple_inheritance.md b/oop/multiple_inheritance.md new file mode 100644 index 0000000..3ca56b5 --- /dev/null +++ b/oop/multiple_inheritance.md @@ -0,0 +1,45 @@ +# Multiple Inheritance + +Sometimes we want to inherit from two or more classes. +This works in Pike (and in C++, but not in Java). +You just write several inherits. + +Lets say we have a class `friend`, +that represents a friend: + +```pike +class friend +{ + void cuddle() + { + write("Cuddle, cuddle, cuddle!\n"); + } +} +``` + +A hamster, +as we all know, +is both an animal and a friend, +and it can also dance: + +```pike +class hamster +{ + inherit animal; + inherit friend; + + void dance() + { + write(name + " dances.\n"); + } +} +``` + +So, try it out: + +```pike +hamster h = hamster("Blue Lightning", 0.12); +h->cuddle(); // Cuddle as a friend +h->eat("grain"); // Eat as an animal +h->dance(); // Dance as a hamster +``` diff --git a/oop/oo_in_pike.md b/oop/oo_in_pike.md new file mode 100644 index 0000000..03a43c6 --- /dev/null +++ b/oop/oo_in_pike.md @@ -0,0 +1,34 @@ +# Object Orientation in Pike + +## Programs Within Programs: Object-Oriented Pike + +As we have said before, +a **class** is a description of a type of thing. +You can **clone** the class to create **objects**. +Each object is a **clone** +(sometimes called **instance**) +of the class. + +A class contains some variables, +which are sometimes called **member variables**. +The variables are attributes or characteristics of the objects, +and each object will have +its own set of the member variables. +For example, +if the class `animal` has the member variables `name` and `weight`, +then each animal will have those two variables, +so each animal can have a name and a weight. + +A class also contains some methods. +(C++ programmers would call them "member functions".) +The methods describe things that the objects can do. + +For example, +if the class "animal" has the method `eat`, +then you can call that method in any animal, +to make it eat. +Well, of course it won't really eat, +since it's just some data in the computer +and not a real animal. +But the method can change the member variables, +for example by increasing the value of `weight` for that animal. diff --git a/oop/programs.md b/oop/programs.md new file mode 100644 index 0000000..ab88aa4 --- /dev/null +++ b/oop/programs.md @@ -0,0 +1,73 @@ +# Programs are Classes and Vice Versa + +It may surprise you to know +that you have already seen several class definitions +in this tutorial. +If you have written a program in Pike, +you have also written a class. +This is because in Pike, +programs and classes are the same, +and the terms **program** and **class** +are sometimes used as synonyms. + +A Pike program in a file is a class definition. +The methods that you have defined in the file +are the methods of the class, +and the global variables +(that is, the variables defined outside the methods) +are the member variables. +If you like, +you can imagine that +the file has an implicit "`class { }`" around the code. +But it would be bothersome +if we had to put every little class in its own file, +so we also have the "`class { }` notation. + +To create the equivalent of the class `animal`, +which we defined above, +we would need a file with the following contents. +The file name can be "animal.pike", +but any name will work. + +```pike +string name; + +float weight; + +void create(string n, float w) +{ + name = n; + weight = w; +} + +void eat(string food) +{ + write(name + " eats some " + food + ".\n"); + weight += 0.5; +} +``` + +We can't use a string as a type name, +so the file name won't work as a data type: + +```pike +"animal.pike" my_dog; // Doesn't work at all. +``` + +Instead, +we must let Pike read and compile the file, +making a **program** of it +(or **class**, if you prefer that term, +but the data type is `program`), +and then we put that program in a **constant**: + +```pike +constant animal = (program)"animal.pike"; +``` + +Now you can use `animal` as the class name, +just as before: + +```pike +animal piglet = animal("Piglet", 6.3); +``` diff --git a/statements/index.md b/statements/index.md new file mode 100644 index 0000000..b3b557f --- /dev/null +++ b/statements/index.md @@ -0,0 +1,213 @@ +# Statements + +# Choosing between Alternatives + +A program must sometimes make choices, +choosing between different instructions to execute. +Sometimes it must also execute +the same instructions several times. +All this is done using various **control structures**. +We will start by looking at +the different ways of choosing between alternatives. + +Pike has three facilities for choosing between alternatives: +the **if** statement, +the **switch** statement, +and the `? :` operator. + +## The `if` statement + +The `if` statement comes in two flavors. +The first and simplest one follows this pattern or template: + +```pike +if ( *expression* ) + *statement* +``` + +As usual in this tutorial, +words in a `fixed-width font` +are supposed to be written verbatim in the program, +while words in *italics* +are supposed to be replaced by something else. +This means that the word `if` and the parentheses should be kept, +but you replace *expression* with some expression, +and *statement* with some statement. +An example, +which could have been part of a control program for a stove, +looks like this: + +```pike +if (temperature < 200.0) + burn(); +``` + +When Pike encounters an `if` statement, +it first calculates the value of the *expression*. +Pike then checks if this value is **true** or **false**. +The value zero (**0**) is considered to be **false**, +and everything else is **true**. +If the value is **true**, +the *statement* is executed. +If the value is **false**, +nothing is done, +and program execution will continue after the `if` statement. + +An `if` statement can also follow this template: + +```pike +if ( *expression* ) + *statement1* +else + *statement2* +``` + +Example: + +```pike +if (this_user == file_owner) + allow_access(); +else + deny_access(); +``` + +A statement can be a block, +which is several statements enclosed by curly brackets. +Example: + +```pike +if (this_user == file_owner) + allow_access(); +else +{ + deny_access(); + send_message(file_owner, "Warning: " + this_user + + " tried to access your file."); +} +``` + +You can "chain" several `if` statements together, like this: + +```pike +if (temperature < 200.0) + burn(10); +else if (temperature < 300.0) + burn(5); +else if (temperature < 400.0) + burn(2); +else + turn_off_heat(); +``` + +## The `switch` statement + +If your program is choosing +between a number of different actions, +depending on the value of a variable or expression, +you can express this using a chain of `if` statements: + +```pike +if (command == "print") + print(argument); +else if (command == "save") + save(argument); +else if (command == "quit" || command == "exit") + quit(argument); +else + write("Unknown command.\n"); +``` + +In such cases a `switch` statement can be a better alternative: + +```pike +switch(command) +{ + case "print": + print(argument); + break; + case "save": + save(argument); + break; + case "quit": + case "exit": + quit(argument); + break; + default: + write("Unknown command.\n"); + break; +} +``` + +In a `switch` statement, +Pike first calculates the value of the expression between the parentheses, +in this case `command`. +It then compares this value with +all the values given in the `case`s in the body +(i e between the curly brackets) +of the `switch` statement. +If it finds a value that is equal, +it jumps to that place +and continues to execute the program there. +If it comes to a `break` statement, +it will skip the rest of the code in the `switch` body, +and continue execution after the block. + +It is not necessary to have a `default:` block, +but if one exists, +Pike will go to that one if it finds no matching `case` value. +The final `break` statement in this example isn't really necessary, +since the switch statement block ends there anyway, +but it won't hurt either. + +You can use a range of values in a case: + +```pike +case 10..14: +``` + +This case will match if the value is between 10 and 14, +inclusively: 10, 11, 12, 13 or 14. + +## The ugly `? :` operator + +The operator `? :` is similar to the `if` statement, +but returns a value. +Expressions that use the operator `? :` follow this template: + +```pike +*condition* ? *then-expression* : *else-expression* +``` + +*Condition*, *then-expression* and *else-expression* +are three expressions. +Pike starts by calculating the value of *condition*. +If that value is **true**, +it then calculates *then-expression*, +and doesn't do anything with *else-expression*. +If the value of *condition* is **false**, +it calculates *else-expression*, +and doesn't do anything with *then-expression*. +The value of the whole construct +is the value of the expression that was calculated: +either *then-expression* or *else-expression*. + +Using this operator, +you can rewrite + +```pike +if (a > b) + max_value = a; +else + max_value = b; +``` + +as + +```pike +max_value = (a > b) ? a : b; +``` + +We recommend that you don't use the `? :` operator, +unless you have to. +It can be necessary when writing function-like macros, +but that is beyond the scope of this tutorial. diff --git a/statements/loops.md b/statements/loops.md new file mode 100644 index 0000000..2dcad47 --- /dev/null +++ b/statements/loops.md @@ -0,0 +1,252 @@ +# Repetition (or "Loops") + +Pike has four different facilities for repetition: +the `while` statement, +the `for` statement, +the `do while` statement, +and the `foreach` statement. + +## The `while` Statement + +The `while` statement does something +as long as a condition is true. +It follows this template: + +```pike +while ( *expression* ) + *statement* +``` + +Pike calculates the value of *expression*. +If the value is **false**, +it leaves the loop. +If the value is **true**, +it executes *statement*, +and then it goes back to the start +and calculates the value of *expression* once again, +to see if we should run another iteration of the loop. + +Example: + +```pike +while (temperature < 200) + heat_some_more(); +``` + +This will keep calling the method `heat_some_more` +until the value of `temperature` is at least **200**. +If `temperature` was at least **200** from the start, +`heat_some_more` is never called. + +As always, +*statement* can be a block, +so we can have several statements that are executed +in each iteration of the loop. +This example will print the first five elements +(element number 0, 1, 2, 3, and 4) +in the array `argv`, +each on its own line: + +```pike +int i = 0; +while (i < 5) +{ + write(argv[i] + "\n"); + i = i + 1; +} +``` + +## The `for` Statement + +The `for` statement does something as long as a condition is **true**, +just like the `while` statement, +but the `for` statement also has a place +to put an expression that is calculated +before the loop is started, +and another place +for an expression that is run immediately after the statement in the loop. +The `for` loop follows this template: + +```pike +for ( *init-expression* ; *condition-expression* ; *change-expression* ) + *statement* +``` + +This is (almost exactly) +equivalent to this **while** loop: + +```pike +*init-expression*; +while ( *condition-expression* ) +{ + *statement* + *change-expression*; +} +``` + +The **while** loop in the example above, +the one that writes the element in an array, +can be re-written as a **for** loop, +like this: + +```pike +int i; +for (i = 0; i < 5; i = i + 1) + write(argv[i] + "\n"); +``` + +As an extra feature, +the definition of the loop variable +can be put inside the `for` loop: + +```pike +for (int i = 0; i < 5; i = i + 1) + write(argv[i] + "\n"); +``` + +In that case, +the variable `i` is local in the `for` loop, +and disappears when we leave the loop. + +## The `do while` Statement + +Sometimes we don't want to do the test in a loop +until after the first iteration +of the statement in the loop. +In those case we can use a **do while** loop. +The **do while** loop statement +follows this template: + +```pike +do + *statement* +while ( *expression* ); +``` + +Pike starts by executing *statement*. +Then it calculates the value of *expression*. +If the value is **false**, +it leaves the loop. +If the value is **true**, +it goes to the start of the loop, +executes *statement* again, +and then calculates the value of *expression* once again, +to see if we should run another iteration of the loop. + +If we want the user to answer "yes" or "no" to a question, +and we want to keep asking until we get either "yes" or "no", +we could write a loop like this: + +```pike +string answer; +write("Have you stopped beating your wife yet?\n"); +do +{ + write("Answer yes or no: "); + answer = Stdio.stdin->gets(); +} while (answer != "yes" && answer != "no"); +``` + +## The `foreach` Statement + +The **foreach** loop statement is very useful. +It goes through all the elements in an array, +doing something with each element. +It follows this template: + +```pike +foreach( *container* , *loop-variable* ) + *statement* +``` + +*Container* should be an expression with an array as value, +and *loop-variable* should be the name of a variable. +Pike will execute *statement* +once for each element in the array *container*, +with that element in the variable *loop-variable*. +This example will print all the strings in the array **argv**, +each on its own line: + +```pike +string s; +foreach (argv, s) + write(s + "\n"); +``` + +The `foreach` statement is similar to the `for` statement, +in that the definition of the loop variable +can be put inside the `foreach` loop: + +```pike +foreach(argv, string s) + write(s + "\n"); +``` + +In that case, +the variable `s` is local in the `foreach` loop, +and disappears when we leave the loop. + +## `break` and `continue` + +Sometimes you want to leave a loop somewhere in the middle, +and continue executing the program +after the end of the loop. +You can use the `break` statement for this, +as in this example: + +```pike +while (1) +{ + string command = Stdio.stdin->gets(); + if (command == "quit") + break; + do_command(command); +} +``` + +`break` can be used in loops and in `switch` statements. +It will cause Pike to "break out" of the loop or `switch` statements, +and execution will continue after the loop or `switch` statement. + +`continue`, +on the other hand, +can only be used in loops. +A `continue` statement will cause Pike +to skip the rest of the body of the loop, +going directly to the next iteration. +For example, +this loop will never call `do_command` +with an empty string as argument: + +```pike +while (1) +{ + string command = Stdio.stdin->gets(); + if (strlen(command) == 0) + continue; + do_command(command); +} +``` + +Some programmers feel that `continue` is unnecessary +and makes the code hard to read. +A loop that uses `continue` +can always be re-written without `continue`. +Our example would look like this: + +```pike +while (1) +{ + string command = Stdio.stdin->gets(); + if (strlen(command) != 0) + do_command(command); +} +``` + +There are at least three more ways of leaving a loop in the middle: + +* You can use the `return` statement to leave the entire method. + +* You can use `throw` to throw an exception. + +* You can call `exit` to terminate the program. diff --git a/statements/others.md b/statements/others.md new file mode 100644 index 0000000..0e06413 --- /dev/null +++ b/statements/others.md @@ -0,0 +1,129 @@ +# Other Statement Types + +## The Empty Statement + +Sometimes you may need a statement that does nothing. +The **empty statement** can be used for this. +It just consists of a single semi-colon. +For example, +sometimes you may want the body of a loop +to do nothing: + +```pike +// Keep checking if it is finished, until it is +while (! finished()) + ; +``` + +## The Block, or Compound Statement + +As we have seen above, +you can enclose several statements in curly brackets, +"{" and "}". +The result is called a **block** or **compound statement**, +and can be used as a single statement. +Here is one example: + +```pike +{ + write("Hello "); + write("world!\n"); +} +``` + +Do not put a semi-colon (";") +after the final bracket ("}"). + +You can define variables inside the block. +Such a variable is local in that block, +and is available only to the program code +written inside the block: + +```pike +{ + write("What is your name?\n"); + string name; + name = Stdio.stdin->gets(); + write("Your name is " + name + ".\n"); +} +``` + +A block can be empty: + +```pike +{ } +``` + +## The Expression Statement + +The **expression statement** follows this template: + +```pike +*expression* ; +``` + +That is, +you just take an expression and put a semi-colon (`;`) +at the end. +Typical expression statements are: + +```pike +write("Hello world!\n"); +i = 7; +++i; +``` + +All of these are expressions with a semi-colon appended. +Since the expression statement doesn't do anything +with the value of the expression, +it is the so-called "side-effects" of the expressions +that we are interested in. +For example, +the expression "`i = 7`" has the value **7**, +but what is interesting is of course +that it has the side-effect +of setting the variable `i` to **7**. + +Since you can take any expression and add a semi-colon, +these strange-looking (and rather useless) +statements are also allowed: + +```pike +2 + 2; +3; +``` + +## Other Statements: `return` and `catch` + +The `return` statement is used to leave a method, +and sometimes also to return a value from that method: + +```pike +return; +return x + 3; +``` + +You can read more about the `return` statement +in the chapter about methods. + +The `catch` statement is used +to try to execute some Pike code, +letting the programmer control what happens +if there is an error: + +```pike + mixed result = catch + { + i = klooble() + 2; + fnooble(); + j = 1/i; + }; + + if (result == 0) + write("Everything was ok.\n"); + else + write("Oops. There was an error.\n"); +``` + +You can read more about the `catch` statement +in the chapter about error handling.