📖
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
  • The Concept of Behavior
  • Activation
  • Introducing Console Output
  • Activating Console Output
  • Deactivating
  1. Chapter 4 - Reacting with Behaviors

4.1 Revisiting Hello World!

Previous3.3 Operation HierarchiesNext4.2 From 'When' to 'Whenever'

Last updated 6 months ago

The Concept of Behavior

Behaviors are constructs that provide additional meaning to their required, and qualifying, contexts, with encapsulated operations that can to changes in those contexts. The contexts associated with a behavior form a relationship that can be leveraged by the behavior and other behaviors/operations, . This reactivity and the conditional associations between contexts and their shared operations is at the heart of Contextual Programming, enabling programmers to more effectively develop dynamic applications.

Activation

Before going over the internals of a behavior, it's best to understand how a behavior exists and what to expect of it. Behaviors require contexts that have been "activated". So far, there have been no such contexts explicitly activated. Doing so can be done with this generalized syntax, within an operation, :

activate "some context"

All contexts can be activated. Once this is done, a behavior that requires a context of the same type as the activated context can evaluate it to see whether it qualifies to be associated with the behavior and its other contexts, that is, if all of its required contexts exist and qualify. In some cases, multiple instances of behaviors can exist.

An instance of a behavior may be similar to an instance of an object in Object-Oriented Programming, although there are some differences. A behavior will be instanced, meaning it will exist with specific associations and will perform its functionality, if its context requirements are met. Once a behavior has its requirements met, any additional contexts (that cannot be associated with that behavior based on ) will be considered for additional behavior instances.

When a behavior can no longer continue to exist as an instance, namely because one of its contexts were . Then the remaining contexts are (usually, again depending on how its defined) considered for new behavior instances with other contexts that are currently in-use with other behaviors. This highlights one of the primary differences in instances, compared to Object-Oriented Programming, that being the internal data of a behavior instance may persist and be associated with a new behavior instance automatically.

Although, if a context enters a state in which it will no longer qualify for any behavior that either already exists or that can be immediately created, then it will be deactivated automatically and removed from memory once it is no longer in use by any evaluating operations.

Introducing Console Output

One of the most basic behaviors is one that was, unknowingly, being used back in the . That code was:

Output Hello World :: 
    operation when initialized?
        evaluate "Hello World!" as Console Message.

There's no apparent activation occurring here, but the operation that handles Console Message will actually activate the Console Message and a Console Output context. Afterwards, a behavior that works with a Console Output context and any activated Console Message contexts will append each value of those Console Messages to a Messages property of Console Output. The Console Messages are deactivated at a later time through another behavior to prevent unnecessary memory use. As part of the console's refresh cycle, any content in Messages of Console Output will be printed onto the console.

One may be wondering, "How can I know in what ways a context, such as Console Message is being used?" In the modern era, s play a vital role in software development. While the programmer looking at this evaluating code may not know all of the associations of Console Message and its conditional operations/behaviors, the IDE can, since it is always knowledgeable of how the Console Message is referenced and manipulated across those operations/behaviors. The short answer here is, a proper IDE should inform the programmer of everything they need to know for the contexts that the programmer is working with.

As described, that's quite a bit happening behind the scenes. The purpose of reducing all of that down to evaluate some string as Console Message is to simplify the steps taken to output to the console, and to prevent the need to make Console Output a required context for any number of behaviors/operations. However, there may be times when it is appropriate to declare and activate Console Output directly, and to have it as a .

In addition to other useful properties, Console Output has the aforementioned Messages property. The value of this property is exactly that which appears in the console to the user, including the user's , although word wrap to fit within the bounds of the console may change how it appears. Every message is assumed to be its own print statement, with an assumed at the end. Having direct access to this property is useful, as the contents of the console can be cleared by changing that property to be an empty list, or otherwise altered.

Activating Console Output

The Hello World! example can be updated, based on the generalized syntax to activate a context, to explicitly declare Console Output, like so:

Output Hello World :: 
    operation when initialized?
        activate output is Console Output,
        output(messages) is "Hello World!".

On the third line, activate output is Console Output is performing an inline declaration of a Console Output called output, then activating it. This provides output for further use while also activating it so the console printing behavior mentioned previously can be initialized and begin working.

This example can be shortened further by setting messages at the point of output being declared:

Output Hello World :: 
    operation when initialized?
        activate Console Output [messages ["Hello World!]].

This code is similar, but output is no longer named in the declaration, as it isn't needed beyond its activation, and the Console Output instance is initialized with messages set to "Hello World!", as is accomplished with the code Console Output [messages ["Hello World!"]].

Per how the console printing behavior is set up, only one Console Output can sensibly be activated at a time to effect printing to the console, as that behavior will be the one to capture all Console Messages. This type of behavior parallels the concept of a 'singleton' in Object-Oriented Programming, where there is only one instance of some kind of system required to do something.

That's not to say that there can't be more than one activated Console Output though, and it's entirely possible that some other behavior that does not print to the console may do something with all of them. That's a difference between a self-enforced singleton as a behavior and a dependency determined singleton of an object; the data that defines the behavior can serve other purposes (through other behaviors) that may still effectively extend the functionality of the behavior.

Deactivating

The opposite of activating is deactivating, which informs the runtime that the previously activated context (if it was activated, if not, nothing happens) should no longer be active. Any behavior that was depending on the context will no longer have access to that context, so if its existence was required for the behavior to function, then the behavior will be terminated, and any relationships formed between other contexts due to that behavior are broken.

Deactivation is done in the same manner as activation, :

deactivate "some context"

Knowing that Console Output will update the console display with its contents if it is activated, then it can be expected that the console won't continue to update if Console Output is deactivated:

Output Hello World :: 
    operation when initialized?
        activate output is Console Output [messages ["Hello World!"]],
        output(messages) is itself + "This is a second message.",
        
        await output,  `Wait for the behavior to update for the new message.`
        
        deactivate output,
        output(messages) is itself + "This message won't be printed.".

The above code will deactivate output, after the first two messages are printed, which will prevent the console printing behavior from outputting the last message, as would have happened once the operation completed. Besides that, there are a couple of new concepts in this code.

The keyword itself is seen when updating the value of output(messages). When used as part of an itself refers to the value being assigned to. It's a shorthand, in some cases, to updating a value that changes with reference to its previous state.

The second is await. While there is a comment in the code describing what that line is doing, it's worth noting that in general await will allow any pending reactive evaluations of the subsequent context(s) to occur before this operation continues. In this specific case, the only pending reactive evaluation is the console printing behavior updating the display for the change to messages as shown in the line directly before await.

The last line, output(messages) is "Hello World!" is assigning a single String to the list of messages in output. This will result in messages being a list with one item, the String that is Hello World!. This change will the console printing behavior to update the console's display, resulting in Hello World! being displayed to the user.

as seen later
how it is defined
original Hello World! example
deactivated
later trigger