Temporal coupling

Spacerat

Expert Member
Joined
Jul 29, 2015
Messages
1,524
Reaction score
653
I created this thread on Temporal coupling as it was mentioned by [MENTION=8711][)roi(][/MENTION] in his thread on DI
https://mybroadband.co.za/vb/showthread.php/970155-Dependency-Injection-Method(s)-and-a-Challenge.

Temporal coupling is related to DI when it comes to injecting dependencies by means of property injection after construction. However, there are other scenarios that is also regarded as temporal coupling that has nothing to do with DI, hence I created this thread to discuss it here.

What is temporal coupling?
"A common problem in API design is temporal coupling, which occurs when there's an implicit relationship between two, or more, members of a class requiring clients to invoke one member before the other. This tightly couples the members in the temporal dimension."
 
Last edited:
Great idea to split this off; because it will allows me to not sidetrack the DI thread by posting the example code that deals with coupling.

Here's two blogs on the coupling: temporal and behavioural.


I'll tackle the first posts later this evening (in about an hour or two), firstly on an easy solution to work around setter and / or other property coupling issues by using a simple VB-esque style with higher order function.

And if time permits tonight, this will be followed by a templating example using Extensions higher order functions (methods) that can be use to create templates for things like UI Buttons, or any class with many properties and/or setters that are typically configured after the instantiation of class.
 
Last edited:
Setter injection example:
Here's a contrived illustration of the possibility for an indeterminate state with an object whose dependency is injected via a setter method as opposed to constructor method injection.

First we'll define an Interface for a Dependency:
PHP:
public interface IDependency {
  int getStuff();
  void setStuff(int value);
}

Next let's define a class that conforms to this interface i.e. we're creating a Dependency class that can be injected.
PHP:
public class Dependency: IDependency {
  private int stuff = 3;
  public Dependency() {}
  public int getStuff() {
    return stuff;
  }
  public void setStuff(int value) {
    stuff = value;
  }
}

Next's let's create a class that has a property dependency that needs to be injected, and we'll define a setter method to facilitate the injection of this.
PHP:
public class TestObjectPI {
  int foregroundColor;
  public string titleMessage = "Hello, World!";
  public bool drawBorder = false;
  public bool drawBackground = false;
  private bool drawShadow = false;
  public IDependency dependency;

  public TestObjectPI(int foregroundColor)
  {
    this.foregroundColor = foregroundColor;
  }

  public void setDependency(IDependency dependency) {
    this.dependency = dependency;
  }

  public void setDrawShadow(bool value)
  {
    drawShadow = value;
  }

  override public string ToString()
  {
    return String.Format(
      "foregroundColor: {0}, titleMessage: {1}, drawBorder: {2}, drawBackground: {3}, drawShadow: {4}, stuff: {5}",
      foregroundColor, titleMessage, drawBorder, drawBackground, drawShadow, dependency.getStuff());
  }
}

Ok let's look at the instantiation of our TestObjectPI:
PHP:
var test = new TestObjectPI(123);

// at this point in the execution; our test instance is in an indeterminate
// state because our Dependency still has not be injected
Only after this instruction can our test object be considered to be properly instantiated.
PHP:
test.setDependency(new Dependency());

This possibility for an indeterminate state is the essence of a coupling issue; whereas injecting a dependency in the constructor method would not permit this indeterminate state. Coupling scenarios can extend to a greater degree of complexity; where the order of dependent object instantiation also becomes critical to in its success. More details on the complexities surrounding DI and instantiation challenges is covered in this article: https://medium.com/easy-pieces-for-...to-loving-functional-programming-7019e1bf9bba

Next post will look what we can do to work around this coupling problem.
 
Last edited:
Work arounds for the setter injection coupling issues

Option1: convert the class from setter to constructor injection:
PHP:
public class TestObjectCI {
  int foregroundColor;
  public string titleMessage = "Hello, World!";
  public bool drawBorder = false;
  public bool drawBackground = false;
  private bool drawShadow = false;
  public IDependency dependency;

  public TestObjectCI(int foregroundColor, IDependency dependency) {
    this.foregroundColor = foregroundColor;
    this.dependency = dependency;
  }

  public void setDrawShadow(bool value) {
    drawShadow = value;
  }

  override public string ToString() {
    return String.Format(
      "foregroundColor: {0}, titleMessage: {1}, drawBorder: {2}, drawBackground: {3}, drawShadow: {4}, stuff: {5}",
      foregroundColor, titleMessage, drawBorder, drawBackground, drawShadow, dependency.getStuff());
  }
}

Option 1 instantiation
PHP:
var test = new TestObjectCI(123, new Dependency());

// no more indeterminate state, instantiation of test also instantiates its dependency

Option 2: create a With higher order method extension that allows us to inject dependency at the same time as the instantiation of our object:
Assuming we can't change the original because either we don't have the source and/or its part of some existing framework.

Creating a C# rendition of VB's With keyword
:
PHP:
static class ExtensionWithMethod {
  public static A With<A>(this A a, Action<A> f)
  {
    f(a);
    return a;
  }
}

Ok let's see how this can be used to change the way that we instantiate our setter injected class TestObjectPI:
PHP:
var test = new TestObjectPI(123).With(o => {
  o.setDependency(new Dependency());
});
A little bit longer, but it avoids the coupling issue.

This extension method however is of course not just restricted to this scenario, we can use it to configure other properties at the same time, in much the same way as it's VB keyword counterpart, for example:
PHP:
var test = new TestObjectPI(123).With(o => {
  o.setDependency(new Dependency());
  o.drawBackground = true;
  o.drawBorder = true;
  o.setDrawShadow(true);
});

The 3rd option is of course to either subclass and fix the problem (if that's permitted), or to wrap the existing class in a new class that circumvents the coupling issue.

Next post is going to expand on the concept of the With extension method; in order to examine how we can create configuration templates for classes that have a lot of separately configurable properties & setters.
 
Last edited:
How to create template lambda functions for the configuration of a class with a lot of property / setter permutations.
In some situations you may want to provide some interface flexibility that allows the customisation of properties / setters of a class like System.Windows.Controls.Button .... or you simply may just want better control over how your class objects properties and setters are configured. Templating functions are a simple way to package these for later application.

To illustrate the possibilities for templating styles; I'm going to use the TestObjectCI in the previous posts to illustrate how this can done. As you should see this contrived class has a number of properties, and a few setter methods, including that of its dependency that can be configured.

Composing with void returns method calls (setters / properties assignments)
When configuring these properties or setter methods, we are typically engaging with void returning method calls. Which as you might know are not typically suitable for standard composition.

Let's look at a few contrived examples of different template lambda functions for the configuration of our TestObjectCI instance:
PHP:
Action<TestObjectCI> bgTemplate = o => {
  o.drawBackground = false;
  o.titleMessage = "Hello, Pluto!";
};

Action<TestObjectCI> bgTemplate1 = o => {
  o.drawBackground = false;
  o.titleMessage = "Hello, Mars!";
};

Action<TestObjectCI> bgTemplate2 = o => {
  o.drawBackground = false;
  o.titleMessage = "Hello, Jupiter!";
};
Above we have 3 lambda functions that take a single parameter; and instance of TestObjectCI and apply some property changes.

Now let's define another lambda function to enable the border property:
PHP:
Action<TestObjectCI> boTemplate = o => {
  o.drawBorder = true;
};

Let's see how we'd use these template functions:
PHP:
var test = new TestObjectCI(123, new Dependency());

bgTemplate(test);  // drawbackground = false, titleMessage = "Hello, Pluto!"
boTemplate(test); // drawBorder = true
That certainly isn't much more elegant than just setting the properties directly.

Question now is how can we concatenate these templates
In order to create a composite lambda function that will not only disable the drawBackground, set the titleMessage but will also enable drawBorder.
Without of course having create another new Lambda function.

Why? Think of the permutations with a class with a lot of styling properties
How could you provide flexibility of styling if you were limited to the permutations of lambda functions you had created beforehand. Boilerplate nightmare scenario.

There is of course a better solution for this
We can work around this void returning method / setter composition problem by creating some extension methods that will help us concatenate two void returning functions.
PHP:
static class ExtensionTemplateMethods {
  // Concatenate the two Unary non value returning functions 
  // By apply the first followed by the se
  // (A) -> void + (A) -> void i.e. two Action<A> functions
  public static Action<A> Concat<A>(this Action<A> f, Action<A> g)
  {
    return (a) => {
      f(a);
      g(a);
    };
  }

  // Pipe a value into a Unary Non Value returning function and return the result
  // i.e. Apply an Action<A> to A and return the result.
  // Mutable pipe; returns a reference to the input object
  public static A Pipe<A>(this A a, Action<A> f)
  {
    f(a);
    return a;
  }
}

Let's see how we use this to concatenate templates and apply it to a target object:

First let's define a few more templates
PHP:
Action<TestObjectCI> shadowTemplate = o => {
  o.setDrawShadow(false);
};

Action<TestObjectCI> stuffTemplate = o => {
  o.dependency.setStuff(33);
};

Now let's concatenate the bgTemplate with the boTemplate and the stuffTemplate and store this combination as bgBoShadowTemplate
PHP:
var bgBoShadowTemplate = bgTemplate.Concat(boTemplate).Concat(stuffTemplate);
... let's apply it to our test instance.
PHP:
test.Pipe(bgBoShadowTemplate);

This of course can all be done at the same time in 1 instruction:
PHP:
test.Pipe(bgTemplate1.Concat(boTemplate).Concat(shadowTemplate));

This is all being affected to the mutable state of test object i.e. 1 change will potentially overwrite another.

How to avoid this is of course a subject of immutability; which is a new post that will have to wait until tomorrow.
 
Last edited:
BTW if you missed how this could ever translate into a flexible solution for styling; then let me provide a quick run through of how this could work:
  1. First we'd define lambda functions for the properties we want to be able to set, including the flexibility to turn something on or off, select a color, define border width, etc.
  2. Next we'd provide an interface that allowed the user to select which of the lambda styling to apply including their chosen setting values: true / false, borderwidth, etc.
  3. Next we'd append these styled lambda functions to an array, which is possible because they all share the same type signature i.e. Action<TestObjectCI>
  4. Next we use Linq to reduce over this array using our Concat method to concatenate our templates together using the Concat extension method until we have a single template variable that will be the combination of all the configured settings.
  5. Finally we'd use Pipe to apply this combination template to our object instance

Easy Peasy :sick:, hope that makes sense :p
 
Last edited:
Continuing with the templating example:
... but this time focusing on this ending statement:

This is all being affected to the mutable state of test object i.e. 1 change will potentially overwrite another.

How to avoid this is of course a subject of immutability; which is a new post that will have to wait until tomorrow.
If we didn't want the Pipe extension method to affect the mutable state of an object, primarily because of the outcome can be unpredictable; then we'd probably want to have a second immutable implementation of Pipe that would:
  1. make a copy of an existing object,
  2. apply the templating
  3. and finally return that instance
Here's a bit of code to achieve:
C#:
static class ExtensionPipeSerializable {
  public static A CloneSerializableObject<A>(this A o) where A: class
  {
    var ms = new MemoryStream();
    var bf = new BinaryFormatter();
    bf.Serialize(ms, o);
    ms.Position = 0;
    object result = bf.Deserialize(ms);
    ms.Close();
    return (A)result;
  }

  // Immutable Pipe (creates a copy of the input object)
  // returns a copy of the input with Action effected.
  public static A PipeI<A>(this A a, Action<A> f) where A: class
  {
    var b = a.CloneSerializableObject();
    f(b);
    return b;
  }
}

The curve ball is that this implementation requires a class to adorned with the [Serializable()] tag, for example:

C#:
  [Serializable()]
  public class TestObjectCI {
    int foregroundColor;
    public string titleMessage = "Hello, World!";
    public bool drawBorder = false;
    public bool drawBackground = false;
    private bool drawShadow = false;
    public IDependency dependency;

    public TestObjectCI(int foregroundColor, IDependency dependency) {
      this.foregroundColor = foregroundColor;
      this.dependency = dependency;
    }

    public void setDrawShadow(bool value) {
      drawShadow = value;
    }

    override public string ToString() {
      return String.Format(
        "foregroundColor: {0}, titleMessage: {1}, drawBorder: {2}, drawBackground: {3}, drawShadow: {4}, stuff: {5}",
        foregroundColor, titleMessage, drawBorder, drawBackground, drawShadow, dependency.getStuff());
    }
  }

Which then permits us to use PipeI to make a copy of our object before applying the template changes, for example:
C#:
var test1b = With(new TestObjectCI(126, new Dependency()), a => {
  a.drawBackground = true;
  a.drawBorder = true;
  a.setDrawShadow(true);
});

var newTest1b = test1b.PipeI(bgTemplate1.Concat(boTemplate).Concat(shadowTemplate));
Console.WriteLine(newTest1b);
Using this rudimentary serialization / deserialization method, we end up with a newTest1b instance that is a copy of test1b, to which we have also applied the concatenation of 3 templates:
  • bgTemplate1
  • boTemplate
  • shadowTemplate
In that order.

Naturally for more complex scenarios with a either class that cannot be easily work with the [Serializable()] tag, or a class we don't own; we'd have to come up with a different solution for this, or just try to find a better work around for the unpredictable nature of mutability.

For example in CSS; it's quite common to see the use of a normalize.css file, which essentially provides a bit of reset button on CSS settings in order to avoid this mutable problem.
 
Last edited:
Ok so the new forum did not include my post to the old forum. Here it is again.

To write quality code, defective code needs to fail fast (ASAP) and fail loudly (be observable). Rather have your code fail at compile time than runtime. I.e. let the compiler help you resolve defects before runtime.

Having an object in an indeterminate/unintended state after ctor or at any time is a really bad idea. The API (ctor, methods, properties) of an object should never allow a user to put an object into an unintended state. An object should only exist in a valid state or not at all. Even if a user does not read the docs, he must not be able to use the object in such a way that will put the object into an invalid state.

If an object has mandatory dependencies, resolving those dependencies after ctor by means of property injection is a recipe for failure down the line. This is one example of temporal coupling and is considered a design smell. IMO, it is acceptable to resolve optional dependencies after ctor because the object will cater explicitly for the fact that the dependency is optional and might not be set. Ctor injection of mandatory dependencies is commonly regarded as good practice. The ctor advertises what the object dependencies are in no uncertain terms. No need to look at methods and properties to try and figure out if you need to call/set something after ctor. With ctor injection you will not be able to create the object without providing all the dependencies to the ctor. Also, the compiler will tell you if you are missing a dependency. I.e. your code breaks at compile time which is good.

All this being said, although new code should never employ temporal coupling, there are masses of code out there that suffers from this. The With<> extension method solution is pretty neat. It does make it easier to supply dependencies after ctor. However it does not solve the problem of temporal coupling. The call of the With is still optional and suffers from temporal coupling in itself. Instantiating TestObjectPI throughout a code base still requires you remembering to call the With as well. If we were to add another dependecy to TestObjectPI , we would need to go throughout our code base and update code where we instantiated TestObjectPI to modify it. Not much of a win because the compiler wont tell us.

My preferred way of dealing with this type of temporal coupling is to use the Factory pattern. The Factory pattern also does not solve the fact that TestObjectPI suffers from temporal coupling nor does it prevent the user from instantiating it without the required dependencies. What it does however do, is to establish a different habit of instantiating TestObjectPI that is safer in the sense that it forces you to supply the dependencies.

Code:
public class TestObjectPIFactory
{
  public static TestObjectPI Create(int foregroundColor, IDependency dependency)
  {
    TestObjectPI obj = new TestObjectPI(foregroundColor);  
    obj.setDependency(dependency); 

    return obj

    // Or use new TestObjectPI(foregroundColor).With()....
  }
}

Then to create a TestObjectPI instance:

Code:
    TestObjectPI obj = TestObjectPIFactory.Create(foregroundColor,dependency);


or, depending on your use case

Code:
public class TestObjectPIFactory
{
  public TestObjectPIFactory(IDependency dependency)
  {
    this.dependency = dependency;
  }

  public TestObjectPI Create(int foregroundColor)
  {
    TestObjectPI obj = new TestObjectPI(foregroundColor);  
    obj.setDependency(dependency); 

    return obj

    // Or use new TestObjectPI(foregroundColor).With()....
  }

  private readonly IDependency dependency;
}

and
Code:
    TestObjectPI obj = instanceOfTestObjectPIFactory.Create(foregroundColor);



If you add a dependency to TestObjectPI, you only make the change in the Factory class.

Code:
public class TestObjectPIFactory
{
  public static TestObjectPI Create(int foregroundColor, IDependency dependency, IAnotherDependency anotherDependency)
  {
    TestObjectPI obj = new TestObjectPI(foregroundColor);  
    obj.setDependency(dependency); 
    obj.setAnotherDependency(anotherDependency); 

    return obj

    // Or use new TestObjectPI(foregroundColor).With()....
  }
}

Then to create a TestObjectPI instance:

Code:
    TestObjectPI obj = TestObjectPIFactory.Create(foregroundColor,dependency,anotherDependency);

or

Code:
public class TestObjectPIFactory
{
  public TestObjectPIFactory(IDependency dependency,IAnotherDependency anotherDependency)
  {
    this.dependency = dependency;
    this.anotherDependency = anotherDependency;
  }

  public TestObjectPI Create(int foregroundColor)
  {
    TestObjectPI obj = new TestObjectPI(foregroundColor);  
    obj.setDependency(dependency); 
    obj.setAnotherDependency(anotherDependency); 

    return obj

    // Or use new TestObjectPI(foregroundColor).With()....
  }

  private readonly IDependency dependency;
  private readonly IAnotherDependency anotherDependency;
}

and instantiate:

Code:
  TestObjectPI obj = instanceOfTestObjectPIFactory.Create(foregroundColor);

In the above case only the factory ctor and Create method was affected by the additional dependency.
In both cases, adding the dependency will cause the compiler to tell you that something is wrong. I.e your code fails at compile time.
 
Same problem re lost posts. I asked when / if these would be restored; but I guess MyBB staff were too overwhelmed with other issues to be bothered about this.

So we're forced to manually try to recreate these posts -- whilst this won't be an exact match to my previous comments I think in conceptually it should be similar.

To write quality code, defective code needs to fail fast (ASAP) and fail loudly (be observable). Rather have your code fail at compile time than runtime. I.e. let the compiler help you resolve defects before runtime.
No problems with the general concept; except practically we'll certainly differ on how to accomplish this.

As for the compiler fixing defects before runtime / compile time -- yes, but the factory pattern offers very little in that regard; the more modern approach is to employ Algebraic Data Types (ADTs). This while driving compiler correctness; it achieves this by arguably convoluting our types with more superficial type embellishments.

The With<> extension method solution is pretty neat. It does make it easier to supply dependencies after ctor. However it does not solve the problem of temporal coupling. The call of the With is still optional and suffers from temporal coupling in itself. Instantiating TestObjectPI throughout a code base still requires you remembering to call the With as well. If we were to add another dependecy to TestObjectPI , we would need to go throughout our code base and update code where we instantiated TestObjectPI to modify it. Not much of a win because the compiler wont tell us.
Sure, but the factory pattern is no less flawed, as are many of the by choice constructs in programming today. the goal of With and Templating is relatively similar to the factory pattern -- but I'd argue one is substantially more flexible simply because it promotes composition.


As to the greater issue of coupling;
I'd reason the constructor and/or property dependency models whilst adequately providing for a separation of concerns -- are inherently flawed because they've hitched their ride to mutability; and there-in we've also lost:
  • any guarantees about side effects.
  • ease of composition.
  • the ability to pinpoint the cause of runtime bugs
  • concurrency
  • a clean API -- re we have no choice but to pollute the API with dependencies, not forgetting to mention the unfortunate repetition when a dependency has to be passed around through a number of interlinked constructor calls.
Side Note:
As for what's a better approach, really depends on the situation; simple and not too complex I'd probably argue for a environment singleton; increase flexibility and avoids pollution of the API but doesn't solve the mutability concern. Whereas to avoid that; I'd probably lean towards a Reader Monad (aka environment monad). For more complex architectures I probably steer the discussion in the direction of the Free Monad, which is essentially the Interpreter pattern merged with a Monad -- not for its affordances ito syntax, but rather the ability of the Abstract Syntax Tree (AST) in modelling computations.

Both Monad options avoid the problems of mutability and I'd argue offer far more opportunity to simplify API and increase versatility overall. Practically as I mentioned both these concepts deserve their own threads in order to understand the extent of the benefits and wins over OOP dependency approaches.
 
Last edited:
As for the compiler fixing defects before runtime / compile time -- yes, but the factory pattern offers very little in that regard;

Sure, but the factory pattern is no less flawed, as are many of the by choice constructs in programming today.


... and there-in we've also lost:
  • any guarantees about side effects.
  • ease of composition.
  • the ability to pinpoint the cause of runtime bugs
  • concurrency
  • a clean API -- re we have no choice but to pollute the API with dependencies, not forgetting to mention the unfortunate repetition when a dependency has to be passed around through a number of interlinked constructor calls.

Agreed, the factory class in itself does not fix the fact that we have a 'problem' class. However, the use of the factory forces us to comply to the convention of having to supply all dependencies. To me personally, it promotes a habit of using the factory and 'forgetting' about the class constructor. I park the constructor at the back of my mind and establish a convention for using the factory.

As for passing dependencies along a composition ctor chain, yes that is a pain. I suppose that is why many devs use a ServiceLocator. But that is an anti-pattern and also not good. Unfortunately I don't have a great solution to that.
 
Agreed, the factory class in itself does not fix the fact that we have a 'problem' class. However, the use of the factory forces us to comply to the convention of having to supply all dependencies. To me personally, it promotes a habit of using the factory and 'forgetting' about the class constructor. I park the constructor at the back of my mind and establish a convention for using the factory.

As for passing dependencies along a composition chain, yes that is a pain. I suppose that is why many devs use a ServiceLocator. But that is an anti-pattern and also not good. Unfortunately I don't have a great solution to that.
Hence I said its the same concept as the With and Template options -- re they compose very easily so its very easy to wrap these in a lambda function that offers everything and more that the Factory pattern offers.

Same concept; the key difference is the design approach:
  • first approach makes the Class the center point for construction
  • whereas with the other approach it's the Function that is the center point
 
As for passing dependencies along a composition ctor chain, yes that is a pain. I suppose that is why many devs use a ServiceLocator. But that is an anti-pattern and also not good. Unfortunately I don't have a great solution to that.

FYI with the Reader Monad the dependency API of a constructor is typically swapped out for a static constructor method where the dependency is encapsulated in the return type signature as opposed to the Constructor method's parameters, for example:

C#:
class User {
  User(string email, Service service) {
    ...
  }

Would be converted to something like this with the ReaderMonad:
C#:
class User {
  static Reader<Service, User> Create(string email) {
   ...
  }
}

i.e. dependencies are encapsulated in the return type; with the benefit that it:
  • promotes composition; meaning we can easily compose multiple dependencies type signatures and actions without any complication to the API.
  • supports lazy transformations e.g. map, process chaining e.g. flatMap / bind, etc....
...and of course we don't need this "passing dependencies along a composition ctor chain".
 
Last edited:
TBH I don't get your static ctor example above. Can you expand and/or show a more concrete example?
 
The approach adopted by the Reader Monad is based on the principle that all dependencies essentially have a function signature of f(A) -> B.

So when you look at the reader type signature, you should envisage that Reader<Service, User> is referring to a function that takes a Service conformance as a dependency for the input and returns a User as the output i.e. Service is the A and User is the B in the function f(A) -> B.

Reader btw is not a very complicated structure -- the basics are essentially this:
C#:
// E refers to the Environment, whereas A is the output type
// i.e. the function signature is f(E) -> A
// keep in mind that these are simply generic placeholders, we could call them Environment and Output instead of E and A
public class Reader<E, A> {
   Func<E, A> f;
    Reader(Func<E, A> f) {
      this.f = f;
   }

    public A run(E e) {
      return f(e);
   }
}
To which we add add Functor (map), Monad (flatmap / bind) and Applicative (pure / apply) conformances that in the C# sense essentially mean our reader can apply transformations and bindings similar to Linq's Enumerable; except far more flexible, for example we can have a function that is injected with a Service dependency that returns a User, to which we then apply a transformation or we bind to another process, etc.

Anyway, if you're interested to see how this plays our in a code; then I'll try to find spare time to include either with the Github repository challenge, or to present this more completely at a later date in a separate thread.

Rough mockup use example:
C#:
class User {
  // type signature defines that out Create function has dependency for Service.
  // This can of course be an interface conformance e.g. IService
  static Reader<Service, User> Create(string email) {
    return Reader { (service) => return service.getUser(email); }
  }
}

var service = new Service(); // instantiate the conforming dependency
var user = User.Create(”[email protected]”).run(service); // injection of conforming instance.

Note:
the run method cannot be executed without providing a conforming instance. i.e. we don't have the problem of property injection and it plays well with the compiler. Naturally the environment can be more than just a single object dependency, hence the environment moniker. For more complexity we can build this up with either or both: composition and monadic process binding.

Also keep in mind that we don't have to execute the run at the point of the user variable declaration; and by leaving off the run, e.g. var user = User.Create(”[email protected]”); we have essentially a function that can return a User object, that we can pass around and/or compose with other things.

You can see this as a way to flip the dependency injection around, normal ctor dependency would have this type of signature: Dependency -> Action -> Result, whereas the reader turn this into (Action -> Result).run(Dependency)
 
Last edited:
Tx for the response. I need to however chew on that. I am not at all familiar with functional way of thinking TBH. So this is foreign to an extent, but I get how the code works. Somehow I am not seeing the benefit of this approach. Maybe a more concrete example would help me. :unsure:
 
Tx for the response. I need to however chew on that. I am not at all familiar with functional way of thinking TBH. So this is foreign to an extent, but I get how the code works. Somehow I am not seeing the benefit of this approach. Maybe a more concrete example would help me. :unsure:
The approaches from FP always tend to flip things on their head including switching around the order of inputs. Plus we should acknowledge many of difference come from the fact that FP's primary unit of construction is the function in contrast with OOP's class.

Perceiving the benefit will certainly need a more comprehensive example. The github repo challenge is too simplistic to show the full extent of this. So I think we probably will need to open up a new thread on FP's approaches to DI once we wrap up the two we have running concurrently.

As simple example of where flipping things around helps:
Imagine you have a class method that returns a User object from a web service by using their email as the lookup. In OOP you would inject web api dependency into the User class constructor, so we could support offline coding, test mocking, API service changes, etc...

Now let's say retrieving the User object is really only a step in a chain of processes; where the returned User object is fed into another process that may or may not have more dependencies, and so on, ... The Reader approach by enabling both composition and monadic binding makes this very easy because in code we not only can create a single composition that represents the end of process object(s) I need; I can take it a step further and apply transformations; without the need to pre-inject any dependency ahead of time and/or to funnel the dependencies from one class through to the next.
 
Last edited:
Perceiving the benefit will certainly need a more comprehensive example. The github repo challenge is too simplistic to show the full extent of this. So I think we probably will need to open up a new thread on FP's approaches to DI once we wrap up the two we have running concurrently.
Would be interested to have a look at a comprehensive example.

Imagine you have a class method that returns a User object from a web service by using their email as the lookup. In OOP you would inject web api dependency into the User class constructor, so we could support offline coding, test mocking, API service changes, etc...

Personally I would not do it like that because you then couple the User to an infrastructural/persistence service. You should never make domain objects (assuming User is a domain type object) depend on any infrastructure services. The webservice should rather follow an IRepository type pattern where the implementation detail fetches the user from the endpoint e.g.

Code:
public interface IUserRepository
{
  User GetByEmail(string email);
}

public class WebServiceUserRepository:
  IUserRepository
{
  public WebServiceUserRepository(string endpoint)
  {
    this.endpoint = endpoint;
  }

  public User GetByEmail(string email)
  {
    // Get from webservice endpoint
  }

  private readonly string endpoint;
}
 
Would be interested to have a look at a comprehensive example.



Personally I would not do it like that because you then couple the User to an infrastructural/persistence service. You should never make domain objects (assuming User is a domain type object) depend on any infrastructure services. The webservice should rather follow an IRepository type pattern where the implementation detail fetches the user from the endpoint e.g.

Code:
public interface IUserRepository
{
  User GetByEmail(string email);
}

public class WebServiceUserRepository:
  IUserRepository
{
  public WebServiceUserRepository(string endpoint)
  {
    this.endpoint = endpoint;
  }

  public User GetByEmail(string email)
  {
    // Get from webservice endpoint
  }

  private readonly string endpoint;
}
I think we are missing each other here; because the Reader Monad doesn't force you into a particular style of architecting your dependencies including how this ties in with interfaces. It provides the same affordances ctor injection does, except that it achieves this differently, in a solution that is far more composable and avoids problems like the funnelling of dependencies in a process / computation chain.

As soon as I have a moment spare I'll throw together a hopefully more meaning example to compare the reader approach with ctor injection.
 
@Spacerat picking up from the last point of discussion re the reader monad; been a bit busy with another project and had to take a trip.

I've thrown together a simple example of how the reader monad pattern can be used for dependency injection; and how it switches around around how dependencies are defined / injected.

First off let's define some simple models around which we'll craft a few dependency examples:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using LanguageExt;
using static LanguageExt.Prelude;

namespace ReaderMonadDI
{
  public sealed class Student {
    public readonly string lastname;
    public readonly int id;

    private Student(string lastname, int id) {
      this.lastname = lastname;
      this.id = id;
    }

    public static Student Create(string lastname, int id) {
      return new Student(lastname, id);
    }

    override public string ToString() {
      return String.Format("Student: [lastname: {0}, id: {1}]", lastname, id);
    }
  }

  public enum Subject {
    Math, Science, English
  }

  public sealed class Grade {
    public readonly int id;
    public readonly int year;
    public readonly Subject subject;
    public readonly int score;

    private Grade(int id, int year, Subject subject, int score) {
      this.id = id;
      this.year = year;
      this.subject = subject;
      this.score = score;
    }

    public static Grade Create(int id, int year, Subject subject, int score) {
      return new Grade(id, year, subject, score);
    }

    override public string ToString() {
      return String.Format("Grade: [id: {0}, year: {1}, subject: {2}, score: {3}]", id, year, subject, score);
    }
  }
}
 
Last edited:
Top
Sign up to the MyBroadband newsletter
X