Thread overview
class Object with Dependency Injection
Jun 18, 2023
Salih Dincer
Jun 18, 2023
Ali Çehreli
Jun 18, 2023
Salih Dincer
June 18, 2023

Hi, below is an example of DI-dependency injection with 3 versions nested in the code. If you remove the leading // characters, you will not get the "no property deliver for service of type object.Object" error. Because version-2I with interface wants its methods to depend on Object..

//abstract class /* toggle-code
interface //* ^---version 2A */
ITransport
{
  string deliver();
}

class Ship : ITransport
{
  override string deliver()
  {
    return "Ship Deliver";
  }
}

class Truck : ITransport
{
  override string deliver()
  {
    return "Truck Deliver";
  }
}

abstract class Logistics
{
  ITransport createTransport();

  auto operations()
  {
    return createTransport.deliver();
  }
}

class RoadLogistics : Logistics
{
  override ITransport createTransport()
  {
    return new Truck();
  }
}

class SeaLogistics : Logistics
{
  override ITransport createTransport()
  {
    return new Ship();
  }
}

import std.stdio;
void main()
{
  // DI version 1:
  auto sl = new SeaLogistics;
  auto rl = new RoadLogistics;

  auto logistics = [ sl, rl ];
  foreach(deliver; logistics)
  {
    auto str = deliver.operations();
    str.length.writeln(": ", str);
  }

  import std.range : repeat;
  "÷ ".repeat(9).writefln!"%-(%s%)";

  // A->I version 2:
  auto truck = new Truck;
  auto ship = new Ship;

  auto services = [ truck, ship ];
  foreach(service; services)
  {
    auto str = service.deliver();
    str.length.writeln(": ", str);
  }
}

Maybe using an abstract class instead of interface or not using auto will solve the problem, but I can't accept the situation! I wonder what makes the interface special?

SDB@79

June 18, 2023
On 6/18/23 07:37, Salih Dincer wrote:

>    auto truck = new Truck;
>    auto ship = new Ship;
>
>    auto services = [ truck, ship ];

The problem is with the deduced type of 'services'. I don't know the mechanism behind it but the common type of 'truck' and 'ship' are deduced to be Object. Apparently, their interfaces don't take part in that decision. I don't know why.

One solution is to help the compiler by casting them to your desired interface:

  auto services = [ cast(ITransport)truck, cast(ITransport)ship ];

Or you can put the casts inside a function that could hide the complexity below:

  import std.algorithm;
  import std.range;
  auto services = [ truck, ship ].map!(s => cast(ITransport)s).array;

Ali

June 18, 2023

On Sunday, 18 June 2023 at 16:58:15 UTC, Ali Çehreli wrote:

>

The problem is with the deduced type of 'services'. I don't know the mechanism behind it but the common type of 'truck' and 'ship' are deduced to be Object. Apparently, their interfaces don't take part in that decision. I don't know why.

This is very interesting because it looks like a bug. Why is there no problem in an abstracted object, but things get confused in the interface (ITransport)?

On Sunday, 18 June 2023 at 16:58:15 UTC, Ali Çehreli wrote:

>

One solution is to help the compiler by casting them to your desired interface:

In fact, there is no need to cast:

interface ITransport
{
  string deliver();
}

//...

void main()
{
  auto truck = new Truck;
  ITransport ship = new Ship;

/* or
  ITransport truck = new Truck;
  auto ship = new Ship;

// or

  ITransport truck = new Truck;
  ITransport ship = new Ship;//*/
}

SDB@78