# 4.3 Working with Buckets

## Collection-Dependent Behaviors

Some behaviors will need to operate for every instance of a type of context. The [logging behavior](/a-general-introduction-to-contextual-programming/chapter-4-reacting-with-behaviors/4.2-from-when-to-whenever.md#logging) created in the last chapter is an example of such a behavior. Up to this point, its declaration looks like:

```
Perform Logging :: handles logging per a Log Settings for a Log Message : 
    behavior {settings, message}
    when message(level) >= settings(minimum level)?
    
    Log :: for {message} when initialized?
        evaluate "Log: \(message)" as Console Message,
        deactivate message.
```

As it is currently implemented, there will be an instance of this behavior for every `Log Message` (assuming there is only one `Log Settings` in the application). That instance will be destroyed after its initialization operation executes. There isn't anything wrong with this implementation, but it does require a bit more work by the application to continually cycle through new instances of the behavior. It also requires the `Log Settings` to be maintained by another behavior so it would persist across the destruction of this behavior's instances.

These requirements can be removed by making `Perform Logging` dependent on the application's collection of `Log Message` instances rather than a single instance. Doing so can be done by updating the behavior, as:

```
Perform Logging :: handles logging per a Log Settings for {*Log Message*} : 
    behavior {settings, messages}?
    
    Evaluate Messages :: for {settings, messages}
        whenever |messages| > 0,
        foreach message in messages?
            evaluate message for settings,
            deactivate message;
    
    Log :: log a Log Message to the console : <message> for {settings}
        when message(level) >= settings(minimum level)?
            evaluate "Log: \(message)" as Console Message.
```

The first change to point out is `{*Log Message*}` replacing `Log Message` in the behavior description. This change is what makes the behavior collection dependent. Surrounding a context type with curly braces and stars in Rede, generally as `{* "Context Type" *}`, defines what is called a "bucket" of those contexts. A bucket is an ordered[^1] collection of unique[^2] contexts. Contexts can be accessed sequentially (as shown above by `foreach message in messages`), by index (e.g., `messages(0)`), or by [context ID](/a-general-introduction-to-contextual-programming/chapter-6-abstracting-contexts/6.2-context-identifiers.md). When used in a behavior declaration, by default, all instances of the specified context will be provided to the behavior's bucket. However, that can be customized, as discussed [below](#managing-the-collection-s).

By making the behavior dependent on a collection, an instance of `Log Settings` on its own will be enough to qualify an instance of the behavior, albeit with an empty `Log Message` bucket, which is fine for this behavior. Whenever the number of messages in the `Log Message` bucket is more than `0`, as specified by `whenever` [`|messages|`](#user-content-fn-3)[^3] `> 0`, the `Evaluate Messages` operation will reactively evaluate, being executed for every `message` that is now in the bucket.

Within this operation, there is a composition-based evaluation. `evaluate message for settings` initiates the evaluation of any operations that depend upon a `Log Message` and a composition that consists only of the `Log Settings`. This evaluation could extend beyond this behavior, to any other behavior that is working with the same `Log Settings` instance and has an operation for a single `Log Message`. It would not evaluate any operations that require any `Log Message` and any `Log Settings`, as that is not what is being specified by this evaluation.

The one operation that currently depends on a `Log Message` for that specific `Log Settings` instance is the `Perform Logging` behavior's `Log` operation, as also shown above. It will qualify if the message's log level meets the setting's minimum log level and will then evaluate the message as a `Console Message` with `Log:` prepended, just as logging was accomplished before these changes. Once that is done, `Evaluate Messages` will deactivate the message, regardless of whether it was logged.

These changes accomplish the same functionality as before, but there no longer needs to be a behavior to maintain the `Log Settings` between `Log Message` instances. The single `Perform Logging` behavior instance created for the `Log Settings` will persist until `Log Settings` is deactivated, which also grants an improvement to performance.

## Managing the Collection(s)

The above changes are an improvement, but they can go a step further to make the behavior as a whole more focused and explicit in its purpose. This can be accomplished by altering what qualifies for the `Log Message` bucket.

There are a couple of ways to customize the contexts of a behavior's bucket(s) as a new [qualification value](/a-general-introduction-to-contextual-programming/chapter-3-evaluating-with-operations/3.2-expanding-on-when.md#qualification-values) (a new bucket in this case). The second of which will be applied to the `Perform Logging` behavior.

{% hint style="warning" %}
Operations can use buckets the same as any other input context, and just like behaviors, they can customize the contexts of those buckets into new qualification buckets before using them.
{% endhint %}

### Sorting

A behavior can ensure a bucket is sorted per a mapping. Mappings are a restricted way to make an immediate change to a value, often converting the value into a new instance of a different type in the process. In the case of sorting, the mapping will evaluate two inputs to either a [`Tril`](#user-content-fn-4)[^4] or an `Int`, which will be used to specify whether the first value should be sorted higher than the second value; `False` or a negative number meaning the first is less-than the second, `Unknown` or `0` meaning that they are equal (there is no measured distinction between the two), and `True` or a positive number meaning that the first is greater-than the second.

While not useful for the purpose of this logging implementation, `Perform Logging` could be updated to show sorting:

```
Perform Logging :: handles logging per a Log Settings for {*Log Message*} : 
    behavior {settings, messages}
    where messages is messages sorted by
        [(first, second) => first(level) - second(level)]?
    
    Evaluate Messages :: for {settings, messages}
        whenever |messages| > 0,
        foreach message in messages?
            evaluate message for settings,
            deactivate message;
    
    Log :: log a Log Message to the console : <message> for {settings}
        when message(level) >= settings(minimum level)?
            evaluate "Log: \(message)" as Console Message.
```

The above adds a qualification to the behavior, `where messages is messages sorted by [(first, second) => first(level) - second(level)]`. This will ensure messages are sorted by their log levels, in order of the lowest log level to the highest. The keywords to define the sort are `sorted by`, which will apply the subsequent mapping `[(first, second) => first(level) - second(level)]` to the bucket, `messages`. The mapping is subtracting the log levels of the two inputs, which can be done since a `Log Level` is [an enum](/a-general-introduction-to-contextual-programming/chapter-4-reacting-with-behaviors/4.2-from-when-to-whenever.md#conditional-behavior) of an `Int`. The result will be an `Int` indicating whether the first should be sorted higher or lower than the second. The result of the sort is assigned to a new qualification bucket that is also called `messages`, since all mappings and their uses in Rede are performed without [side effects](#user-content-fn-5)[^5].

{% hint style="info" %}
Mappings can be declared, similar to a context, or used in-line, as done here (wrapped in square brackets), and they can play a very important role in structuring the code and specifying the direct manipulation of data. However, they are not a core concept to Contextual Programming, so they are not covered in further detail.
{% endhint %}

This sorting functionality will occur prior to whenever the behavior will perform a reactive operation, if the messages bucket either has new contexts or has had contexts change their state, thus ensuring that the messages bucket is only sorted right before it is used.

### Filtering

Filtering contexts is the second way behaviors can control the contents of their buckets, and it's the method that will be relevant to further improving the `Perform Logging` implementation. Filtering is accomplished in a fashion similar to sorting, where a mapping (the filter logic) is specified after the keywords `filtered by`, except this mapping takes only one input and outputs a `Bool` to indicate whether the input passes the filter. Using a filter, `Perform Logging` can move the qualification of the `Log` operation to the behavior's bucket, thus simplifying the overall implementation by condensing its operations:

```
Perform Logging :: handles logging per a Log Settings for {*Log Message*} : 
    behavior {settings, messages}
    where messages is messages filtered by
        [(message) => message(level) >= settings(minimum level)]?
    
    Log Messages :: for {messages}
        whenever |messages| > 0,
        foreach message in messages?
            evaluate "Log: \(message)" as Console Message,
            deactivate message.
```

{% hint style="info" %}
This makes a couple of assumptions about what will use the `Log Message` context and when it should be deactivated. These assumptions will be discussed and corrected with the help of an abstraction concept covered [later](/a-general-introduction-to-contextual-programming/chapter-6-abstracting-contexts/6.1-contracts.md).
{% endhint %}

Now a `Log Message` will only qualify for `Perform Logging`, as an element of a new `messages` qualification bucket, if its log level is higher than the minimum log level specified in the settings. Any time there is at least one such message `Perform Logging` will loop through all the messages, log them as a `Console Message` and deactivate them. [Recall](/a-general-introduction-to-contextual-programming/chapter-3-evaluating-with-operations/3.2-expanding-on-when.md#qualification-values) that the qualification value `messages` is replacing the original `messages`, so the `Perform Logging` behavior will only form a relationship with the remaining contexts of the new bucket. It isn't concerned with any `Log Message` that doesn't qualify, and such a context will automatically be deactivated if it doesn't qualify for some other behavior. If a `Log Message` were to be persisted by another behavior and should then later qualify for `Perform Logging` by changing its `level`, then that `Log Message` would be added to `messages`.

[^1]: Meaning that they maintain their arrangement, originally by the first added to the last added, but they can be re-arranged manually or by sorting.

[^2]: Meaning that the same context instance will not exist in a bucket more than once. If it already exists, any attempt to assign or add the instance will be ignored.

[^3]: The `|` symbol surrounding any collection means 'size of', the same as it does in mathematics. It will provide the number of elements in that collection.

[^4]: Tril is short for "Trilean", which is similar to a Boolean, but with three values. Where a Boolean only has `True` and `False`, a Trilean has `True`, `False`,  and `Unknown`.

[^5]: A side effect is when functionality is performed upon some input and the result is a change to the input or to something entirely unrelated to the input, as opposed to producing new data that captures the changes. Operations work entirely through (clearly defined) side effects, by changing their contexts, but mappings work without side effects.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://rede.gitbook.io/a-general-introduction-to-contextual-programming/chapter-4-reacting-with-behaviors/4.3-working-with-buckets.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
