The Avail Programming Language
Mobile Users: Click here to view our text rendering warning.

Introduction

An Avail program — be it a system, library, or application — comprises a collection of modules. A module is a container for Avail code. These statements are loose enough to be true, in different ways, at both compile time and run time.

At compile time, the compiler operates on an Avail program as a collection of source modules[1]. A source module is a human-readable document that describes, sincerely, a variety of types, values, and operations. It is generally a creative work produced by a programmer, though it might be the output of a code generator. A valid source module is a plain text document that contains Unicode code points in the UTF-8 character encoding. A source module that resides within a file system must have a .avail file extension.

At run time, the executor operates on an Avail program only as a collection of binary modules. A binary module is the output of the Avail compiler, and is not intended to be human-readable. Its purpose is to improve the performance of executing Avail code. The separation of Avail code into source and binary forms also permits developers to distribute their software without having to also distribute their source code. This flexibility is essential to many software business models.

Throughout this series, when the term "module" is used without a qualifier, like "source" or "binary", then it will refer exclusively to a source module. If the discussion regards a binary module, then the term "binary module" will be used explicitly. This simplification of nomenclature is made because the primary purpose of this series is to explain the features of modules from the perspective of an Avail programmer, who deals primarily with source modules.

Whether in source or binary form, a module has three primary responsibilities:

  • To declare its dependencies, so that a human or machine reader can understand its relationship to upstream modules.
  • To define services, in the form of methods, that may be consumed by downstream modules.
  • To define services, in the form of entry points, that may be consumed by end users and external programs.
Module dependencies: upstream vs. downstream Module dependencies. Red is upstream of M, blue is downstream. Arrows point against the flow (because they represent imports). A A B B C C D D D->A D->B E E E->C M M M->D M->E U U U->M V V V->M X X X->M Y Y Y->M Z Z Z->U Z->Y

A module A is upstream of a module B if A must be compiled before B can be compiled. A module C is downstream of a module D if C cannot be compiled until D has been compiled. So upstream and downstream are reciprocal relationships based on the notion of module dependency: a module depends upon another (upstream) module, directly or indirectly, if it consumes services made available by that module.

A module is divided into two main units:

  • The module header, which declares the services that the module consumes and the services that it provides for consumption.
  • The module body, which defines the services that it provides for consumption.

We will begin by examining the module header.


[1] Actually, the compiler operates also on binary modules produced by previous compilations. This dramatically improves the performance of the build process, but has no impact on the semantics of compilation. Using a hybrid source-binary module compilation approach is isomorphic to using a source-only approach, so we will discuss the process in terms of the latter only, for simplicity.

Return to Modules | Module Headers ›