1 Getting Started

The purpose of programming languages is of course the construction of applications. In this chapter we will use Oz for our first small application.

1.1 Our First Application: Webget.oza

Our first application is a program that copies a file from a url to a local file. The program is called Webget.oza.


ozengine Webget.oza --in http://www.mozart-oz.org/LICENSE --out LICENSE

Figure 1.1: Get yourself a Mozart license.


Our goal is to have an application that can be started like any other application from the operating system shell. For example, executing the command shown in Figure 1.1 gets us a local copy of the Mozart license file.

In addition to taking arguments from the command line, Webget.oza should report problems by returning an error status to the operating system shell. The error status is an integer, where the value 0 means okay. Any other values signals an error.

1.2 What to do?

In the following we consider the three main steps in constructing our application. We give a brief outline of what to do, the following sections are going to detail the steps.

Definition

The first step, of course, is to program our application. For this purpose, we will create a file Webget.oz that contains the Oz program implementing webget. More specifically, the file Webget.oz contains a functor definition.

Compilation

Next, we compile the functor definition contained in Webget.oz. The compiler takes the functor definition and executes it. By this it creates a functor. Then the functor is written to a file Webget.oza. This persistent representation of a functor value is called a pickled functor.

Execution

The pickled functor Webget.oza is executed by the Oz virtual machine ozengine. The engine takes a pickled functor (Webget.oza in our case), unpickles the functor, runs the functor, and supplies it with application arguments. After execution terminates, it reports the application's execution status back to the operating system shell.

1.3 Functor Definition: Webget.oza

The toplevel structure of the file Webget.oz is as follows.

<Webget.oz>=
functor 
   
<Module import> 
   
<Functor body> 
end

Importing modules

Our application requires the system module Application to both process the command line arguments as well as for terminating the application. In addition, the module Open provides the class Open.file required for reading and writing files.

The functor needs to import these two modules. The functor definition thus contains the following import specification:

<Module import>=
import  
   Application  
   Open

The import specification serves two purposes: the variable identifiers Application and Open are introduced with a lexical scope that extends over the entire body of the functor. Secondly, the identifiers also serve as module names. When the functor corresponding to this definition is executed, the variables are given as values the system modules with the same names.

More precisely, the import specification above is a convenient abbreviation for the more verbose specification below:

<Module import (no convenience)>=
import  
   Application at 'x-oz://system/Application' 
   Open        at 'x-oz://system/Open'

In Section 3.3 we will discuss system modules in more detail. In particular, Table 3.1 lists available system modules.

Functor body

The body of a functor is a statement that is executed when the application is run.

<Functor body>=
define 
   
<Argument processing> 
   Status = try 
               
<Opening input and output files> 
            in 
               
<Copying input file to output file> 
               0
            catch _ then 1
            end 
   
<Terminating the application>

The structure for our application is straightforward: after processing the command line arguments, file objects for source and destination are created and the content is copied from the source file to the destination file.

If a runtime error occurs either during opening the files or while copying the file content, the raised exception is caught and the Status is bound to 1. Otherwise, Status gets bound to zero.

Note that the body of a functor is like the part of a local ... in ... end statement before the in: definitions and statements are allowed, where the left hand side of definitions can introduce variables.

Processing arguments

The application needs two input parameters: the URL to get the file from, and the file name under which the downloaded content should be stored.

The following application of Application.getCmdArgs

<Argument processing>=
Args = {Application.getArgs record('in'(single type:string)
                                   'out'(single type:string))}

computes Args to be a record (as signalled by the label record of the single argument to Application.getArgs. The features of the record are 'in' and 'out' where both fields are of type string and both are allowed to be given only once on the command line (that is specified by single).

For a complete reference of how application arguments are processed see Chapter 1 of ``System Modules''.

Opening input & output

The two files are opened as follows:

<Opening input and output files>=
I={New Open.file init(url:  Args.'in')}
O={New Open.file init(name: Args.'out'  
                      flags:[write create truncate])}

Note how the strings Args.'in' and Args.'out' computed by argument processing are used for the source URL and the destination filename.

Copying input to output

Copying the file from source to destination is straightforward: As long as we can read a non-empty string S from the source file, we write it to the destination file and repeat the procedure.

<Copying input file to output file>=
local 
   proc {Copy}
      S={I read(list:$)}
   in 
      if S\="" then  
         {O write(vs:S)} {Copy}  
      end 
   end 
in  
   {Copy}
end

Terminating the application

Termination of the application is effected by invocation of Application.exit which takes the application status as single integer argument. In our case an exit value of 1 indicates an error, otherwise 0 is returned to the operating system shell.

<Terminating the application>=
{Application.exit Status}

1.4 Compilation

As is the case for many programming languages, the functor definition must be compiled before it can be executed. This is achieved by invoking the Oz compiler ozc as follows:

ozc -c Webget.oz -o Webget.oza

Note the intentional similarity between the options illustrated above and those accepted by a C compiler. The compiler ozc offers a variety of other options that control compilation, an overview of which can be found in Chapter 2 of ``Oz Shell Utilities''.

1.5 Execution

The functor pickled into Webget.oza can be executed by applying the program ozengine to the functor and the application arguments. For example, to copy the Mozart license file at url http://www.mozart-oz.org/LICENSE to the local file LICENSE, simply enter the command line shown in Figure 1.1 at your shell promt.

Execution of an application proceeds as follows:

  1. ozengine, the Oz virtual machine, is started by the operating system.

  2. ozengine starts to execute a module manager.

  3. The module manager loads the pickled functor Webget.oza. This initial application functor is called the root functor.

  4. The module manager links the functor by applying the functor body to argument modules. The argument modules in our example are the system modules Application and Open.

  5. Then it executes the functor body.

The different steps in application are detailed in the following sections.


Denys Duchier, Leif Kornstaedt and Christian Schulte
Version 1.4.0 (20080702)