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

Concrete classes considered harmful

189 views
Skip to first unread message

Mr Flibble

unread,
Jul 10, 2015, 11:05:16 PM7/10/15
to
Dependencies on concrete classes are considered harmful and should be
replaced with dependencies on abstractions. A class should not new its
member objects for example but rather should use a factory passed into
its constructor.

SOLID priniciples can be at odds with performance though as far as C++
is concerned as certain optimizations cannot be peformed if all function
calls are via abstract interfaces (virtual functions). Any thoughts on
how to square this circle?

/Flibble

Ian Collins

unread,
Jul 10, 2015, 11:09:25 PM7/10/15
to
Mr Flibble wrote:
> Dependencies on concrete classes are considered harmful and should be
> replaced with dependencies on abstractions.

By whom?

> A class should not new its
> member objects for example but rather should use a factory passed into
> its constructor.

Why?

--
Ian Collins

Alf P. Steinbach

unread,
Jul 10, 2015, 11:11:51 PM7/10/15
to
You can do a cost/benefit analysis. Is the added developer time and
runtime overhead worth whatever the unmentioned benefit is, for you? If
so, use the guideline/principle, but if not, ditch it.

A good heuristic, if the benefits are unclear, can be to look at what
others do and think, i.e. common practice.

Which is, that practically nobody uses the above principle. ;-)


Cheers & hth.,

- Alf

--
Using Thunderbird as Usenet client, Eternal September as NNTP server.
Message has been deleted

Alf P. Steinbach

unread,
Jul 11, 2015, 12:07:29 AM7/11/15
to
On 11-Jul-15 5:25 AM, Stefan Ram wrote:
> Mr Flibble <fli...@i42.co.uk> writes:
>> Dependencies on concrete classes are considered harmful and should be
>> replaced with dependencies on abstractions.
>
> In C++, the term »concrete class« already has a different
> meaning than assumed above. At least according to Bjarne
> Stroustrup who explained:
>
> »The basic idea of concrete classes is that (...) In
> many important cases, such as a vector, that representation
> is only one or more pointers to more data stored elsewhere,
> but it is present in each object of a concrete class.«
>
> So, if I understand Bjarne Stroustrup right, ::std::vector is /not/
> a concrete class, because its representation is stored outside of
> its instances. But according to your terminology, it would be a
> »concrete class«, because it implements all it's member functions.

On the contrary, Bjarne uses std::vector as an example of a concrete class.

Quoting the relevant passage, indirectly from <url:
http://programmers.stackexchange.com/questions/221437/concrete-types-as-described-by-stroustrup-c-programming-language-4th-ed>:

> The basic idea of concrete classes is that they behave “just like built-in
> types.” For example, a complex number type and an infinite-precision integer are
> much like built-in int, except of course that they have their own semantics and
> sets of operations. Similarly, a vector and a string are much like built-in
> arrays, except that they are better behaved (§ 4.2, § 4.3.2, § 4.4.1).
>
> The defining characteristic of a concrete type is that its representation is
> part of its definition. In many important cases, such as a vector, that
> representation is only one or more pointers to more data stored elsewhere, but
> it is present in each object of a concrete class.... In particular, it allows us
> to
>
> • place objects of concrete types on the stack, in statically allocated memory,
> and in other objects (§ 6.4.2);
>
> • refer to objects directly (and not just through pointers or references);
>
> • initialize objects immediately and completely (e.g., using constructors;
> § 2.3.2); and
>
> • copy objects (§ 3.3).
>
> Stroustrup, Bjarne (2013-07-10). The C++ Programming Language (4th Edition)
> (Section 16.3 Concrete Classes; Kindle Locations 2373-2386). Pearson Education.
> Kindle Edition.

Note: I find the discussion over on SO perplexing. But then much is
perplexing there. It's the #1 Herb Schildt area of the net, AFAIK.

Paavo Helde

unread,
Jul 11, 2015, 3:06:13 AM7/11/15
to
Mr Flibble <fli...@i42.co.uk> wrote in news:y42dnfPZC9VKGj3InZ2dnUU78Q-
dn...@giganews.com:

> Dependencies on concrete classes are considered harmful and should be
> replaced with dependencies on abstractions.

Over-engineering is also considered harmful.

> A class should not new its
> member objects for example but rather should use a factory passed into
> its constructor.

Any C++ class with no public data is already at pretty high abstraction
level. Virtual interfaces are just one of many abstraction methods which
can be used in C++.

> SOLID priniciples can be at odds with performance though as far as C++
> is concerned as certain optimizations cannot be peformed if all function
> calls are via abstract interfaces (virtual functions). Any thoughts on
> how to square this circle?

Common sense?

JiiPee

unread,
Jul 11, 2015, 3:28:51 AM7/11/15
to
On 11/07/2015 08:06, Paavo Helde wrote:
> Mr Flibble <fli...@i42.co.uk> wrote in news:y42dnfPZC9VKGj3InZ2dnUU78Q-
> dn...@giganews.com:
>
>> Dependencies on concrete classes are considered harmful and should be
>> replaced with dependencies on abstractions.
> Over-engineering is also considered harmful.

agree. As Brarne puts ""simple things should be done in a simple way"

>
>
>> SOLID priniciples can be at odds with performance though as far as C++
>> is concerned as certain optimizations cannot be peformed if all function
>> calls are via abstract interfaces (virtual functions). Any thoughts on
>> how to square this circle?
> Common sense?

As somebody already said, if the speed benefit is not esssential (after
proper testing) then making things complicated is not worth of it.


Reinhardt Behm

unread,
Jul 11, 2015, 3:48:35 AM7/11/15
to
Another quote from from Edsger W. Dijkstra:
"Simplicity is prerequisite for reliability."

--
Reinhardt

Message has been deleted

Mr Flibble

unread,
Jul 11, 2015, 12:49:34 PM7/11/15
to
On 11/07/2015 04:09, Ian Collins wrote:
> Mr Flibble wrote:
>> Dependencies on concrete classes are considered harmful and should be
>> replaced with dependencies on abstractions.
>
> By whom?

Go learn the SOLID principles; anyone who does not know and/or follow
SOLID is not a very good engineer IMO.

>
>> A class should not new its
>> member objects for example but rather should use a factory passed into
>> its constructor.
>
> Why?

Good luck unit testing a class that has lots of dependencies on concretions.

/Flibble


Message has been deleted

Mr Flibble

unread,
Jul 11, 2015, 1:11:05 PM7/11/15
to
On 11/07/2015 17:55, Stefan Ram wrote:
> Mr Flibble <fli...@i42.co.uk> writes:
>> On 11/07/2015 04:09, Ian Collins wrote:
>>> Mr Flibble wrote:
>>>> Dependencies on concrete classes are considered harmful and should be
>>>> replaced with dependencies on abstractions.
>>> By whom?
>> Go learn the SOLID principles; anyone who does not know and/or follow
>> SOLID is not a very good engineer IMO.
>
> I still remember reading Robert C. Martin ("Uncle Bob"), who
> invented SOLID, in »comp.object«. That group »comp.object«
> would possibly be a fine place for your topic, but today it
> is deserted.
>
> Usually the Java crowd, especially the Java EE crowd, pays
> more attention to such general OO topics than the C++ crowd.
> C++ is more multi-paradigm and is often using generic
> programming instead of OO.

Yes C++ is multi-paradigm and yes you should be using generic
programming just as often as OOP, however OOP is no less important than
any other C++ paradigm. *When* performing OOP with C++, SOLID should be
followed. My post was intended to solicit opinions on if/when we should
ignore SOLID principles for the sake of performance. Should 90% of your
OO code follow SOLID as only 10% of your code is critical path as far as
performance is concerned?

/Flibble


Martin Shobe

unread,
Jul 11, 2015, 2:33:36 PM7/11/15
to
I would expect that you'd see much more than 90% if 10% of your code was
performance critical and you used SOLID everywhere performance concerns
didn't indicate otherwise.

But to answer your original question, you'd cease using SOLID to gain
performance only when your measurements indicate that you can gain the
performance you need to meet your projects requirements.

Whether or not you should be using SOLID is another can of worms.

Martin Shobe

woodb...@gmail.com

unread,
Jul 11, 2015, 5:12:48 PM7/11/15
to
> > * place objects of concrete types on the stack, in statically allocated memory,
> > and in other objects (§ 6.4.2);
> >
> > * refer to objects directly (and not just through pointers or references);
> >
> > * initialize objects immediately and completely (e.g., using constructors;
> > § 2.3.2); and
> >
> > * copy objects (§ 3.3).
> >
> > Stroustrup, Bjarne (2013-07-10). The C++ Programming Language (4th Edition)
> > (Section 16.3 Concrete Classes; Kindle Locations 2373-2386). Pearson Education.
> > Kindle Edition.
>
> Note: I find the discussion over on SO perplexing. But then much is
> perplexing there. It's the #1 Herb Schildt area of the net, AFAIK.
>

It's kind of a site for control freaks. The site waxed for
years and now I think it will be waning.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Ian Collins

unread,
Jul 11, 2015, 5:17:17 PM7/11/15
to
Mr Flibble wrote:
> On 11/07/2015 04:09, Ian Collins wrote:
>> Mr Flibble wrote:
>>> Dependencies on concrete classes are considered harmful and should be
>>> replaced with dependencies on abstractions.
>>
>> By whom?
>
> Go learn the SOLID principles; anyone who does not know and/or follow
> SOLID is not a very good engineer IMO.

Well I certainly know about them and consider them guidelines, not hard
and fast rules. If you follow any set of guidelines as if they were
gospel, you'll end up like the religious zealots who pop up here from
time to time.

Oh by the way, I also use int in my code, so I guess by your standards
I'm already not a very good engineer.

>>> A class should not new its
>>> member objects for example but rather should use a factory passed into
>>> its constructor.
>>
>> Why?
>
> Good luck unit testing a class that has lots of dependencies on concretions.

I've been unit testing everything I write for over a decade now and I've
yet to encounter problems with non-abstract base classes. Go and and
learn about mock objects.

--
Ian Collins

Chris Vine

unread,
Jul 11, 2015, 7:17:18 PM7/11/15
to
Yes, use generics.

However, the "D" part of SOLID is contentious and of itself too
abstract to be provable: another product of the OOP fad of the 1990s.
The C++ standard library is stuffed fully of concrete classes (for good
reason), many or most of them templated. Small one purpose concrete
classes giving effect to the single responsibility principle, but using
generics where necessary, can form an excellent basis for composition.

Edsger Dijkstra (needs no introduction): "Object-oriented programming is
an exceptionally bad idea which could only have originated in
California."

Rob Pike (one of the originators of Go and of UTF-8 and a member of
the unix team): "Object-oriented design is the roman numerals of
computing."

Chris

Mr Flibble

unread,
Jul 11, 2015, 8:51:25 PM7/11/15
to
On 11/07/2015 22:17, Ian Collins wrote:
> Mr Flibble wrote:
>> On 11/07/2015 04:09, Ian Collins wrote:
>>> Mr Flibble wrote:
>>>> Dependencies on concrete classes are considered harmful and should be
>>>> replaced with dependencies on abstractions.
>>>
>>> By whom?
>>
>> Go learn the SOLID principles; anyone who does not know and/or follow
>> SOLID is not a very good engineer IMO.
>
> Well I certainly know about them and consider them guidelines, not hard
> and fast rules. If you follow any set of guidelines as if they were
> gospel, you'll end up like the religious zealots who pop up here from
> time to time.
>
> Oh by the way, I also use int in my code, so I guess by your standards
> I'm already not a very good engineer.

If you lazily use 'int' all over your code without actually thinking if
it is appropriate then that does indeed make you a not very good
engineer. Perhaps you should be using Java rather than C++.

>
>>>> A class should not new its
>>>> member objects for example but rather should use a factory passed into
>>>> its constructor.
>>>
>>> Why?
>>
>> Good luck unit testing a class that has lots of dependencies on
>> concretions.
>
> I've been unit testing everything I write for over a decade now and I've
> yet to encounter problems with non-abstract base classes. Go and and
> learn about mock objects.

It is virtually impossible to unit test a class that has dependencies on
lots of other concrete classes that themselves require unit testing. I
know all about mock objects thanks and that is the point: it is easy to
make a class being unit tested use a mock object if that mock object
complies to an abstract interface and is created by a mock object factory.

/Flibble

Mr Flibble

unread,
Jul 11, 2015, 8:52:21 PM7/11/15
to
What utter idiocy.

>
> Chris

/Flibble

Ian Collins

unread,
Jul 11, 2015, 9:20:23 PM7/11/15
to
Mr Flibble wrote:
> On 11/07/2015 22:17, Ian Collins wrote:
>> Mr Flibble wrote:
>>> On 11/07/2015 04:09, Ian Collins wrote:
>>>> Mr Flibble wrote:
>>>>> Dependencies on concrete classes are considered harmful and should be
>>>>> replaced with dependencies on abstractions.
>>>>
>>>> By whom?
>>>
>>> Go learn the SOLID principles; anyone who does not know and/or follow
>>> SOLID is not a very good engineer IMO.
>>
>> Well I certainly know about them and consider them guidelines, not hard
>> and fast rules. If you follow any set of guidelines as if they were
>> gospel, you'll end up like the religious zealots who pop up here from
>> time to time.
>>
>> Oh by the way, I also use int in my code, so I guess by your standards
>> I'm already not a very good engineer.
>
> If you lazily use 'int' all over your code....

Which I don't.

>>>>> A class should not new its
>>>>> member objects for example but rather should use a factory passed into
>>>>> its constructor.
>>>>
>>>> Why?
>>>
>>> Good luck unit testing a class that has lots of dependencies on
>>> concretions.
>>
>> I've been unit testing everything I write for over a decade now and I've
>> yet to encounter problems with non-abstract base classes. Go and and
>> learn about mock objects.
>
> It is virtually impossible to unit test a class that has dependencies on
> lots of other concrete classes that themselves require unit testing.

The code bases I work on have a mix of abstract and concrete classes.
All are TDD projects, so there is effectively 100% test coverage. How
would you define "lots of other concrete classes"? most of ours depend
on very few others. Having too many dependencies is more of a design
issue than having dependencies on concrete classes.

> I
> know all about mock objects thanks and that is the point: it is easy to
> make a class being unit tested use a mock object if that mock object
> complies to an abstract interface and is created by a mock object factory.

Unless the the class has non-trivial inline member functions, whether it
is abstract or not has little bearing on mocking. In this instance,
using the Pimpl idiom is just as effective as abstract base classes.

Given the three options of abstract, concrete without non-trivial inline
member functions or Pimpl classes all are equally simple to mock.

I have nothing against using abstract base classes, but in the small
embedded world where much of my code is used the cost is often (rightly
or wrongly) considered to high a price to pay.

--
Ian Collins

Mr Flibble

unread,
Jul 11, 2015, 9:32:52 PM7/11/15
to
You are obviously doing it wrong (TM). Unit testing and TDD are not
synonyms and TDD itself is actually considered harmful: you can *not*
design software to a high standard by designing things downwards from
tests. A good design involves first defining an architecture along with
abstractions (interfaces) and object interactions all of which should be
driven by system requirements and not by passing brain-dead isolated tests.

/Flibble

Ian Collins

unread,
Jul 11, 2015, 11:48:36 PM7/11/15
to
Mr Flibble wrote:
> On 12/07/2015 02:20, Ian Collins wrote:
>>
>> The code bases I work on have a mix of abstract and concrete classes.
>> All are TDD projects, so there is effectively 100% test coverage. How
>> would you define "lots of other concrete classes"? most of ours depend
>> on very few others. Having too many dependencies is more of a design
>> issue than having dependencies on concrete classes.
>
> You are obviously doing it wrong (TM).

My clients and bank manager would argue otherwise.

--
Ian Collins

Ian Collins

unread,
Jul 12, 2015, 12:15:06 AM7/12/15
to
Mr Flibble wrote:
>
> You are obviously doing it wrong (TM). Unit testing and TDD are not
> synonyms and TDD itself is actually considered harmful:

So is crossing the road.. It appears that you consider everything you
don't do (whether you understand it or not) to be harmful.

> you can *not*
> design software to a high standard by designing things downwards from
> tests. A good design involves first defining an architecture along with
> abstractions (interfaces) and object interactions all of which should be
> driven by system requirements and not by passing brain-dead isolated tests.

I agree. No one who uses TDD writes brain-dead isolated tests.

--
Ian Collins

Juha Nieminen

unread,
Jul 12, 2015, 7:33:18 AM7/12/15
to
Mr Flibble <fli...@i42.co.uk> wrote:
>>> A class should not new its
>>> member objects for example but rather should use a factory passed into
>>> its constructor.
>>
>> Why?
>
> Good luck unit testing a class that has lots of dependencies on concretions.

So we should just forget what makes C++ so efficient as it is, and just
turn it into a less-efficient Java/C# variant?

Unit testing is ok, but I'm not happy if unit testing means that my
program needs to be 10 times slower than it could be, even when making
the final release build.

(And no, I'm not even exaggerating with that "10 times slower".)

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

Chris Vine

unread,
Jul 12, 2015, 8:46:41 AM7/12/15
to
On Sun, 12 Jul 2015 11:32:53 +0000 (UTC)
Juha Nieminen <nos...@thanks.invalid> wrote:
> Mr Flibble <fli...@i42.co.uk> wrote:
> >>> A class should not new its
> >>> member objects for example but rather should use a factory passed
> >>> into its constructor.
> >>
> >> Why?
> >
> > Good luck unit testing a class that has lots of dependencies on
> > concretions.
>
> So we should just forget what makes C++ so efficient as it is, and
> just turn it into a less-efficient Java/C# variant?
>
> Unit testing is ok, but I'm not happy if unit testing means that my
> program needs to be 10 times slower than it could be, even when making
> the final release build.
>
> (And no, I'm not even exaggerating with that "10 times slower".)

It's mocking rather than unit testing as such where the issue tends to
arise. However, there is no need to adopt complicated abstract
interfaces on the Flibble model just to provide dependency injection for
mocking purposes. Where mocking is the best way of unit testing a
particular implementation, concrete classes are just as capable of
being designed for dependency injection. (Admittedly, the frameworks
for this are not as well developed.)

Possibly it is Flibble's title for this thread ("concrete classes
considered harmful") which is part of the problem, because on the face
of it, as a statement it is ridiculous. You then get to the issue of
what he means by "dependencies on concrete classes". So far as his
principle forbids composing types using concrete types, then he is also
(in my view) way off the mark.

Chris

Mr Flibble

unread,
Jul 12, 2015, 8:47:01 AM7/12/15
to
Clients are oblivious to whether or not you have solved their problem
the correct way; if it all barely hangs together and just meets their
requirements they are usually happy even if the actual implementation is
shite.

Egregious have-a-go cowboy developers can often make money out of poor
quality work; doesn't make it right.

/Flibble


Mr Flibble

unread,
Jul 12, 2015, 8:54:55 AM7/12/15
to
On 12/07/2015 13:46, Chris Vine wrote:
> On Sun, 12 Jul 2015 11:32:53 +0000 (UTC)
> Juha Nieminen <nos...@thanks.invalid> wrote:
>> Mr Flibble <fli...@i42.co.uk> wrote:
>>>>> A class should not new its
>>>>> member objects for example but rather should use a factory passed
>>>>> into its constructor.
>>>>
>>>> Why?
>>>
>>> Good luck unit testing a class that has lots of dependencies on
>>> concretions.
>>
>> So we should just forget what makes C++ so efficient as it is, and
>> just turn it into a less-efficient Java/C# variant?
>>
>> Unit testing is ok, but I'm not happy if unit testing means that my
>> program needs to be 10 times slower than it could be, even when making
>> the final release build.
>>
>> (And no, I'm not even exaggerating with that "10 times slower".)
>
> It's mocking rather than unit testing as such where the issue tends to
> arise. However, there is no need to adopt complicated abstract
> interfaces on the Flibble model just to provide dependency injection for

Abstract interfaces are not "complicated"; abstract interfaces are
actually simpler than the concrete classes that implement them; abstract
interfaces allow loose coupling; abstract interfaces are a win-win as
far as designing, implementing and maintaining software is concerned.
The only issue with abstract interfaces is performance when using them
with C++ (hence the reason for this thread).

/Flibble

Chris Vine

unread,
Jul 12, 2015, 9:21:16 AM7/12/15
to
Abstract interfaces have their uses, but often best hidden as an
implementation detail behind a concrete class. std::function is a good
example of this, which is a templated concrete type which happens to use
an internal helper type with a virtual function and inheritance for type
erasure purposes. (In consequence, the std::function concrete type
enables you to implement the strategy pattern or the observer pattern
without having you write your own abstract interfaces, so improving
design and reducing coupling.)

Mr Flibble

unread,
Jul 12, 2015, 9:40:49 AM7/12/15
to
What utter garbage mate. We are talking about dependencies between
classes and dependencies on concrete classes result in tight coupling
rather than the lose coupling that abstract interfaces provide. Yes you
can use type erasure via std::function to achieve loose coupling however
if multiple methods are involved than an interface can and usually is
both more convenient and makes more sense from a design point of view:
it makes your dependencies both named and explicit. You are suffering
from the design over-genericization syndrome typical of C++ programmers.

I suspect you are trolling though; do it again and you will be blocked.

/Flibble

David Harmon

unread,
Jul 12, 2015, 9:58:20 AM7/12/15
to
On Sat, 11 Jul 2015 04:04:55 +0100 in comp.lang.c++, Mr Flibble
<fli...@i42.co.uk> wrote,
>Dependencies on concrete classes are considered harmful and should be
>replaced with dependencies on abstractions. A class should not new its
>member objects for example but rather should use a factory passed into
>its constructor.

No. A better guideline is avoid using 'new' in application-level code.
Use 'new' only where doing so solves some problem, preferably inside a
library class whose whole purpose is managing allocated memory,
preferably using RIAA. Overuse of 'new' is a symptom of Java brain
damage.


Chris Vine

unread,
Jul 12, 2015, 9:59:27 AM7/12/15
to
On Sun, 12 Jul 2015 14:40:35 +0100
For someone who began a post with the title "concrete classes
considered harmful", which is about as troll-full as you can get, and
that I have fully explained my views, you have quite a nerve. The fact
is that you have a one-track mind and you get locked into your own point
of view to the exclusion of all others. The same was apparent in your
"Avoid 'int', 'long' and 'short'..." and "Avoid 'int' and associates"
postings, an issue that required you to start two separate threads on
the same point.

Anyway, be my guest.

Chris

Mr Flibble

unread,
Jul 12, 2015, 10:45:32 AM7/12/15
to
What utter nonsense. Perhaps you are confusing new with delete? Using
new is fine but using delete isn't as you should be wrapping objects you
new in a smart pointer.

A good example of when you should use new (or in this case make_unique)
is when you want to populate:

std::vector<std::unique_ptr<IShape>>

where IShape is an interface abstracting shapes.

/Flibble

Message has been deleted

Mr Flibble

unread,
Jul 12, 2015, 11:30:50 AM7/12/15
to
On 12/07/2015 16:28, Stefan Ram wrote:
> Mr Flibble <fli...@i42.co.uk> writes:
>> Dependencies on concrete classes are considered harmful and should be
>> replaced with dependencies on abstractions.
>
> We already have this in C++ when appropriate. For example,
>
> ::std::sort( ::std::begin( a ), ::std::end( a ), ::std::greater<int>() );
>
> . »sort« does not depend on a concrete class, but on the
> interface (well, template parameter) (well, »concept«)
> »Compare«, which is the type of the comparison argument,
> which is »injected« by the caller.

Typing '::std' instead of 'std' is a bit silly.

/Flibble


woodb...@gmail.com

unread,
Jul 12, 2015, 2:23:36 PM7/12/15
to
On Sunday, July 12, 2015 at 10:30:50 AM UTC-5, Mr Flibble wrote:
>
> Typing '::std' instead of 'std' is a bit silly.
>

I use ::std for clarity.


Brian
Ebenezer Enterprises
http://webEbenezer.net
Message has been deleted
Message has been deleted

Alf P. Steinbach

unread,
Jul 12, 2015, 3:37:27 PM7/12/15
to
On 12-Jul-15 8:23 PM, woodb...@gmail.com wrote:
> On Sunday, July 12, 2015 at 10:30:50 AM UTC-5, Mr Flibble wrote:
>>
>> Typing '::std' instead of 'std' is a bit silly.
>>
>
> I use ::std for clarity.

I've used global namespace qualification in macros, for correctness,
because you never know where a macro can be used. And I've used global
namespace qualification for clarity for identifiers from the Windows
API. However, I don't think "::std::x" is more clear than "std::x"; on
the contrary, those little "::" are more like noise to my eyes.


Cheers,

- Alf

--
Using Thunderbird as Usenet client, Eternal September as NNTP server.

woodb...@gmail.com

unread,
Jul 12, 2015, 5:34:59 PM7/12/15
to
On Sunday, July 12, 2015 at 2:37:27 PM UTC-5, Alf P. Steinbach wrote:
> On 12-Jul-15 8:23 PM, woodb...@gmail.com wrote:
> > On Sunday, July 12, 2015 at 10:30:50 AM UTC-5, Mr Flibble wrote:
> >>
> >> Typing '::std' instead of 'std' is a bit silly.
> >>
> >
> > I use ::std for clarity.
>
> I've used global namespace qualification in macros, for correctness,
> because you never know where a macro can be used. And I've used global
> namespace qualification for clarity for identifiers from the Windows
> API.

I don't know what the context will be for library code that I
write either.

> However, I don't think "::std::x" is more clear than "std::x"; on
> the contrary, those little "::" are more like noise to my eyes.
>

Sorry, but I don't have a better idea.

Luca Risolia

unread,
Jul 12, 2015, 6:39:11 PM7/12/15
to
woodb...@gmail.com wrote:

> I use ::std for clarity.

It has been shown several times on this NG that :: before std is
completely unuseful.

Richard

unread,
Jul 13, 2015, 1:09:03 PM7/13/15
to
[Please do not mail me a copy of your followup]

OK, this is a long post that covers ideas from object-oriented design
and test-driven development.

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0bfmq...@mid.individual.net> thusly:

>Mr Flibble wrote:
>> Dependencies on concrete classes are considered harmful and should be
>> replaced with dependencies on abstractions.
>
>By whom?

Well, I put Mr. Flibble in my KILL file when he couldn't control
himself in responding to religious flamewar threads, so I didn't see
the original post. I'm also unlikely to respond to anything else he
says on this thread, because he's staying in my KILL file.

However, it seems in this quoted statement Mr. Flibble is conflating
(confusing?) two different pieces of advice. First, there is the
dependency inversion principle (DIP) and there is the technique of
dependency injection.

"In object-oriented programming, the dependency inversion
principle refers to a specific form of decoupling software
modules. When following this principle, the conventional
dependency relationships established from high-level,
policy-setting modules to low-level, dependency modules are
inverted (i.e. reversed), thus rendering high-level modules
independent of the low-level module implementation details. The
principle states:

A. High-level modules should not depend on low-level modules. Both
should depend on abstractions.

B. Abstractions should not depend on details. Details should
depend on abstractions.

The principle inverts the way some people may think about
object-oriented design, dictating that both high- and low-level
objects must depend on the same abstraction."

<https://en.wikipedia.org/wiki/Dependency_inversion_principle>

This is the 'D' in the mnemonic 'SOLID' object oriented design
principles. (This is related to, but not identical to, the idea of
dependency injection in order to construct an object that depends on
another object, but we will get to that in the 2nd point below.)
<https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)>

I have always interpreted this principle to be talking about "objects"
as compared to "value types". I'm using these terms in the same
sense as they are introduced in "Growing Object-Oriented Software,
Guided by Tests" by Freeman and Pryce. <http://amzn.to/1Sjskpm>:

"Values and Objects

When designing a system, it's important to distinguish between
_values_ that model unchanging quantities or measurements, and
_objects_ that have an identity, might change state over time, and
model _computational processes_."

In a C++ program, value types are things like std::string and containers
like std::vector and so-on. The "objects" are things whose identity
matters or model a computational process. Suppose we have a class
representing a person in a payroll application. This is more
appropriately considered an object and not a value type. In that same
payroll application there may be a class called Money that is used to
represent payments between the employer and the employee. This is
more appropriately considered a value type. In C++ value types are
often called "concrete types", because they have no virtual methods
and don't derive from an interface. They aren't intended to be part
of a runtime polymorphic class hierarchy. The abstraction here is the
base polymorphic interface that all derived members of the hierarchy
implement in order to satisfy the Listkov Substitution Principle
(LSP), the 'L' in 'SOLID'.

However, C++ also supports static polymorphism through templates.
In these cases, it is often intentional that there are no virtual methods.
The template mechanisms do not preclude the use of virtual methods as
well for a combination of static and dynamic polymorphism, but this
is a fairly advanced template design pattern. Here the polymorphism
is generally obtained through template parameters and not necessarily
through inheritance. The template arguments are assumed to be models
of a Concept <http://en.cppreference.com/w/cpp/concept>, such as a
Forward Iterator <http://en.cppreference.com/w/cpp/concept/ForwardIterator>.

In both cases, good design following DIP says that the details should
depend on abstractions. An object collaborates with other objects
through an interface so that both can vary independently without
impacting the other. In C++, a web of collaborating objects following
DIP gets the benefit of the "compiler firewall" because the
changes to the implementations of collaborating interfaces don't cause
their collaborators to be recompiled because they literally only
depend on the abstraction of the interface. You put the interface in
one header file and the implementation's declaration in another.

In the static polymorphism case, reusing the standard algorithms
doesn't require me to change my containers so long as they and their
associated iterators model the appropriate concepts used by the
iterator arguments to the algorithms. Similarly, I can write my own
algorithms that operate seamlessly on the standard containers without
those containers having been constructed with knowledge of my
algorithms. The key mechanism that makes this work is the iterators
which decouple the containers from the algorithms and vice-versa. The
iterators are the abstraction upon which both containers and
algorithms depend in order to cooperate with each other.

>> A class should not new its
>> member objects for example but rather should use a factory passed into
>> its constructor.
>
>Why?

This is a very Java-esque way of looking at things, but the same
technique can be applied in C++. It only makes sense for "objects"
and not for "value types". There is no reason to introduce a factory
of std::string, for instance, even if I create a value type that
creates std::string dynamically. (Usually a value type will use
composition instead of the heap, but a std::string is itself an
example of a value type that uses the heap for storage.)

So why introduce a factory for some type T instead of using 'new T'?
Let's look at it from the perspective of unit testing. When I'm unit
testing, I want to mock out the collaborators of the system under test
(SUT). With dynamic polymorphism where the SUT (of type S) dynamically
creates instances of a object collaborator (of type T, implementing some
abstract interface I) dynamically, how can I sense the interaction with
the dynamically created collaborator? If the concrete type T is used
directly by S with 'new T', then I don't have a nice mechanism directly
in the language for substituting a mock of type I under the circumstances
of my test. S is really collaborating with I, the abstraction
implemented by T, but you can't new up an interface, you can only new
up an implementation of the interface, so it ends up being directly
coupled to T. Anytime the implementation of I changes, T changes and
forces S to be recompiled even though the underlying collaboration --
the interface abstraction I -- didn't change. This is because we
aren't following the DIP and we have details depending on details.

However, if S is constructed by taking a factory that creates
instances of type T, then under test circumstances I can provide a
factory that provides mock instances of I and in production
circumstances I can provide a factory that creates instances of T that
implement the abstraction I.

With static polymorphism, there isn't any need for a factory because
the type implementing the abstraction is directly supplied by the code
instantiating the template. The expression 'new T' for some template
parameter T in a template function or class isn't directly coupling
the code to some specific implementation of T. In our test code we
simply need to make sure that the expression 'new T' makes sense for
our supplied mock type. Existing mock libraries let us write sensible
expectations for template arguments, even when new instances are
created dynamically, although it can get a bit tedious. There is
probably some work that could be done in existing mock libraries to
make this easier.

So following the DIP implies that direct coupling of collaborating
object types leads you to want to introduce factory interfaces so that
instead of directly coupling the two implementations of objects you
can couple them through abstractions instead.

In a language like Java, that only supports dynamic polymorphism, that
means that you don't allow 'new' when applied to object types. It is
still allowed for value types. In a language like C++ that fully
supports both static and dynamic polymorphism, you use the appopriate
mechanism at the appropriate time. Virtual functions and dynamic
polymorphism are great for modeling abstractions and collaborating
interfaces. If you aren't dynamically creating collaborators, simply
use dependency injection for your constructors and create the objects
by passing them their collaborators. This technique is often used to
follow the DIP, but the principle and the technique are different.
<https://en.wikipedia.org/wiki/Dependency_injection>

There is no need to use dependency injection for value types. I don't
need to sense how a string is used inside an object I'm unit testing,
I simply verify the object from the outside. For an instance of an
object type, I might ask it to do something and verify it from
externally visible properties of the object when I'm testing something
state-oriented. (If the state is only internally visible and doesn't
manifest itself in any way external to the object, then it doesn't make
sense to try and write a test for that.) If I'm testing an object
that models a computational process then I'm most likely interested in
how this object interacted with its collaborators. I can sense that
interaction through the use of mock collaborators.

When I'm testing a value type object, it doesn't have any collaborators
by definition. Everything I can do to a value type can be observed
from the outside. Imagine yourself in the (unenviable) job of writing
a set of unit tests to verify the behavior of std::string. You can
cover every member function of std::string without knowing *anything*
about how the string is internally represented. All the required
semantics can be verified from its set of public member functions.
--
"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>

Richard

unread,
Jul 13, 2015, 1:10:32 PM7/13/15
to
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.stein...@gmail.com> spake the secret code
<mnq1el$d3u$1...@dont-email.me> thusly:

>Which is, that practically nobody uses the above [SOLID] principle[s]. ;-)

I disagree, the SOLID principles are embraced throughout the standard
library. They just don't do it the 'Java way'.

Richard

unread,
Jul 13, 2015, 1:28:22 PM7/13/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0dtm9...@mid.individual.net> thusly:

>Given the three options of abstract, concrete without non-trivial inline
>member functions or Pimpl classes all are equally simple to mock.

I'm guessing you're using a lot of link-time mocking?

Richard

unread,
Jul 13, 2015, 1:46:56 PM7/13/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0e7tr...@mid.individual.net> thusly:

>I agree. No one who uses TDD writes brain-dead isolated tests.

I'm not sure what it means for a test to be "brain-dead isolated".

However, there are plenty of times when I've started with tests and
gotten to a good design without designing up-front any interfaces or
abstractions explicitly. Did I have an idea of where I wanted to go
in my head? Sure, but I didn't write it down as a "design document".

Mr Flibble

unread,
Jul 13, 2015, 2:59:41 PM7/13/15
to
On 13/07/2015 18:08, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> OK, this is a long post that covers ideas from object-oriented design
> and test-driven development.

[snip]

I can't remember the last time I read so much that said so little.

/Flibble


Mr Flibble

unread,
Jul 13, 2015, 3:06:37 PM7/13/15
to
On 13/07/2015 18:08, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> OK, this is a long post that covers ideas from object-oriented design
> and test-driven development.
>
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <d0bfmq...@mid.individual.net> thusly:
>
>> Mr Flibble wrote:
>>> Dependencies on concrete classes are considered harmful and should be
>>> replaced with dependencies on abstractions.
>>
>> By whom?
>
> Well, I put Mr. Flibble in my KILL file when he couldn't control
> himself in responding to religious flamewar threads, so I didn't see
> the original post. I'm also unlikely to respond to anything else he
> says on this thread, because he's staying in my KILL file.
>
> However, it seems in this quoted statement Mr. Flibble is conflating
> (confusing?) two different pieces of advice. First, there is the
> dependency inversion principle (DIP) and there is the technique of
> dependency injection.

I am not confused at all: by passing a factory to a constructor you are
effectively using *both* dependency injection AND dependency inversion.

[snip]

/Flibble

Ian Collins

unread,
Jul 13, 2015, 4:48:00 PM7/13/15
to
Richard wrote:
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <d0dtm9...@mid.individual.net> thusly:
>
>> Given the three options of abstract, concrete without non-trivial inline
>> member functions or Pimpl classes all are equally simple to mock.
>
> I'm guessing you're using a lot of link-time mocking?

Yes. A lot of my work is low level system code and down there I'll be
mocking mainly C libraries.

--
Ian Collins

Ian Collins

unread,
Jul 13, 2015, 4:52:25 PM7/13/15
to
Richard wrote:
>
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <d0e7tr...@mid.individual.net> thusly:
>
>> I agree. No one who uses TDD writes brain-dead isolated tests.
>
> I'm not sure what it means for a test to be "brain-dead isolated".
>
> However, there are plenty of times when I've started with tests and
> gotten to a good design without designing up-front any interfaces or
> abstractions explicitly. Did I have an idea of where I wanted to go
> in my head? Sure, but I didn't write it down as a "design document".

I've been down the same path many times, especially what doing XP for
one.. In bigger projects some minimal up-front interface design is
necessary.

--
Ian Collins

Richard

unread,
Jul 13, 2015, 6:01:33 PM7/13/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0imnu...@mid.individual.net> thusly:
I agree. The larger the system you're designing, the more up-front
work it requires. However I would say that most of the time when I
was required to produce "design documents" it was largely busy work
that could have been avoided by simply pair programming on the work.
YMMV, of course.

Richard

unread,
Jul 13, 2015, 6:03:15 PM7/13/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0imfg...@mid.individual.net> thusly:
OK, given that confirmation, have you looked at cgreen? It's a unit
test framework built specifically around link-time mocking and the use
of C. All my TDD work has been in C++ where I could use static or
dynamic polymorphism for mocking out collaborators, so I haven't used
link-time mocking. However, I can see it's usefulness.

Ian Collins

unread,
Jul 13, 2015, 6:35:58 PM7/13/15
to
Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <d0imfg...@mid.individual.net> thusly:
>
>> Richard wrote:
>>> Ian Collins <ian-...@hotmail.com> spake the secret code
>>> <d0dtm9...@mid.individual.net> thusly:
>>>
>>>> Given the three options of abstract, concrete without non-trivial inline
>>>> member functions or Pimpl classes all are equally simple to mock.
>>>
>>> I'm guessing you're using a lot of link-time mocking?
>>
>> Yes. A lot of my work is low level system code and down there I'll be
>> mocking mainly C libraries.
>
> OK, given that confirmation, have you looked at cgreen? It's a unit
> test framework built specifically around link-time mocking and the use
> of C.

No, I haven't. I use my own mocking framework that is unit test
framework neutral (it's been used with CppUnut, CxxTest and Google
Test). I prefer to keep the two coupled so I can use my framework with
whatever unit test setup a client uses.

> All my TDD work has been in C++ where I could use static or
> dynamic polymorphism for mocking out collaborators, so I haven't used
> link-time mocking. However, I can see it's usefulness.

It's pretty much the only option when you are working with system (or
object only third party) libraries.

My approach has been to apply the same techniques to pure C++ code and
mixed C and C++. This leads to an unconventional approach to pure C++
code where it is the individual class member functions that are mocked,
rather than class instances. While this may appear odd, I've found most
test cases revolve around checking passed parameter values and responses
to returned values. In these cases, being able to use the code
generated by the framework rather than having to write mock objects
saves a lot of work.

--
Ian Collins

Richard

unread,
Jul 14, 2015, 12:52:40 AM7/14/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0ispt...@mid.individual.net> thusly:

>Richard wrote:
>> All my TDD work has been in C++ where I could use static or
>> dynamic polymorphism for mocking out collaborators, so I haven't used
>> link-time mocking. However, I can see it's usefulness.
>
>It's pretty much the only option when you are working with system (or
>object only third party) libraries.

As they say: any problem in computer science can be solved with
another level of indirection :-). I've done TDD with system-level
APIs provided as free functions by creating a domain-specific wrapper
around them. I've done it with both static polymorphism and dynamic
polymorphism. Link-time mocking is another alternative, of course.

Ian Collins

unread,
Jul 14, 2015, 3:31:43 AM7/14/15
to
Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <d0ispt...@mid.individual.net> thusly:
>
>> Richard wrote:
>>> All my TDD work has been in C++ where I could use static or
>>> dynamic polymorphism for mocking out collaborators, so I haven't used
>>> link-time mocking. However, I can see it's usefulness.
>>
>> It's pretty much the only option when you are working with system (or
>> object only third party) libraries.
>
> As they say: any problem in computer science can be solved with
> another level of indirection :-).

One of my favourite phrases :)

> I've done TDD with system-level
> APIs provided as free functions by creating a domain-specific wrapper
> around them.

That is one solution I have used in the past, however mocking them
required a lot less work - especially if the mocking framework generates
all of the code for you. My framework takes an XML definition of a
function signature (which can its self be code generated from a header)
and produces a class object with a rich set of static member functions
for setting return values and setting up parameter checks.

--
Ian Collins

Richard

unread,
Jul 15, 2015, 12:58:11 PM7/15/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0js6i...@mid.individual.net> thusly:

>Richard wrote:
>> I've done TDD with system-level
>> APIs provided as free functions by creating a domain-specific wrapper
>> around them.
>
>That is one solution I have used in the past, however mocking them
>required a lot less work - especially if the mocking framework generates
>all of the code for you.

Yeah, it's a judgment call. If you're using a handfull of functions
from the Win32 API, then creating your own domain-specific wrapper
around them can be easy. If you need to wrap hundreds of API calls
from Win32 then you'll want something more automated.

On the flip side, sometimes you end up with better architecture as a
side benefit of creating the insulting domain specific layer. You end
up with interfaces that more directly describe the specific services
needed by your application.

Ian Collins

unread,
Jul 15, 2015, 5:49:55 PM7/15/15
to
Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Ian Collins <ian-...@hotmail.com> spake the secret code
> <d0js6i...@mid.individual.net> thusly:
>
>> Richard wrote:
>>> I've done TDD with system-level
>>> APIs provided as free functions by creating a domain-specific wrapper
>>> around them.
>>
>> That is one solution I have used in the past, however mocking them
>> required a lot less work - especially if the mocking framework generates
>> all of the code for you.
>
> Yeah, it's a judgment call. If you're using a handfull of functions
> from the Win32 API, then creating your own domain-specific wrapper
> around them can be easy. If you need to wrap hundreds of API calls
> from Win32 then you'll want something more automated.
>
> On the flip side, sometimes you end up with better architecture as a
> side benefit of creating the insulting domain specific layer. You end
> up with interfaces that more directly describe the specific services
> needed by your application.

A lot of the code I write (and have to test) falls into that category,
hence the need to mock the system calls!

--
Ian Collins

Richard

unread,
Jul 16, 2015, 11:53:53 AM7/16/15
to
[Please do not mail me a copy of your followup]

Ian Collins <ian-...@hotmail.com> spake the secret code
<d0o2ri...@mid.individual.net> thusly:

>Richard wrote:
>> Yeah, it's a judgment call. If you're using a handfull of functions
>> from the Win32 API, then creating your own domain-specific wrapper
>> around them can be easy. If you need to wrap hundreds of API calls
>> from Win32 then you'll want something more automated.
>
>A lot of the code I write (and have to test) falls into that category,
>hence the need to mock the system calls!

Yeah, I can see that if you're writing lots of system oriented code.
However, lots of C APIs are really thinly disguised objects. They have
some C function you call to obtain a resource and another function you
call to release a resource. So a wrapper can still be useful in these
circumstances to map the C api to a more object-oriented api that
ensures that resources are always properly released. Still, for unit
testing that stuff you need to mock out the underlying system API
calls. I've done it via both static and dynamic polymorphism to allow
me to decouple myself from the specific API call. It's more tedious
to do link-time substitution when the things you're mocking are in
Windows DLLs. I haven't tried link-time mocking Windows DLLs myself
but a coworker who tried it said that it was really quite painful. I
didn't review the code he did, so I don't know exactly what the pain
was, but I can imagine that link-time mocking without some sort of
tool that automates the process could be quite tedious.

Jorgen Grahn

unread,
Oct 8, 2015, 9:20:46 AM10/8/15
to
On Wed, 2015-07-15, Richard wrote:
...
> Yeah, it's a judgment call. If you're using a handfull of functions
> from the Win32 API, then creating your own domain-specific wrapper
> around them can be easy. If you need to wrap hundreds of API calls
> from Win32 then you'll want something more automated.
>
> On the flip side, sometimes you end up with better architecture as a
> side benefit of creating the insulting domain specific layer. You end
^^^^^^^^^
You mean "insulating", but the typo was amusing ;-)

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Richard

unread,
Oct 12, 2015, 4:48:27 PM10/12/15
to
[Please do not mail me a copy of your followup]

Jorgen Grahn <grahn...@snipabacken.se> spake the secret code
<slrnn1crcg.5...@frailea.sa.invalid> thusly:

>On Wed, 2015-07-15, Richard wrote:
>...
>> Yeah, it's a judgment call. If you're using a handfull of functions
>> from the Win32 API, then creating your own domain-specific wrapper
>> around them can be easy. If you need to wrap hundreds of API calls
>> from Win32 then you'll want something more automated.
>>
>> On the flip side, sometimes you end up with better architecture as a
>> side benefit of creating the insulting domain specific layer. You end
> ^^^^^^^^^
>You mean "insulating", but the typo was amusing ;-)

LOL. Yes, of course I meant insulating. Thanks for the correction.
0 new messages