Wednesday 25 December 2019

First-Class Module

This is the second in a series looking at the Inversion of Coupling Control type system for composition.  This article discusses a more general Module type system than the previous article's First-Class Procedure Type.

Note: some functional programming languages also attempt to define First-Class Modules.  The First-Class Modules defined in this article are created from inverted functions.

First-Class Procedure

To recap the last article, the First-Class Procedure's type is defined as follows.  Note that we exclude the dependency type, as dependencies are auto-wired.

FirstClassProcedureType {
    Class<?> parameterType;
    ContinuationType[] continuations;

ContinuationType {
    String name;
    Class<?> argumentType;

This defines the First-Class Procedure to have a single input parameter and multiple continuations out for further composition of logic and handling of exceptions.


Having a single input with multiple outputs is fine for methods, functions, etc wrapped in First-Class Procedures.   However, when systems grow we don't want the complexity to make the inputs/outputs suffer similar increased complexity.  We want the inputs/outputs to provide an interface to encapsulate the complexity of the Module.  Note that without encapsulation, we don't get the ability to modularise the complexity of the application.

To enable an interface to the Module, let's create the following input / output types:

InputType {
    String name;
    Class<?> parameterType;

OutputType {
    String name;
    Class<?> argumentType;

To understand why these types are created, we are going to use the visual configuration of Inversion of Coupling Control to better aid understanding what is happening.

The following Module configuration represents a single input, handled by a First-Class Procedure that sends its result to an output:

In the above configuration, the First-Class Procedure is encapsulated in the Module.  All that is exposed from the Module is the Inputs and Outputs.  The resulting type of the above Module would be the following:
  • Input named "Input" with a parameter passed to the First-Class Procedure
  • Output named "Output" with the argument provided by the result of the First-Class Procedure execution
This, however, provides little improvement on the First-Class Procedure interface.

What becomes useful is the encapsulation of multiple First-Class Procedures to undertake functionality of the Module:

While a new procedure was included within the Module, there was no change to the interface of the Module.  Other configuration using the Module would be unaware of the internal addition of another First-Class Procedure.

We also need not limit ourselves to single inputs and outputs.   We could have an arbitrarily complex Module that has multiple Inputs and Outputs:

The resulting Module encapsulated the detail to have the following interface:
  • Input "Input"
  • Input "Input-2"
  • Output "Output"
  • Output "Output-2"
  • Output "Output-3"

Module Type

The resulting type for the Module is the following:

SectionType {
    InputType[] inputs;
    OutputType[] outputs
Note that OfficeFloor's naming is derived from its foundation in business concepts and subsequently calls a Module a "Section".

The Module (Section) has multiple inputs and multiple outputs.  These inputs/outputs can then be connected to respective outputs/inputs of other Modules.

Furthermore, Modules may themselves contain other Modules.  As inputs/outputs are connected for composition, Modules have the same input/output connectivity as First-Class Procedures.  The following configuration demonstrates embedding the Module at the start of this article within another Module:

Whether it is the Module containing a single First-Class Procedure or two First-Class Procedures is encapsulated and not of concern within the above configuration.  The use of the Module is only on the Inputs / Outputs exposed by the Module.  The rest of the complexity of the Module is encapsulated. This allows modularising the application's complexity.

First-Class Module

So the title mentioned "First-Class Modules", yet we've only discussed visually wiring together the Modules.

To essentially be "First-Class" the Module needs to be assigned to a variable.  Yes, there are other conditions.  However, for me, this is the simplest way of thinking about something being first class.

Well the above graphical configuration is built on Sections (Modules) being configured together programmatically.  The graphical configuration is actually a layer above the First-Class Modules (Sections) to enable easier comprehension of how the application is modularised.

You can see this in OfficeFloor's implementation of the graphical configuration used above in this article.  The above graphical configuration is via an Activity. An Activity is a specific specialisation of a Section (ActivityLoaderImpl source here).  The Activity translates the XML from the graphical configuration into the creation of Sections, First-Class Procedures, Inputs, Outputs.  Each of these in the Activity implementation are assigned to variables, stored in data structures, passed to functions, returned from functions, etc.  This makes the Section (Module) essentially "First-Class".

This input / output interface based on continuations is extremely flexible.  It is so much so that First-Class Procedures themselves are also just a specialised implementation of a Section (see ProcedureEmployer).


We have seen how we can encapsulate First-Class Procedures within First-Class Modules, and even First-Class Modules within themselves.

We have shown how the graphical configuration is actually taking advantage of the "First-Class" nature.  The graphical configuration is actually a higher level composition that provides both:
  • easier to comprehend modularising of the application
  • quicker configuration of the application (effectively just draw lines for composition)
Note that it is quite possible to programmatically configure up our application.  However, this requires understanding First-Class Procedures / Modules in significantly more depth.  Much more than junior developers may want to initially.

The graphical configuration of First-Class Modules, therefore, provides the simplicity for building modularised applications.  This is without having to deal with the complexity of the underlying constructs.  Something I'm finding other composition strategies are still having trouble with.

In the next article we look at how First-Class Modules can provide composition of varying existing composition strategies.  You may find that existing composition strategies only really consider programming in the small, rather than programming in the much larger - where First-Class Modules become a lot more effective in modularising and simplifying your applications.