conventions(7) conventions(7)

NAME

conventions - cfl conventions

SYNOPSIS

CFL files and conventions for naming, object lifetimes and manual pages.

FILES

The file config.hpp contains some hardware dependent settings, such as whether the program is intended run distributed (on more than one process) or accelerated (using GPU:s). cfl.hpp is a master header including all available files.

MANUAL PAGES

First, the CFL manual pages normally use a function template to describe what really is an instantiation of a class overloading operator (), or a function object.

struct F
{
    template <typename U>
    auto operator () (U && u)
    {
        return u;
    }
} f;

assert (f (1) == 2);

Is written as

template <typename U> auto f (U && u);
f (1) == 2;

Function templates are not suitable for a library such as CFL where functions appear as stand-alone values. Below is a list of further simplified notations used in the documentation. Although not always valid C++, they should make the manual pages less verbose and easier to read.

OBJECT LIFETIMES

Throughout CFL, function arguments are always passed by reference. If the callee must store argument values to use after the full expression has ended, storage is selected from the argument lifetime and ownership encoded in the regular const and reference specification (using the terminology from c++ specification [basic.lval]):

const && arg   ==> store arg as copy-constructed value
      && arg   ==> store arg as move-constructed value
const &  arg   ==> store arg by const lvalue reference
      &  arg   ==> store arg by lvalue reference

This is called standard CFL storage and normally applies to all containers in CFL, such as tuples, asynchronous functions and closures. Functions evaluating to a return value immediately just use references to arguments.

The rationale for this choice of storage, is the fact that with no manual memory management in the user code (i.e. using Scope Based Resource Management), an lvalue will outlive any later expression in scope.

Argument lifetime may be manipulated through functions move and copy, which basically are utility functions for casting to non-const and const rvalue references respectively.

The storage for a function may be changed using glfn. Then values are stored by reference only, lvalues as lvalue references and rvalues as rvalue references. The name glfn refers to glvalue function - a function using generalized lvalues for storage. Note, glfn operates on the function itself, not its arguments.

glfn (bind (1__, 0)) ([] (int arg) { return arg; })

The above example would store the argument 0 by rvalue reference in the closure, instead of move-constructing a value. This a manual optimization, done when the caller can guarantee argument lifetimes.

Analogously, the storage for a function may be changed to only use prvalues using prfn.

At the other end, return values are passed back to the caller using the same conventions: lvalues as lvalue references and rvalues as values. To avoid unnecessary copy- or move-construction, return values should preferably be assigned to auto && declared variables.

auto && r = f ();

Here, neither glvalues nor prvalues returned from f are copy- or move-constructed into r, but instead bound by reference immediately. As usual, the lifetime of a returned prvalue is prolonged until the end of scope.
However, it is the users responsibility to guarantee the lifetime of inner references in return values. Normally, such inner references would be a consequence of previous lifetime manipulation by the user - the default argument and return value lifetime convention should be safe.

An exception to this is when asynchronous values from an outer scope are assigned references bound to values in the inner scope. Then the caller must manually copy-construct such left-hand-side inner scope references.

In short, using the default c++ scope based resource management and assigning function return value using auto &&, object lifetimes are guaranteed without unnecessary copy- or move-construction, also for asynchronous function.

NAMING CONVENTIONS

FUNCTIONS

Functions have plain names without prefix or suffix.

int plus (int u, int b) { return u + v; }

Function classes are classes which overload operator (). They are suffixed with _f. Instantiations thereof (function objects) are named as functions and uses no prefix or suffix.

struct plus_f
{
    template <typename U, typename V>
    auto operator () (U && u, V && v)
    {
        return u + v;
    }
} plus;

FACTORIES

Factories are possibly templated classes with at least a member type type, and is normally suffixed with an underscore _. A factory may have an optional static member function value returning type, where parameters by convention have the same type as the class template argument list. For distinction, the former is called a type factory and the latter a type-value factory.

template <typename U, typename V> 
struct plus_
{ 
    typedef int type;

    static type value (U && u, V && v)
    {
        return u + v;
    }
}

The added rvalue reference declarators for U and V are part of the object lifetime scheme, which is treated in [OBJECT LIFETIMES][].

As type-factories can not have a function variant, the underscore suffix is sometimes omitted to please the eye. Similar to std, CFL uses the _t suffix to denote factory members type type (although this violates the POSIX reservation of the _t suffix).

A factory may also have a template class as result. Then the member holding the result is called factory instead of type. As usual in templated C++ code, when accessing a class member the user has to explicitly specify if it is of typename or template type. So not using type as name does not break any generality in the factory conventions.

Some functions taking another function as argument come with a variant prefixed with f, then replacing the function argument with a factory as template argument. This is mostly relevant for the CFL implementation, but an end user example is enable_if and fenable_if, where the first has a function as predicate argument and the latter a factory template.

CONTAINERS

Containers are classes holding other values. They are parametrized by the types they are holding and are suffixed with _c. An example is tuple_c, a fixed-size collection of heterogeneous values.

template <typename... U> struct tuple_c;

TEMPLATE AND FUNCTION PARAMETERS

MEMBERS