📖
A General Introduction to Contextual Programming
  • A General Introduction to Contextual Programming
  • Chapter 1 - Thinking Contextually
    • 1.1 What is a Paradigm?
    • 1.2 What is Contextual Programming?
  • Chapter 2 - Creating Context
    • 2.1 Organizing Data
    • 2.2 Decorators
    • 2.3 Adaptation
  • Chapter 3 - Evaluating with Operations
    • 3.1 Hello World!
    • 3.2 Expanding on 'When'
    • 3.3 Operation Hierarchies
  • Chapter 4 - Reacting with Behaviors
    • 4.1 Revisiting Hello World!
    • 4.2 From 'When' to 'Whenever'
    • 4.3 Working with Buckets
    • 4.4 Expanding Purpose
    • 4.5 Adapting Behaviors
  • Chapter 5 - Abstracting Evaluations
    • 5.1 Compositions
    • 5.2 Operables
  • Chapter 6 - Abstracting Contexts
    • 6.1 Contracts
    • 6.2 Context Identifiers
  • Chapter 7 - Looking to What's Next
    • 7.1 Final Thoughts
    • 7.2 Additional Resources
Powered by GitBook
On this page
  1. Chapter 6 - Abstracting Contexts

6.2 Context Identifiers

Previous6.1 ContractsNext7.1 Final Thoughts

Last updated 6 months ago

As described , a context can't maintain values of other contexts. However, it may be necessary for a context to be able to refer to another context. This can be done through an identifier that is unique to each instance of a context, called a context identifier.

The ability to identify a specific context, consistently and uniquely, particularly to retrieve from (or to verify a context within) a bucket is important enough of a concept to make it apply to all contexts. This identifier is different than any normal context value though, for the following reasons:

  • In Rede, it is accessed through special syntax, using the @ symbol preceding the context instance, such as @some context. Technically, this @ is not an accessor but instead a specialized conversion from a context instance to its identifier.

  • It can be used alongside a context's creation to attempt to create a context identified by that context identifier.

  • It only exists for an instance after it has been accessed or when explicitly associated with the context. This prevents identifiers from taking up memory for contexts that won't use it.

  • It cannot be changed for a context after the context's creation.

For a simple practical example, consider the small part of a video game implementation from . The behavior in that example was:

Protect Character :: enables a character identified by a shared Character Id to 
    reduce incoming damage as specified by Armor : behavior {id, armor}
    when armor(wearer id) = id?
    
    Reduce Damage :: reduce Attack damage : <attack> for {armor} before all?
        `Alter the potential attack damage based on the armor`.

The qualification for the behavior is comparing some kind of ID in Armor with an associated Character Id. This might not truly be unique, and the Character Id could have its value be changed, which may lead to many unintended side effects, considering how it is being used. This code can be updated to instead use the context identifier of Character Id:

Protect Character :: enables a character identified by a shared Character Id to 
    reduce incoming damage as specified by Armor : behavior {id, armor}
    when armor(wearer id) = @id?
    
    Reduce Damage :: reduce Attack damage: <attack> for {armor} before all?
        `Alter the potential attack damage based on the armor`.

It's assumed that Armor would have also updated wearer id to be of type Id (Rede's built-in type of a context identifier) for the comparison to work. The Character Id context could now just be a flag context, representing a context identifier that uniquely identifies a character for any other contexts it is associated with.

  • All log routes are associated with the App State (currently, Console Log Route is associated through the Maintain Console Log Route behavior).

  • Some context is maintaining all of the log routes as Id values, so the following behavior's operation can be initiated with one of the Id values specifying the Log Route Id of the provided context.

With those assumptions, the example behavior and its relevant contexts can be:

Disable Log Route :: specifies the Id of a log route to be disabled : context
    log route id.

Enable Log Route :: specifies the Id and Type of a log route to be enabled : context
    log route id,
    log route type.

Manage Log Routes ::
    enables and disables the log routes associated with the App State: {app}?
    
    :: 
         is details(log route type),
        where id is details(log route id),
         is $type$  id?
            activate log route;
    
    :: Disable Log Route : <details> for {app}
        where log routes is app <# Log Route,
        where log route is log routes(details(log route id))?
            deactivate log route.

Type, as seen above in Manage Log Routes, is a built-in type of record that Rede provides to specify a type of a construct (record, context, etc.). It can also be used to create instances of a type without specifically knowing which type. Although that instance can't really be used for anything in the immediate operation. The syntax to use a Type (or a String) as a literal type for instance creation is to surround the Type with $.

There is much more that can be done with Type, but it isn't specific to Contextual Programming, so it isn't covered in detail here.

In the operation above for Enable Log Route, in Manage Log Routes, there are a couple of convenience qualification values to improve readability and then where log route is $type$ with id. This line creates a new () log route of the specified type with the given context identifier. If a context is already activated for that identifier, then this qualification value will fail to be created and the operation won't be performed. The operation itself activates the new context, which effectively initializes the log route to begin outputting log messages.

If the minimum level of a re-enabled route should be restored to the new context, assuming it was provided through Enable Log Route, and stored in a qualification value called log level, then it could be applied by changing the log route creation qualification to where log route is $type$ [minimum level [log level]] with id. This will attempt to set minimum level on the created instance, although if such a property is not available, the attempt will be ignored with the new instance still being successfully created.

The operation for Disable Log Route does the inverse. It defines log route as the context identified by log route id, from the composition of Log Route contexts that are associated with the App State, as it has been stated that they all will be through some other behavior. If such a log route is found, then the operation will be performed, which is to say that the log route will be deactivated, thus preventing it from outputting any additional log messages.

For a more thorough example, using the , consider how a specific log route could be disabled or re-enabled. There will be a few assumed changes to the existing implementation to make this example work:

earlier logging feature
earlier
earlier