Monad With IoCC Provides Process/Thread Model

DZone 's Guide to

Monad With IoCC Provides Process/Thread Model

In this final installment looking at the Inversion of Coupling Control (IoCC) composition, we focus on monads and providing thread models.

· Java Zone ·
Free Resource

This is the final article in the series on looking at the Inversion of Coupling Control (IoCC) composition.  The previous articles covered:

This article looks at providing a mathematical model to explain the composition.

You may also like: Functional Programming in Pure Java: Functor and Monad Examples

Just a little disclaimer that I'm not a mathematics boffin.  I have a degree in computer science, but it did not cover much functional programming. Much of this is through my self-taught understanding of functional programming and mathematics. Therefore, I'm open to feedback from more capable mathematicians on better ways to express the model. I'm hoping this article reasonably conveys the underlying model for composition with Inversion of Coupling Control.

From Category Theory, we have the associative law:

Plain Text

With this, we can introduce dependencies:

Plain Text

... where d is a set of dependencies.

This makes the program very rigid, as changing d1 to d3 has a significant impact for use of f(x)(d1 now d3). For example, switching from a database connection to a REST endpoint.

ZIO attempts to reduce the rigidity by the following:

Plain Text

... where: D = d1 + d2

Or, in other words:

   D extends d1 with d2 

Now, we can create lots of morphisms and at execution of resulting ZIO, provide a hom(D), which is the set of all required dependencies.

So, this model works. It is certainly enabling the injection of dependencies in functional programs.

Now, I'd like to take another tact to the problem.

The Imperative Functional Programming paper could not see how to remove the continuation type (z) from the signature. The authors did conclude Monads and CPS very similar, but due to the extra continuation type on the signature and the author's intuition, the IO Monad was the direction forward.

Now, I certainly am not taking the tact to replace IO Monad with CPS. I'm looking to create a complementary model. A model where continuations decouple the IO Monads.

So, by introducing dependencies to the IO Monad, we get:

Plain Text

... where: d is the set of dependencies required

This then follows, that joining two IO together we get:

Plain Text

So, maybe let's keep the IO Monad's separate and join them via CPS. This changes the signature to:

Plain Text

... where: z = Either[Throwable,x] -> ()

The pesky z that the Imperative Functional Programming paper was talking about.

However, discussed previously is Continuation Injection. This effectively hides the z from the signature, making it an injected function. As it's an injected function, the z becomes an indirection to another function. This indirection can be represented as:

Plain Text

Note: the joined IO need only handle y or any of its super types. Hence, the relationship indicates the passed type. This makes it easy to inject in another IO for handling the continuation.

Now to start isolating the IO Monads from each other, we are going to start with Thread Injection.

Plain Text

This represents Thread Injection choosing the appropriate Executor from the dependencies. Therefore, we can then introduce a Thread Injection Monad to choose theExecutor .

Plain Text

... where TI is the Thread Injection Monad that contains the dependency to Executor mapping to enable executing the IO Monad with the appropriateExecutor .

This then has the above continuation between IO Monads relationship become:

Plain Text

Now, the IO Monads can be executed by the appropriate Executor via the TI Monad.

Further to this, we can model dependency injection with:

Plain Text

... where DI is the Dependency Injection Monad that supplies dependencies to the function.

Note that DI Monad will also manage the life-cycle of the dependencies.  A discussion of how this is managed will be a topic for another article.

So, the above IO Monad continuation relationship becomes:

Plain Text

Now, with Continuation Injection, we are not limited to injecting in only one continuation. We can inject in many:

Plain Text

Note: I'm guessing this can be represented on a single line (possible asset of continuations from a particular IO), but I'll leave that to a boffin more mathematical than me.

This means we can remove the Either and have the (possibly many) exceptions handled by separate continuations to get:

Plain Text

This demonstrates that an IO may now actually have more than one output. By having the ability to inject multiple continuations, the IO is capable of multiple outputs.

It is also execution safe. OfficeFloor (Inversion of Coupling Control) ensures the handling of one continuation completes before the next continuation begins executing. This ensures only one IO is ever being executed at one time.

Further to this, we can qualify DI. Originally, we had d1, d2 that was hidden by DI. We can qualify the scope of DI as follows:

Plain Text

... where:

  P is the set of process dependency instances

  T is the set of thread dependency instances

This allows for the following:

Plain Text

In other words:

  • Spawning a thread is creating a new set of thread dependencies instances
  • Interprocess communication is a different set of process dependency instances

Further to this:

  • The set of T may only be the same if the set of P is the same
  • Context (eg transactions) apply only to dependencies in T

The resulting IO Monad relationship for the same thread continuation becomes:

Plain Text

... while a spawned thread continuation relationship is modeled as follows:

Plain Text

What this essentially allows is multi-threading concurrency. Any continuation may spawn a new thread by starting a new set of thread dependencies. Furthermore, OfficeFloor will asynchronously process the continuation of returning control immediately. This has the effect of spawning a thread.

The same goes for spawning a new process.

Plain Text

Therefore, with OfficeFloor, processes and threading are a configuration, not a programming problem. Developers are no longer required to code thread-safety into their possible imperative code within the IO. As the seldom-used process dependencies are coded thread-safe, this relationship introduces the ability for mutability within the IO that is thread-safe. The isolation of dependencies prevents memory corruption (assuming dependencies respect not sharing static state).

OfficeFloor (Inversion of Coupling Control) is in this sense possibly the dark side. Functional programming strives for purity of functions being the light. Given OfficeFloor can handle:

  • Multiple outputs from IOs including exceptions as continuations
  • Mutability within the IOs that is thread-safe

OfficeFloor enables modeling of the darker impurities (or maybe I just watch too much Star Wars).

What we now have is a possible "inversion" of the function:

Function: strives to be pure, may have multiple inputs and only a single output.    

IoCC: allows impurities, has a single input and may have multiple outputs.

I personally like to think of functions like parts of a machine. They are highly coupled engine cogs providing always predictable output.

I then like to think of IoCC like signals. This is a more organic structure of loosely coupled events triggering other loosely coupled events. The result is a mostly predictable output. This is more similar to human decisioning outputs.

Regardless, we now have a typed model that can be represented as a directed graph of interactions. The IO Monads are the nodes with the various continuations edges between them. An edge in the graph is qualified as follows.

Plain Text

... where:

  y indicates the data type provided to the continuation

  p indicates if a new process is spawned (represented as 0 for no and 1 for yes)

  t indicates if a new thread is spawned (again represented as 0 for no and 1 for yes)

The result is the following example graph.


All of the above is already implemented in OfficeFloor.

The previous articles demonstrated the type system of Inversion of Coupling Control to enable composition. The type system also enabled encapsulation in First-Class Modules for easy assembly and comprehension of OfficeFloor applications. This was then demonstrated with a simple example application.

What this article has attempted to cover is the core underlying model. It has looked at how injected continuations can be used to join together IO instances. Further, it looked at the dependencies and how they can be used to model processes and threads.

Further Reading

 Functional Programming in Pure Java: Functor and Monad Examples

For-Comprehension Free Monads in Scala

monad ,continuations ,inversion of control ,thread concurrency ,thread configuration ,thread safety ,process ,process state ,java ,iocc

Published at DZone with permission of Daniel Sagenschneider . See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}