Software Composition in COSA
Components and Connectors
Abstract: This page describes the COSA software composition environment. COSA is an alternative software construction and execution system designed to improve reliability and productivity by several orders of magnitude. COSA is based on the premise that the primary reason that computer programs are unreliable is the age-old practice of using the algorithm as the basis of software construction. Switch to a synchronous, signal-based model and the problem will disappear. Please refer to the previous articles (The Silver Bullet, Project COSA and The COSA Operating System) in the series for important background information.
Note: This page is still under construction. The information that follows is not complete and may not accurately reflect the COSA model. Please read COSA: A New Kind of Programming and The COSA Control Hierarchy for the latest in COSA software composition.
The COSA software construction environment is designed to make software development as painless and easy to understand as possible. There is no cryptic language to learn and no syntax to worry about. A developer can quickly put an application together by dragging in a few objects into the work area and connecting them together. Once the structural design is in place, the designer can then go in and specify the underlying details. Visual software tools have been around for some time but they usually come with some sort of algorithmic scripting language and that is their main flaw. Another major flaw is the proliferation of icons. In COSA, there are only seven icons: cells (effectors and sensors), synapses, components, connectors, data and signal pathways.One of the nicer things about a component-based visual development environment is that it affords the software composer with a quick and easy way to identify and navigate through dependencies. If two objects are connected, they obviously share a dependency. Double click on an object and instantly access its specifications. Double click on a connector to modify its message or type. Pre-built components can be stored in a keyword-searchable and browsable repository or can be downloaded from the web. Drop a component into an application under development and, whenever possible, it will automatically and flawlessly connect itself to other compatible components.
Note that COSA does not prohibit the use of sequential steps to solve any problem for which one would normally use an algorithm. The main difference is that COSA is 100% change-driven. Comparison operators thus become change sensors. That is, they are self-activating as opposed to being explicitly invoked, as is the case in conventional software. A COSA development system automatically couples every sensor (comparison operators) with any effector (operation) that may potentially affect the sensor. The result is that blind code is completely eliminated, thus enabling the creation of extremely robust software. The whole thing is, of course, completely transparent to the developer.
A component is a container for cells, connectors, data, or other components. It is important to understand that components exist primarily for the benefit of the software designer and the end user. Their main function is to serve as an organizing mechanism for saving and loading, and for grouping cells together into plug-compatible ensembles. The COSA execution kernel does not handle components and connectors directly. Indeed, the kernel only “sees” cells, their synapses and their data. Nothing else. Internally, a component is a collection of pointers to cells, connectors, synapses, data and/or other components.
The left figure above shows a component with three female and three male connectors. Double clicking on a component opens it up to reveal its contents. The picture on the right shows a component that has been clicked open to reveal several other components. In this case, the designer chose eight internal connectors to be externally accessible. Note that three of the externally accessible connectors are grouped into a single male multi-connector on the left side of the component. The actual layout of objects inside a component enclosure is arbitrary and is left to the discretion of the designer. The naming labels are omitted in the figures due to the reduced size. User-created labels (such as ‘Save Document’, ‘count++’, ‘A = B + C’ or ‘width != 60’) make it easy to figure out what is actually going on. The developer has the option of showing or hiding the labels. In the case of elementary cells, labels can be automatically created by the development tool.
There are two types of components, low-level and high-level. A low-level component contains one or more elementary cells, at least one connector (for input) and associated data. A high-level component consists of one or more other components. Cells are not allowed to exist at the same containment level as components. A component can be thought of as an inheritance mechanism. Drop a component into another and the target component automatically inherits the functionality of the other.
The figures below show examples of what a designer may see after double clicking on a component icon. The left figure is a high-level component and the right figure is low-level component. The color scheme is as follows: all components are painted dark green; effectors are light green and sensors are yellow. The small red circles are male connectors or synapses. Female synapses can be either white (positive) or black (negative).
New: The Parallel QuickSort Example offers more details on software composition in COSA.
The "while loop" component (above right) is a low-level component because it contains only cells. The one-shot assignment effector (1=) initializes the loop upon receipt of a start signal and then activates the two “loop” effectors (100+ and 100=). The effectors repeatedly increments an internal counter variable while adding (the 100+ cell) and storing data (the 100= cell) in memory until either the not-equal (!=) comparison sensor is satisfied or the effectors have run their course. The dashed-line bracket joining the 100+ and the != cells indicates a sensor-effector association. When the comparison is satisfied, the comparison sensor (!=) outputs a signal that stops both effectors simultaneously. It also sends a signal to the OR detector to indicate that the loop has terminated. The cell fires if it receives a signal from either the comparison sensor or the 100= effector. This means that there are two ways in which the loop can terminate: either the comparison is satisfied or the effector has run its course. The equivalent algorithmic code might look something like this in C++:
Constructing the loop component consists of using the mouse to drag the desired cells and connectors into a new component enclosure, and then connecting them together. Each connector is automatically given a unique ID. It is up to the designer to accept the default or use an existing ID. Click on the data structure to define the operands and constants for the component. Click on the effectors to open up a property box. This will allow you to specify the operator and operand types for each effector. Use the mouse to connect the cells to each other as desired. Finally connect the cells to the connectors. Of course, if you already have a loop component in the repository (which is very likely), it is easier to just copy the existing component and modify it to suit your requirements. Most low-level development in COSA will consist of reusing existing components.
The reentrancy problems that sometimes plague conventional algorithmic software are nonexistent in COSA. The loop component provides a perfect example of how potential timing conflicts are resolved. What would happen if the component receives a second start signal while the loop is still running? During development, COSA enforces the Principle of Motor Coordination or PMC which states that a start signal must not follow another start signal and a stop signal must not follow another stop signal. The PMC enforcer alerts the designer whenever there is a timing conflict. In the loop component, a conflict would be flagged if either of the two loop effectors receive a start signal before they are finished.
If two or more components require the services of another component simultaneously, they must use a message server. The latter places all request messages in a queue to be processed one at a time. If necessary, especially in time-critical environments, multiple instances of a loop component may be used simultaneously.Note: The above does not mean that a recurrent process cannot be implemented within a component or with the use of two or more components. Reentrance is not the same as recurrence.
High-level components do not have data at their level. They are just containers for other components. Most low-level components will have a data structure, the properties of which can be accessed by its cells. Components cannot directly access each other's data. That is to say, a component's internal data is always private. The only way a component may access another component's data is through an explicit request message. For example, a quick sort component may receive a request from another component to sort an array of integers. After completing the request, the sorter sends a 'service completed' signal back to the service requester.The only data that may be shared directly between two components is message data. Even then, the destination component only has read permission. This is because two communicating components share a single message structure. The primary reason for the strict rule against data sharing is to prevent misuse. It would be too easy for one component to modify a property in another component without the knowledge of the other. This can potentially lead to incorrect assumptions and ultimately to catastrophic failure. In multi-threaded architectures, it is customary to use semaphores and other techniques to prevent two threads from simultaneously accessing a data structure. These techniques are not used in COSA because data sharing is forbidden.
A connector is a mechanism used by the designer to link two components together. Internally, however, only cells can be connected to one another, as explained below. Connectors exist mainly for the benefit of the application developer. The same can be said of components. Connectors do nothing, in and of themselves. Their purpose is to enforce compatibility between connected components. There are two types of connectors: uni-connectors and multi-connectors.
Data typing in COSA follows the same principles as data typing in algorithmic languages such as C and C++. In other words, types will include integer, long integer, floating point, character, etc... In addition, the software developer will have the option of creating custom data types from any combination of the basic types. Typing enforcement is maintained automatically at the connector level. It is impossible to create two matched (male/female) connectors with incompatible message types.
Every application is a COSA component and, as such, is an extension of the operating system. However, COSA comes with a suite of service components that form the core of a minimum operating system. Examples are message servers (stack-based and queue-based), file I/O server, memory manager, connection manager, component constructors and destructors, component and cell containers (lists, arrays, etc...), print manager, graphics manager, RAD development tools, etc... Of special importance is the connection manager (CM) which can be used by an application/component for self-modification. The CM can be directed to create new connections on the fly or to sever one or more existing connections if necessary. This can happen either at the component level or the cell/synapse level.
Note: I am preparing a page on Service Components. To be continued...
The component repository is a browsable and keyword searchable SQL database. Its job is to facilitate and encourage reuse during application development. After a component has been tested and documented, it should be dropped in the repository for future reuse. The repository comes with tools that automatically searches a stored component's documentation for pertinent keywords. Software designers should make it a habit of searching the repository before creating a new component.
©2004-2006 Louis Savain
Copy and distribute freely