2.2 Decorators

Overview

Contexts are primarily structures of data, but those data need to be checked for whether they qualify for operations/behaviors, and new contexts should be able to be produced, at least in part, from existing contexts. Decorators offer an optional way to meet both of these needs for any given context. Contextual Programming defines the following two types of decorators, although a language may .

Records can have decorators just as contexts do. This maintains the same purpose as decorators on contexts when records are nested within contexts or to produce new contexts/records based on existing records.

Qualifiers

Qualifiers offer a way to query whether a context qualifies for an operation/behavior, in language appropriate for the purpose of the context. The result of a qualifier will always be a . If the result is 'true', it can be said that the context 'qualifies'. How qualifiers are used is shown when operations are covered in more detail.

In general, a qualifier can be declared, within a context, following :

this "text with optional 'type name' for parameters": 
    'parameter names, as needed' => "logic that evaluates to a boolean"

A Parameterless Example

A simple, parameterless, example building upon a context declared earlier:

Some Int :: Int : context;
    this is even : => .

An Example with Parameters

An example with parameters, again building upon a context declared earlier:

Position :: a 2D location represented by Int and Int : context x, y;
    this matches Int and Int : x, y => this(x) = x && this(y) = y.

Throughout Rede, almost anything wrapped in parentheses is considered a "detail of", meaning something specific to the preceding declaration or value, the primary exception being when the order of operations is being clarified through parentheses.

In this example, "this(x)" is specifying the retrieval of the property 'x', which is a detail of the Position context.

Operators

A common operator that most people are familiar with is '+', the addition operator. As with many programming operators, it has its roots in mathematics, and like its use in mathematics, it takes two (being in math) and produces a new instance. Operators in Rede work much the same way.

A Parameterless Example

There are operators that do not take another instance. A prime example being . Looking again at the Position context from earlier, there's an opportunity to add a negation operator. The below example adds an operator to do so:

Position :: a 2D location represented by Int and Int : context x, y;
    this matches Int and Int : x, y => this(x) = x && this(y) = y;
    -this : => Position 
        [ 
            x[-this(x)], 
            y[-this(y)]
        ].

In the above example, the "stand-in" notation is being used to specify the values of a new Position's x and y. That new Position instance is the result of the operator. It has the negated value of the original instance's x for its own x and the negated value of the original instance's y for its own y.

With this operator declared, negating a Position with code such as -some position will provide an expected and appropriate result.

An Example with Parameters

The Position example can be extended again with an operator that takes a parameter, like so:

Position :: a 2D location represented by Int and Int : context x, y;
    this matches Int and Int : x, y => this(x) = x && this(y) = y;
    -this : => Position [ x[-this(x)], y[-this(y)] ];
    this + Position : other => Position 
        [ 
            x[this(x) + other(x)], 
            y[this(y) + other(y)] 
        ].

Now a Position can be added to another Position through code such as some position + another position, with the result being the actual addition of those two Positions.

Last updated