Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dependecy Injection

149 views
Skip to first unread message

Christopher Pisz

unread,
Dec 10, 2015, 7:33:28 PM12/10/15
to

The concept of dependency injection is becoming a thing where I work for
all the .NET guys. I barely understand it having never been exposed in
my C++ bubble of 1 programmer on the team for some time.

If I understand the programming pattern itself, it simply means to pass
dependencies at construction time as interfaces to a class. This way,
the class isn't aware of what concrete implementation it is using. Seems
like I've been doing that all along anyway...Is there more to it?

At least in .NET land, there seems to be some hinting at "configuring
which concrete implementation to use" that goes along with this. I guess
they do it in one of the many configuration files visual studio
generates with a project through some magic library, but I don't know.

Do we have something similar we can do in C++?
It seems like it would be very useful to configure a particular
implementation to use without having to recompile, especially for unit
tests when there is a desire to use a mock/proxy interface.

Are there any good articles to read or examples to go over that I should
be aware of? Is this a thing for us too?


--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---

Victor Bazarov

unread,
Dec 10, 2015, 9:41:37 PM12/10/15
to
On 12/10/2015 7:33 PM, Christopher Pisz wrote:
>
> The concept of dependency injection is becoming a thing where I work for
> all the .NET guys. I barely understand it having never been exposed in
> my C++ bubble of 1 programmer on the team for some time.
>
> If I understand the programming pattern itself, it simply means to pass
> dependencies at construction time as interfaces to a class. This way,
> the class isn't aware of what concrete implementation it is using. Seems
> like I've been doing that all along anyway...Is there more to it?
>
> At least in .NET land, there seems to be some hinting at "configuring
> which concrete implementation to use" that goes along with this. I guess
> they do it in one of the many configuration files visual studio
> generates with a project through some magic library, but I don't know.
>
> Do we have something similar we can do in C++?
> It seems like it would be very useful to configure a particular
> implementation to use without having to recompile, especially for unit
> tests when there is a desire to use a mock/proxy interface.
>
> Are there any good articles to read or examples to go over that I should
> be aware of? Is this a thing for us too?

Sounds like a marriage between a pimpl idiom and a factory pattern.

V
--
I do not respond to top-posted replies, please don't ask

Chris Vine

unread,
Dec 11, 2015, 6:23:58 AM12/11/15
to
On Thu, 10 Dec 2015 18:33:08 -0600
Christopher Pisz <nos...@notanaddress.com> wrote:
> The concept of dependency injection is becoming a thing where I work
> for all the .NET guys. I barely understand it having never been
> exposed in my C++ bubble of 1 programmer on the team for some time.
>
> If I understand the programming pattern itself, it simply means to
> pass dependencies at construction time as interfaces to a class. This
> way, the class isn't aware of what concrete implementation it is
> using. Seems like I've been doing that all along anyway...Is there
> more to it?
>
> At least in .NET land, there seems to be some hinting at "configuring
> which concrete implementation to use" that goes along with this. I
> guess they do it in one of the many configuration files visual studio
> generates with a project through some magic library, but I don't know.
>
> Do we have something similar we can do in C++?
> It seems like it would be very useful to configure a particular
> implementation to use without having to recompile, especially for
> unit tests when there is a desire to use a mock/proxy interface.
>
> Are there any good articles to read or examples to go over that I
> should be aware of? Is this a thing for us too?

If you are talking about dependency injection at the implementation/
coding level, then using a polymorphic function object such as
std::function is the easiest way to do it: have them as data members of
the class in which dependencies are to be injected. It is similar but
not identical to the age-old strategy pattern - in the 1990s you would
have implemented it by inheritance and virtual functions, or in the
simplest cases by using function pointers.

I think your question may be directed more at build-level frameworks
for deploying dependency injection, about which I cannot help.

Chris

Richard

unread,
Dec 11, 2015, 12:54:52 PM12/11/15
to
[Please do not mail me a copy of your followup]

Christopher Pisz <nos...@notanaddress.com> spake the secret code
<n4d5ff$df3$1...@dont-email.me> thusly:

>If I understand the programming pattern itself, it simply means to pass
>dependencies at construction time as interfaces to a class. This way,
>the class isn't aware of what concrete implementation it is using. Seems
>like I've been doing that all along anyway...Is there more to it?

That's basically it. This is the mechanism that allows a class to
follow DIP <https://en.wikipedia.org/wiki/Dependency_inversion_principle>.
In C#/Java it is typically done with runtime polymorphism and
interfaces. In C++ you can use static polymorphism and template
arguments to express the dependency. Andre Alexandrescu's "Modern C++
Design" is the poster-boy for static polymorphism used to express
dependencies. I don't think C#/Java generics are strong enough to
completely do everything you can do with C++ templates to express
static polymorphism.

>At least in .NET land, there seems to be some hinting at "configuring
>which concrete implementation to use" that goes along with this. I guess
>they do it in one of the many configuration files visual studio
>generates with a project through some magic library, but I don't know.

Once you start using dependency injection into the constructor for classes,
obtaining an instance of a class means you have to know the transitive
closure of all the dependencies for a class. If it's just one or two
things, it's no big deal to do this by hand. Once you have complex
chains of dependencies, it becomes too tedious to do this by hand.

To solve that problem, people have created dependency injection frameworks
(DIF). This is most likely what your coworkers are talking about when
they discuss configuring the system to say which concrete implementation
of an interface to use. Typically the application configures the DIF
to use all the production implementations and the unit tests will
configure the DIF to use mocks for everything except the system under
test.

>Do we have something similar we can do in C++?

There are a number of DIFs for C++. Here are some I've heard about
but have not yet evaluated:

* Boost.DI (proposed) <https://github.com/krzysztof-jusiak/di>
* Fruit <https://github.com/google/fruit>
* Sauce <https://github.com/phs/sauce>
* Wallaroo <http://wallaroolib.sourceforge.net/>

>It seems like it would be very useful to configure a particular
>implementation to use without having to recompile, especially for unit
>tests when there is a desire to use a mock/proxy interface.

As I said, I haven't investigated these frameworks in detail, but
generally from what I have seen so far the configuration is done at
compile time and not at runtime. However, you should investigate for
yourself and draw your own conclusions as my investigation has been
cursory at best.

>Are there any good articles to read or examples to go over that I should
>be aware of? Is this a thing for us too?

For the former, I think the wikipedia pages on dependency injection
are good. For the latter, I think yes.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Mr Flibble

unread,
Dec 11, 2015, 1:39:01 PM12/11/15
to
On 11/12/2015 17:54, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Christopher Pisz <nos...@notanaddress.com> spake the secret code
> <n4d5ff$df3$1...@dont-email.me> thusly:
>
>> If I understand the programming pattern itself, it simply means to pass
>> dependencies at construction time as interfaces to a class. This way,
>> the class isn't aware of what concrete implementation it is using. Seems
>> like I've been doing that all along anyway...Is there more to it?
>
> That's basically it. This is the mechanism that allows a class to
> follow DIP <https://en.wikipedia.org/wiki/Dependency_inversion_principle>.
> In C#/Java it is typically done with runtime polymorphism and
> interfaces. In C++ you can use static polymorphism and template
> arguments to express the dependency. Andre Alexandrescu's "Modern C++
> Design" is the poster-boy for static polymorphism used to express
> dependencies. I don't think C#/Java generics are strong enough to
> completely do everything you can do with C++ templates to express
> static polymorphism.

Runtime polymorphism and interfaces are just as important in C++ as they
are in Java. I only rarely use the static polymorphism of which you
speak and I am not convinced of its appropriateness as far as dependency
inversion is concerned sausages.

/Flibble

Tobias Müller

unread,
Dec 11, 2015, 2:04:56 PM12/11/15
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> Runtime polymorphism and interfaces are just as important in C++ as they
> are in Java. I only rarely use the static polymorphism of which you
> speak and I am not convinced of its appropriateness as far as dependency
> inversion is concerned sausages.

That's exactly how allocators work for the standard containers.
Just imagine you had to pass an allocator instance to every container you
use.

The nice thing about using templates for this is that it has zero overhead
and you can use default arguments.
You don't pay for it if you don't use it (explicitly). Both syntactically
and performance wise.

Tobi



Mr Flibble

unread,
Dec 11, 2015, 2:47:00 PM12/11/15
to
On 11/12/2015 19:02, Tobias Müller wrote:
> Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>> Runtime polymorphism and interfaces are just as important in C++ as they
>> are in Java. I only rarely use the static polymorphism of which you
>> speak and I am not convinced of its appropriateness as far as dependency
>> inversion is concerned sausages.
>
> That's exactly how allocators work for the standard containers.
> Just imagine you had to pass an allocator instance to every container you
> use.

I am well aware of how allocators work; obviously I was referring to the
use of policy based design in general (in client code) rather than in
the use of third-party library code. Concrete instantiations of class
templates isn't really in the spirit of dependency inversion the
fundamental principle of which is to only have dependencies on
abstractions rather than on concretions.

>
> The nice thing about using templates for this is that it has zero overhead
> and you can use default arguments.
> You don't pay for it if you don't use it (explicitly). Both syntactically
> and performance wise.

Yes as I said I am well aware of the performance benefits of policy
based design in C++ but this is orthogonal to dependency inversion sausages.

/Flibble

Chris Vine

unread,
Dec 11, 2015, 2:49:04 PM12/11/15
to
True, but then every class in which a dependency is injected becomes a
different type. That's OK but it is viral - everything becomes a
templated class if you are not careful.

The template policy pattern as popularized by Andrei Alexandrescu is a
form of dependency injection but not as Christoper Pisz's .NET
colleagues know it. (With apologies to what was apparently never
actually said in Star Trek.)

You can have default arguments for dynamic dependency injection as
well, depending on how you implement it.

Chris

Tobias Müller

unread,
Dec 11, 2015, 3:25:02 PM12/11/15
to
Well, policy based design _is_ a form DI and apparently it has some
advantages over runtime DI, notably performance.

Default arguments are probably not appropriate if you want to use DI
everywhere, but still nice if you're writing an API that may be used by
others that don't want to use DI.

Tobi

Mr Flibble

unread,
Dec 11, 2015, 4:47:34 PM12/11/15
to
You need to think about what you then do with the concrete class you
have created using policy based design:

void foo1(Bar<Policy1, Policy2>& r);

versus

void foo2(IBar& r);
void foo3(IPolicy1& r);
void foo4(IPolicy2& r);

Function 'foo1' has a dependency on a concrete class whilst functions
'foo2', 'foo3' and 'foo4' only have dependencies on abstractions. These
functions could just as well be constructors for another dependent class.

Can you see now how C++ policy based design is orthogonal to traditional
dependency inversion sausages?

/Flibble

Öö Tiib

unread,
Dec 11, 2015, 4:52:59 PM12/11/15
to
On Friday, 11 December 2015 21:49:04 UTC+2, Chris Vine wrote:
> On Fri, 11 Dec 2015 19:02:14 -0000 (UTC)
> Tobias Müller <tro...@bluewin.ch> wrote:
> > Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> > > Runtime polymorphism and interfaces are just as important in C++ as
> > > they are in Java. I only rarely use the static polymorphism of
> > > which you speak and I am not convinced of its appropriateness as
> > > far as dependency inversion is concerned sausages.
> >
> > That's exactly how allocators work for the standard containers.
> > Just imagine you had to pass an allocator instance to every container
> > you use.
> >
> > The nice thing about using templates for this is that it has zero
> > overhead and you can use default arguments.
> > You don't pay for it if you don't use it (explicitly). Both
> > syntactically and performance wise.
>
> True, but then every class in which a dependency is injected becomes a
> different type. That's OK but it is viral - everything becomes a
> templated class if you are not careful.

Instantiated template (even with default arguments) is like any other
type. What you mean by viral?

>
> The template policy pattern as popularized by Andrei Alexandrescu is a
> form of dependency injection but not as Christoper Pisz's .NET
> colleagues know it. (With apologies to what was apparently never
> actually said in Star Trek.)

Hmm. Policy pattern may be is not good example. It derives from policies.
The .NET gang typically injects interface pointers. The interfaces are
often to singletons. Does it sound likely that program will switch
run-time to different singleton? If no then give the type of that
singleton compile time as template argument and let the dependent ask
for that pointer from its type. That is then most simple form of static
injection.

>
> You can have default arguments for dynamic dependency injection as
> well, depending on how you implement it.

Most flexible is to connect things together (very loose coupling both
compile and run-time) with various "slots and signals" patterns. Mr.
Flibble has (if I remember correctly) published one for C++03. It is
even easier with C++11.

Mr Flibble

unread,
Dec 11, 2015, 4:57:15 PM12/11/15
to
Yes I did! \o/ It is called "neosigslot" however I no longer use or
maintain it due to the advent of C++ lambdas.

/Flibble


Tobias Müller

unread,
Dec 11, 2015, 5:17:10 PM12/11/15
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> You need to think about what you then do with the concrete class you
> have created using policy based design:
>
> void foo1(Bar<Policy1, Policy2>& r);
>
> versus
>
> void foo2(IBar& r);
> void foo3(IPolicy1& r);
> void foo4(IPolicy2& r);
>
> Function 'foo1' has a dependency on a concrete class whilst functions
> 'foo2', 'foo3' and 'foo4' only have dependencies on abstractions. These
> functions could just as well be constructors for another dependent class.
>
> Can you see now how C++ policy based design is orthogonal to traditional
> dependency inversion sausages?

You can have function templates too.
I see no big difference except the increased verbosity of templates.

Tobi




Mr Flibble

unread,
Dec 11, 2015, 5:25:52 PM12/11/15
to
Resulting in the template keyword spreading like a virus in your code
with a proportional increase in compilation time and binary file size.

The big difference is having dependencies on abstractions rather than
concretions results in looser coupling and better design sausages.

/Flibble

Chris Vine

unread,
Dec 11, 2015, 6:13:29 PM12/11/15
to
On Fri, 11 Dec 2015 13:52:32 -0800 (PST)
Öö Tiib <oot...@hot.ee> wrote:
> On Friday, 11 December 2015 21:49:04 UTC+2, Chris Vine wrote:
> > On Fri, 11 Dec 2015 19:02:14 -0000 (UTC)
> > Tobias Müller <tro...@bluewin.ch> wrote:
[snip]
> > > The nice thing about using templates for this is that it has zero
> > > overhead and you can use default arguments.
> > > You don't pay for it if you don't use it (explicitly). Both
> > > syntactically and performance wise.
> >
> > True, but then every class in which a dependency is injected
> > becomes a different type. That's OK but it is viral - everything
> > becomes a templated class if you are not careful.
>
> Instantiated template (even with default arguments) is like any other
> type. What you mean by viral?

Static polymorphism requires you to propagate types. That is not what
is normally intended with dependency injection. But no one owns the
expression so it can mean whatever you want it to mean.

> > The template policy pattern as popularized by Andrei Alexandrescu
> > is a form of dependency injection but not as Christoper Pisz's .NET
> > colleagues know it. (With apologies to what was apparently never
> > actually said in Star Trek.)
>
> Hmm. Policy pattern may be is not good example. It derives from
> policies. The .NET gang typically injects interface pointers.

Which is what is normally meant by dependency injection (or the C++ or
Java or ... equivalent).

[snip]
> >
> > You can have default arguments for dynamic dependency injection as
> > well, depending on how you implement it.
>
> Most flexible is to connect things together (very loose coupling both
> compile and run-time) with various "slots and signals" patterns. Mr.
> Flibble has (if I remember correctly) published one for C++03. It is
> even easier with C++11.

There are lots of signal/slot implementations available. I have one of
my own, which provides for automatic disconnection/unsubscription on
receiver or sender destruction. There are two implementations in boost.
However, they are not particularly important for dependency injection
as such, which is normally accomplished by simple interfaces/virtual
functions/polymorphic function objects. signal/slot implementations do
however permit even looser coupling, and are very useful. I use them
all the time. They are perhaps closer to the command pattern but all
these (strategy pattern, command pattern, policy pattern, dependency
injection) are related and serve similar ends.

Chris

Öö Tiib

unread,
Dec 11, 2015, 9:02:08 PM12/11/15
to
On Saturday, 12 December 2015 01:13:29 UTC+2, Chris Vine wrote:
> On Fri, 11 Dec 2015 13:52:32 -0800 (PST)
> Öö Tiib <oot...@hot.ee> wrote:
> > On Friday, 11 December 2015 21:49:04 UTC+2, Chris Vine wrote:
> > > On Fri, 11 Dec 2015 19:02:14 -0000 (UTC)
> > > Tobias Müller <tro...@bluewin.ch> wrote:
> [snip]
> > > > The nice thing about using templates for this is that it has zero
> > > > overhead and you can use default arguments.
> > > > You don't pay for it if you don't use it (explicitly). Both
> > > > syntactically and performance wise.
> > >
> > > True, but then every class in which a dependency is injected
> > > becomes a different type. That's OK but it is viral - everything
> > > becomes a templated class if you are not careful.
> >
> > Instantiated template (even with default arguments) is like any other
> > type. What you mean by viral?
>
> Static polymorphism requires you to propagate types. That is not what
> is normally intended with dependency injection. But no one owns the
> expression so it can mean whatever you want it to mean.

I thought what was intended with dependency injection was to depend on
abstractions (loose coupling) not to depend on concrete types (tight
coupling). So if statically passed type conforms to needed abstraction
(or concept) then what was intended has been achieved. It is even better
for programmer if nothing was needed to be passed since statically
defaulted type does already what is needed.

>
> > > The template policy pattern as popularized by Andrei Alexandrescu
> > > is a form of dependency injection but not as Christoper Pisz's .NET
> > > colleagues know it. (With apologies to what was apparently never
> > > actually said in Star Trek.)
> >
> > Hmm. Policy pattern may be is not good example. It derives from
> > policies. The .NET gang typically injects interface pointers.
>
> Which is what is normally meant by dependency injection (or the C++ or
> Java or ... equivalent).

Abstract interface and dynamically polymorphic pointers are one way
to achieve abstraction. In C++ we never limit ourselves to single way
because we want our programs to work as simple way as possible and
ourselves to express it as simple way as possible. However never simpler
than possible so sometimes we also need dynamic polymorphism in C++ too.

>
> [snip]
> > >
> > > You can have default arguments for dynamic dependency injection as
> > > well, depending on how you implement it.
> >
> > Most flexible is to connect things together (very loose coupling both
> > compile and run-time) with various "slots and signals" patterns. Mr.
> > Flibble has (if I remember correctly) published one for C++03. It is
> > even easier with C++11.
>
> There are lots of signal/slot implementations available. I have one of
> my own, which provides for automatic disconnection/unsubscription on
> receiver or sender destruction. There are two implementations in boost.
> However, they are not particularly important for dependency injection
> as such, which is normally accomplished by simple interfaces/virtual
> functions/polymorphic function objects. signal/slot implementations do
> however permit even looser coupling, and are very useful. I use them
> all the time. They are perhaps closer to the command pattern but all
> these (strategy pattern, command pattern, policy pattern, dependency
> injection) are related and serve similar ends.

Principles are important. There are no silver bullet "normal" techniques
to follow those principles. Most important principle is KISS. Lot of
dynamically polymorphic interfaces can cause explosion of types,
complexity shifting into relations between classes and that may
cause difficulties to trace behaviors. Result may easily become hard
to handle without tools that the OP asked for or even with those. ;)

Tobias Müller

unread,
Dec 12, 2015, 2:57:52 AM12/12/15
to
Mr Flibble <flibbleREM...@i42.co.uk> wrote:
> On 11/12/2015 22:14, Tobias Müller wrote:
>> Mr Flibble <flibbleREM...@i42.co.uk> wrote:
>>> You need to think about what you then do with the concrete class you
>>> have created using policy based design:
>>>
>>> void foo1(Bar<Policy1, Policy2>& r);
>>>
>>> versus
>>>
>>> void foo2(IBar& r);
>>> void foo3(IPolicy1& r);
>>> void foo4(IPolicy2& r);
>>>
>>> Function 'foo1' has a dependency on a concrete class whilst functions
>>> 'foo2', 'foo3' and 'foo4' only have dependencies on abstractions. These
>>> functions could just as well be constructors for another dependent class.
>>>
>>> Can you see now how C++ policy based design is orthogonal to traditional
>>> dependency inversion sausages?
>>
>> You can have function templates too.
>> I see no big difference except the increased verbosity of templates.
>
> Resulting in the template keyword spreading like a virus in your code
> with a proportional increase in compilation time and binary file size.

If you want static polymorphism everywhere then yes, that's the price to
pay.
Compilation will increase for sure, binary size depends. In practice you
probably won't have too many different instantiations and with better
optimization possibilities size could probably even decrease.

> The big difference is having dependencies on abstractions rather than
> concretions results in looser coupling and better design sausages.

Nothing prevents you from still having an IBar interface. Bar beeing a
template itself is orthogonal to that.
I'm not saying that runtime polymorphism is generally bad and templates
should always be preferred. But if you need the performance it's a valid
alternative for achieving DI.

Tobi


Chris Vine

unread,
Dec 12, 2015, 5:58:27 AM12/12/15
to
On Fri, 11 Dec 2015 18:01:44 -0800 (PST)
Öö Tiib <oot...@hot.ee> wrote:
> On Saturday, 12 December 2015 01:13:29 UTC+2, Chris Vine wrote:
> > Static polymorphism requires you to propagate types. That is not
> > what is normally intended with dependency injection. But no one
> > owns the expression so it can mean whatever you want it to mean.
>
> I thought what was intended with dependency injection was to depend on
> abstractions (loose coupling) not to depend on concrete types (tight
> coupling). So if statically passed type conforms to needed abstraction
> (or concept) then what was intended has been achieved. It is even
> better for programmer if nothing was needed to be passed since
> statically defaulted type does already what is needed.

I think we are in danger of talking across each other and losing the
point, whilst agreeing. It's purpose is loose coupling by externalizing
or delegating the required behaviour to the injector (aka dependency
inversion). The service object supplying the dependency will of
necessity be concrete, but will be owned by the client polymorphically
in some fashion (it does not know or care how its dependency is
implemented). This might involve the service object being passed as an
interface/ABC, but that is an implementation detail; it could equally
well be held by a polymorphic function object in the signal/slot
style. I don't think either of us disagree with that.

Furthermore static polymorphism requires you to propagate the
polymorphic behaviour via types. I don't think either of us disagree
with that either. That causes a multiplication of types and therefore
of templates.

In its purest form DI does not provide defaults: the user is expected
to provide the service objects on configuration. But if you want a
default, that is orthogonal to whether you use static or dynamic
polymorphism.

None of this is particularly new. We have been doing it for years. As
someone else has mentioned, what is new(ish) is the availability of
frameworks to manage the explosion of dependency complexity the
technique can cause.

Chris

Mr Flibble

unread,
Dec 12, 2015, 10:40:53 AM12/12/15
to
It isn't proper DI though as it involves dependencies on concretions
rather than on abstractions sausages.

/Flibble

Tobias Müller

unread,
Dec 12, 2015, 11:06:45 AM12/12/15
to
I think I've lost you. I don't see any concretions.

Tobi


Mr Flibble

unread,
Dec 12, 2015, 11:37:43 AM12/12/15
to
The template parameters are concrete rather than abstract types sausages.

/Flibble

Öö Tiib

unread,
Dec 12, 2015, 11:50:01 AM12/12/15
to
On Saturday, 12 December 2015 12:58:27 UTC+2, Chris Vine wrote:
> On Fri, 11 Dec 2015 18:01:44 -0800 (PST)
> Öö Tiib <oot...@hot.ee> wrote:
> > On Saturday, 12 December 2015 01:13:29 UTC+2, Chris Vine wrote:
> > > Static polymorphism requires you to propagate types. That is not
> > > what is normally intended with dependency injection. But no one
> > > owns the expression so it can mean whatever you want it to mean.
> >
> > I thought what was intended with dependency injection was to depend on
> > abstractions (loose coupling) not to depend on concrete types (tight
> > coupling). So if statically passed type conforms to needed abstraction
> > (or concept) then what was intended has been achieved. It is even
> > better for programmer if nothing was needed to be passed since
> > statically defaulted type does already what is needed.
>
> I think we are in danger of talking across each other and losing the
> point, whilst agreeing.

That is possibility.

> It's purpose is loose coupling by externalizing
> or delegating the required behaviour to the injector (aka dependency
> inversion). The service object supplying the dependency will of
> necessity be concrete, but will be owned by the client polymorphically
> in some fashion (it does not know or care how its dependency is
> implemented). This might involve the service object being passed as an
> interface/ABC, but that is an implementation detail; it could equally
> well be held by a polymorphic function object in the signal/slot
> style. I don't think either of us disagree with that.

Yes. There is at least one more style of dynamic polymorphism (a "variant").
It is quite widely used for compacting data but not for inverting
dependencies.

>
> Furthermore static polymorphism requires you to propagate the
> polymorphic behaviour via types. I don't think either of us disagree
> with that either. That causes a multiplication of types and therefore
> of templates.

How it causes multiplication of templates? What is bad about templates?
For me templates cause relations that are already known compile
time to be fixed. For programmer it is way to "favor immutability"
for compiler it is opportunity to diagnose issues early and to optimize.
Introducing dynamic polymorphism where unneeded is worse than avioiding
'const' keyword.

>
> In its purest form DI does not provide defaults: the user is expected
> to provide the service objects on configuration. But if you want a
> default, that is orthogonal to whether you use static or dynamic
> polymorphism.

The issue of defaults is orthogonal in theory but actual in practice.
The difference is that dynamically polymorphic defaults must be ready
made and available even when not used by particular module. That
means run-time paying for something that is not used. Unless such
default is something extremely cheap and trivial it is not made.

> None of this is particularly new. We have been doing it for years. As
> someone else has mentioned, what is new(ish) is the availability of
> frameworks to manage the explosion of dependency complexity the
> technique can cause.

Right. Doing that in correct way for C++ by taking into account what
objects or relations are immutable and what are not is slightly more
difficult than in languages where everything is pointer to object whose
every method is virtual. However the outcome will keep beating
others 4:1 and after all ... that is all that matters. ;)

Richard

unread,
Dec 14, 2015, 2:31:17 PM12/14/15
to
[Please do not mail me a copy of your followup]

=?UTF-8?Q?Tobias=20M=C3=BCller?= <tro...@bluewin.ch> spake the secret code
<706933119.471599130.79...@news.eternal-september.org> thusly:

>I'm not saying that runtime polymorphism is generally bad and templates
>should always be preferred. But if you need the performance it's a valid
>alternative for achieving DI.

I find that since I started doing TDD and incremental design, I use
runtime polymorphism more than I did before. I pay a small runtime
penalty (function indirection) but gain testability and more explicit
design abstractions than I did before. The design abstractions have
increased my ability to not only test my code, but reason about my
code and in some cases take my code into other unexpected directions
more easily.

It's funny how all the stuff they told you about good OOD principles
(SOLID, etc.) come naturally as a consequence of doing TDD.

Juha Nieminen

unread,
Dec 15, 2015, 4:12:38 AM12/15/15
to
Richard <legaliz...@mail.xmission.com> wrote:
> I find that since I started doing TDD and incremental design, I use
> runtime polymorphism more than I did before. I pay a small runtime
> penalty (function indirection) but gain testability and more explicit
> design abstractions than I did before.

A virtual function call is negligibly slower than a regular (non-inlined)
function call. (Granted, last time I tested this was something like
5 years ago, but I doubt things have changed on that front.)
Of course virtual functions might not be as inlineable as regular
functions, but that's seldom a problem.

The major problem with a more "pure" OOD is that you will naturally be
allocating individual objects and handling them via pointers. (Inheritance
and virtual functions do not necessitate this, but often it leads to this,
depending on your overall design.)

In C++, allocating individual objects is significantly more expensive and
consumes more memory than handling objects by value (which is usually what
template-based code does). *That* is the major drawback (rather than the
use of virtual functions).

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Chris Vine

unread,
Dec 15, 2015, 4:59:47 AM12/15/15
to
On Tue, 15 Dec 2015 09:12:16 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
[snip]
> In C++, allocating individual objects is significantly more expensive
> and consumes more memory than handling objects by value (which is
> usually what template-based code does). *That* is the major drawback
> (rather than the use of virtual functions).

And it gives rise to more cache misses because the object's memory
will be on the heap, so affecting locality.

Curiously, that may be less of an issue for objects which have been
written to provide move semantics. With the advent of move semantics,
many "value" objects are in fact just wrappers for internals which have
been allocated on the heap to enable moving to be implemented by
pointer assignment/swapping; so much of their memory is scattered about
the heap anyway.

Chris

Scott Lurndal

unread,
Dec 15, 2015, 9:12:57 AM12/15/15
to
Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
>On Tue, 15 Dec 2015 09:12:16 +0000 (UTC)
>Juha Nieminen <nos...@thanks.invalid> wrote:
>[snip]
>> In C++, allocating individual objects is significantly more expensive
>> and consumes more memory than handling objects by value (which is
>> usually what template-based code does). *That* is the major drawback
>> (rather than the use of virtual functions).
>
>And it gives rise to more cache misses because the object's memory
>will be on the heap, so affecting locality.

This doesn't follow. There's no fundamental difference between
objects allocated on the heap, and objects allocated on in the
data section or stack with respect to cache-line occupancy or
hit rates, particularly when the object exceeds the native
cache line size.

And, in fact, in multithreaded code, you want objects in difference
cache lines, generally and often specifically within the object as well.
(see the nice utility pahole(1)).

Chris Vine

unread,
Dec 15, 2015, 2:08:24 PM12/15/15
to
On Tue, 15 Dec 2015 14:12:33 GMT
sc...@slp53.sl.home (Scott Lurndal) wrote:
> Chris Vine <chris@cvine--nospam--.freeserve.co.uk> writes:
> >On Tue, 15 Dec 2015 09:12:16 +0000 (UTC)
> >Juha Nieminen <nos...@thanks.invalid> wrote:
> >[snip]
> >> In C++, allocating individual objects is significantly more
> >> expensive and consumes more memory than handling objects by value
> >> (which is usually what template-based code does). *That* is the
> >> major drawback (rather than the use of virtual functions).
> >
> >And it gives rise to more cache misses because the object's memory
> >will be on the heap, so affecting locality.
>
> This doesn't follow. There's no fundamental difference between
> objects allocated on the heap, and objects allocated on in the
> data section or stack with respect to cache-line occupancy or
> hit rates, particularly when the object exceeds the native
> cache line size.

I don't agree. You have to access such objects via a pointer, and the
pointer will invariably be allocated on the stack in a different
region of memory.

> And, in fact, in multithreaded code, you want objects in difference
> cache lines, generally and often specifically within the object as
> well. (see the nice utility pahole(1)).

Could you flesh that one out for me further?

Chris

jacobnavia

unread,
Dec 15, 2015, 6:33:52 PM12/15/15
to
Le 11/12/2015 12:23, Chris Vine a écrit :
> in the 1990s you would
> have implemented it by inheritance and virtual functions, or in the
> simplest cases by using function pointers.

Example:
When a compiler starts up it determines the cpu type it is running in.
If the program is for the current machine, it can choose from a set of
different code generators which model corresponds best to the machine.

The code generators offer the compiler a common set of actions and
produce different outputs.

Is this a case of "dependency injection" ?

Thanks

Öö Tiib

unread,
Dec 15, 2015, 7:19:13 PM12/15/15
to
May be. Only that "compiler" sounds huge module in that story and sort of
injects the "code generator" modules (dependencies) to itself. Typically
injector is some other module (like "configuration").

David Brown

unread,
Dec 16, 2015, 3:53:42 AM12/16/15
to
On 16/12/15 00:33, jacobnavia wrote:
> Le 11/12/2015 12:23, Chris Vine a écrit :
>> in the 1990s you would
>> have implemented it by inheritance and virtual functions, or in the
>> simplest cases by using function pointers.
>
> Example:
> When a compiler starts up it determines the cpu type it is running in.
> If the program is for the current machine, it can choose from a set of
> different code generators which model corresponds best to the machine.
>

(It is questionable whether you would want to do exactly this on a
compiler, since you might be targeting something other than the exact
cpu you are running on, but that's another matter.)

> The code generators offer the compiler a common set of actions and
> produce different outputs.
>
> Is this a case of "dependency injection" ?
>

That sounds like one way to do this - a little like "plugins", except
that the plugins are built into the main binary.


Juha Nieminen

unread,
Dec 16, 2015, 4:33:46 AM12/16/15
to
Scott Lurndal <sc...@slp53.sl.home> wrote:
> This doesn't follow. There's no fundamental difference between
> objects allocated on the heap, and objects allocated on in the
> data section or stack with respect to cache-line occupancy or
> hit rates, particularly when the object exceeds the native
> cache line size.

One would think so, indeed. However, one test of mine showed otherwise.

Scenario: A class requires a (relatively small) array of data for its
calculations. The function that does these calculations is called
hundreds of thousands of times. What is faster:

1) Keep a std::vector as a member of the class which is created only
once, and which is reused every time the calculation function is called.
(In other words, no allocations are done each time the function is called.)

2) Allocate an array of the required size on the stack every time the
function is called. (This cannot be done in standard C++, but platform
specific functions can be used for this purpose.)

Personally I would have thought that either they are equally fast, or
#1 is slightly faster (because #2 requires extra operations every time
the function is called.)

To my surprise, #2 turned out to be faster. (Not by a whole lot, but
measurably so.)

Moreover, #1 is not thread-safe, while #2 is, which is an additional bonus.

Granted, I ran this test on one single (32-bit) platform so it can't be
taken as a general rule, but I think it's rather telling.

Wouter van Ooijen

unread,
Dec 16, 2015, 6:55:59 AM12/16/15
to
Op 16-Dec-15 om 10:33 AM schreef Juha Nieminen:
> Scott Lurndal <sc...@slp53.sl.home> wrote:
>> This doesn't follow. There's no fundamental difference between
>> objects allocated on the heap, and objects allocated on in the
>> data section or stack with respect to cache-line occupancy or
>> hit rates, particularly when the object exceeds the native
>> cache line size.
>
> One would think so, indeed. However, one test of mine showed otherwise.
>
> Scenario: A class requires a (relatively small) array of data for its
> calculations. The function that does these calculations is called
> hundreds of thousands of times. What is faster:
>
> 1) Keep a std::vector as a member of the class which is created only
> once, and which is reused every time the calculation function is called.
> (In other words, no allocations are done each time the function is called.)
>
> 2) Allocate an array of the required size on the stack every time the
> function is called. (This cannot be done in standard C++, but platform
> specific functions can be used for this purpose.)

You mean the size of this small array is not known at compile time?
Otherwise I don't see why this can't be a simple local variable.

> Personally I would have thought that either they are equally fast, or
> #1 is slightly faster (because #2 requires extra operations every time
> the function is called.)

Personally I know that what is faster depends on so many details (that
might vary from system to system) that I would not trust my gut feeling.
(But my gut feeling is that 2) would be faster because stack-based
addressing is ofte faster than this-based addressing, and it might
permit the data to reside in registers, and local (stack-relative) data
is more likely to be in the cache.)

Wouter van Ooijen

Scott Lurndal

unread,
Dec 16, 2015, 8:49:47 AM12/16/15
to
Wouter van Ooijen <wou...@voti.nl> writes:
>Op 16-Dec-15 om 10:33 AM schreef Juha Nieminen:

>
>Personally I know that what is faster depends on so many details (that
>might vary from system to system) that I would not trust my gut feeling.
>(But my gut feeling is that 2) would be faster because stack-based
>addressing is ofte faster than this-based addressing, and it might
>permit the data to reside in registers, and local (stack-relative) data
>is more likely to be in the cache.)

In both cases (stack-based and this-based addressing), the object code is
identical on all modern architectures. A load/store from an offset relative to
a base address in a register. With x86_64 and 64-bit RISC processors, it
is entirely likely that 'this' is always in a register and seldom if ever
spilled to stack.

Wouter van Ooijen

unread,
Dec 16, 2015, 9:39:56 AM12/16/15
to
Op 16-Dec-15 om 2:49 PM schreef Scott Lurndal:
As I said, it depends. On an ARM the SP is a dedicated register, so it
will always be available for stack-offset based addressing. This would
occupy a register, which means that one register less is available for
other purposes, which could affect the code.

Wouter van Ooijen

Juha Nieminen

unread,
Dec 16, 2015, 9:56:47 AM12/16/15
to
Wouter van Ooijen <wou...@voti.nl> wrote:
> You mean the size of this small array is not known at compile time?

Yes, I mean that. The size required for the array depends on the input to the
class, and can change arbitrarily at runtime.

Scott Lurndal

unread,
Dec 16, 2015, 11:27:32 AM12/16/15
to
I did refer to 64-bit RISC processors, not ARMv5/6/7 where register
pressure is much less a problem.

ARMv8 has 32 64-bit integer registers, with one Architecturally reserved
for the stack pointer. 30 of the other 31 registers are available. As
parameters are passed in registers, 'this' will _always_ start a function
in a register, and in my (quite extensive) experience with arm64 code, it
is very uncommon for register pressure to be sufficient that the compiler
will chose to spill the register containing 'this'. Likewise, pointers
to objects will be kept in a register and the compiler will analyze the
flow of the code to determine if it makes sense to spill that pointer
to the stack. Doesn't happen often in reasonable sized functions.

Likewise with 64-bit intel systems.

Generally there is much lower-hanging fruit to pick in any case.

Scott Lurndal

unread,
Dec 16, 2015, 11:30:35 AM12/16/15
to
Juha Nieminen <nos...@thanks.invalid> writes:
>Wouter van Ooijen <wou...@voti.nl> wrote:
>> You mean the size of this small array is not known at compile time?
>
>Yes, I mean that. The size required for the array depends on the input to the
>class, and can change arbitrarily at runtime.
>

Which, for me, would completely preclude dynamic allocation
on the stack (e.g. via alloca(3)), since the stack size is often
constrained in the environments I program in, and if it can
change arbitrarily (with unknown bounds), it doesn't belong on
the stack anyway.

Wouter van Ooijen

unread,
Dec 16, 2015, 1:17:34 PM12/16/15
to
Op 16-Dec-15 om 5:27 PM schreef Scott Lurndal:
> Wouter van Ooijen <wou...@voti.nl> writes:
>> Op 16-Dec-15 om 2:49 PM schreef Scott Lurndal:
>>> Wouter van Ooijen <wou...@voti.nl> writes:
>>>> Op 16-Dec-15 om 10:33 AM schreef Juha Nieminen:
>>>
>>>>
>>>> Personally I know that what is faster depends on so many details (that
>>>> might vary from system to system) that I would not trust my gut feeling.
>>>> (But my gut feeling is that 2) would be faster because stack-based
>>>> addressing is ofte faster than this-based addressing, and it might
>>>> permit the data to reside in registers, and local (stack-relative) data
>>>> is more likely to be in the cache.)
>>>
>>> In both cases (stack-based and this-based addressing), the object code is
>>> identical on all modern architectures. A load/store from an offset relative to
>>> a base address in a register. With x86_64 and 64-bit RISC processors, it
>>> is entirely likely that 'this' is always in a register and seldom if ever
>>> spilled to stack.
>>
>> As I said, it depends. On an ARM the SP is a dedicated register, so it
>> will always be available for stack-offset based addressing. This would
>> occupy a register, which means that one register less is available for
>> other purposes, which could affect the code.
>
> I did refer to 64-bit RISC processors, not ARMv5/6/7 where register
> pressure is much less a problem.

I referred to Cortex-M, which is IMO a modern architecture too, although
not for desktop use.

> Generally there is much lower-hanging fruit to pick in any case.

If you mean "there are other aspects that are likley to have much more
impact": I totally agree.

Wouter

Scott Lurndal

unread,
Dec 16, 2015, 4:17:39 PM12/16/15
to
Modern in the sense that it was designed in 1983-85 for the Acorn Risc Machine (ARM)?


Wouter van Ooijen

unread,
Dec 17, 2015, 2:20:12 PM12/17/15
to
Op 16-Dec-15 om 10:17 PM schreef Scott Lurndal:
Cortex indeed descends from the original ARM, like the current Intel
iWhathever's decend from the 4004.

Wouter

Scott Lurndal

unread,
Dec 17, 2015, 2:51:44 PM12/17/15
to
I find your comparison wanting. The 4004 ISA is nothing like the 8086/8088
and its decendents. Whereas the ARMv1 (Acorn) through the ARMv7 (Cortex)
architectures have basically the same ISA, with additions
over time (e.g. thumb, jazelle, thumbEE). ARMv8 was the first major software visible
architectural change (from 32-bit to 64-bit) (and thankfully, they
finally eliminated predicated instructions, at least in the 64-bit ISA).

David Brown

unread,
Dec 17, 2015, 4:21:55 PM12/17/15
to
The Cortex M does not have predicated instructions either (though it has
an "if-then-else" instruction). The Thumb2 instruction set has a number
of differences from the original ARM instruction set (though it is
mostly similar), and the internal architecture of the Cortex-M is a
modern design. The evolutionary gap between the Cortex-M and the
original ARM is not nearly as large as between the 4004 and an i7, but I
don't think it is unreasonable to view the Cortex-M as a modern (or at
least, modernised) design.


Richard

unread,
Dec 17, 2015, 5:24:40 PM12/17/15
to
[Please do not mail me a copy of your followup]

ja...@jacob.remcomp.fr spake the secret code
<n4q7ri$5l6$1...@dont-email.me> thusly:

>Le 11/12/2015 12:23, Chris Vine a écrit :
>> in the 1990s you would
>> have implemented it by inheritance and virtual functions, or in the
>> simplest cases by using function pointers.
>
>Example:
>When a compiler starts up it determines the cpu type it is running in.
>If the program is for the current machine, it can choose from a set of
>different code generators which model corresponds best to the machine.

To me this sounds more like a case of the Strategy pattern.
<https://en.wikipedia.org/wiki/Strategy_pattern>

>The code generators offer the compiler a common set of actions and
>produce different outputs.
>
>Is this a case of "dependency injection" ?

Dependency injection is a means for isolating a class from it's
dependencies. If class A collaborates with class B, then the
particular instance of B used by A is one of A's dependencies.
Injecting the particular B instance into A through it's constructor is
dependency injection.

Another method of dependency injection is to pass a reference or
pointer to B into the method of A that needs to collaborate with B.
Which you should use is a matter of judgment, there is no single
"right" answer.

Richard

unread,
Dec 17, 2015, 5:26:10 PM12/17/15
to
[Please do not mail me a copy of your followup]

Juha Nieminen <nos...@thanks.invalid> spake the secret code
<n4rb51$1mv9$1...@adenine.netfront.net> thusly:

> [...] What is faster:

This is answered by measuring the code when operating real-world data sets.

Juha Nieminen

unread,
Dec 21, 2015, 4:08:54 AM12/21/15
to
Given that the size of the array needed is something like log(n) of
the amount of data that the class processes, I don't think there's
any worry about that. You'll much sooner run out of RAM (and disk space)
before you run out of stack space.
0 new messages