www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - class Object with Dependency Injection

reply Salih Dincer <salihdb hotmail.com> writes:
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..

```d
//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
Jun 18 2023
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Jun 18 2023
parent Salih Dincer <salihdb hotmail.com> writes:
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: ```d 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
Jun 18 2023