Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #37010 > unrolled thread

Concrete classes considered harmful

Started byMr Flibble <flibble@i42.co.uk>
First post2015-07-11 04:04 +0100
Last post2015-07-13 00:38 +0200
Articles 20 on this page of 51 — 14 participants

Back to article view | Back to comp.lang.c++


Contents

  Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-11 04:04 +0100
    Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-11 15:09 +1200
      Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-11 17:49 +0100
        Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-11 18:10 +0100
          Re: Concrete classes considered harmful Martin Shobe <martin.shobe@yahoo.com> - 2015-07-11 13:33 -0500
        Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-12 09:17 +1200
          Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 01:51 +0100
            Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-12 13:20 +1200
              Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 02:32 +0100
                Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-12 15:48 +1200
                  Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 13:46 +0100
                Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-12 16:14 +1200
                  Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-13 17:46 +0000
                    Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-14 08:52 +1200
                      Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-13 22:01 +0000
              Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-13 17:28 +0000
                Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-14 08:47 +1200
                  Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-13 22:02 +0000
                    Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-14 10:35 +1200
                      Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-14 04:52 +0000
                        Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-14 19:31 +1200
                          Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-15 16:57 +0000
                            Re: Concrete classes considered harmful Ian Collins <ian-news@hotmail.com> - 2015-07-16 09:49 +1200
                              Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-16 15:53 +0000
                            Re: Concrete classes considered harmful Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-10-08 13:20 +0000
                              Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-10-12 20:48 +0000
        Re: Concrete classes considered harmful Juha Nieminen <nospam@thanks.invalid> - 2015-07-12 11:32 +0000
          Re: Concrete classes considered harmful Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2015-07-12 13:46 +0100
            Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 13:54 +0100
              Re: Concrete classes considered harmful Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2015-07-12 14:21 +0100
                Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 14:40 +0100
                  Re: Concrete classes considered harmful Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2015-07-12 14:59 +0100
      Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-13 17:08 +0000
        Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-13 19:59 +0100
        Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-13 20:06 +0100
    Re: Concrete classes considered harmful "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2015-07-11 05:11 +0200
      Re: Concrete classes considered harmful legalize+jeeves@mail.xmission.com (Richard) - 2015-07-13 17:10 +0000
    Re: Concrete classes considered harmful "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2015-07-11 06:07 +0200
      Re: Concrete classes considered harmful woodbrian77@gmail.com - 2015-07-11 14:12 -0700
    Re: Concrete classes considered harmful Paavo Helde <myfirstname@osa.pri.ee> - 2015-07-11 02:06 -0500
      Re: Concrete classes considered harmful JiiPee <no@notvalid.com> - 2015-07-11 08:28 +0100
      Re: Concrete classes considered harmful Reinhardt Behm <rbehm@hushmail.com> - 2015-07-11 15:48 +0800
    Re: Concrete classes considered harmful Chris Vine <chris@cvine--nospam--.freeserve.co.uk> - 2015-07-12 00:16 +0100
      Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 01:52 +0100
    Re: Concrete classes considered harmful David Harmon <source@netcom.com> - 2015-07-12 06:58 -0700
      Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 15:45 +0100
    Re: Concrete classes considered harmful Mr Flibble <flibble@i42.co.uk> - 2015-07-12 16:30 +0100
      Re: Concrete classes considered harmful woodbrian77@gmail.com - 2015-07-12 11:23 -0700
        Re: Concrete classes considered harmful "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2015-07-12 21:37 +0200
          Re: Concrete classes considered harmful woodbrian77@gmail.com - 2015-07-12 14:34 -0700
        Re: Concrete classes considered harmful Luca Risolia <luca.risolia@linux-projects.org> - 2015-07-13 00:38 +0200

Page 2 of 3 — ← Prev page 1 [2] 3  Next page →


#37074

FromIan Collins <ian-news@hotmail.com>
Date2015-07-14 19:31 +1200
Message-ID<d0js6iFstspU1@mid.individual.net>
In reply to#37073
Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Ian Collins <ian-news@hotmail.com> spake the secret code
> <d0isptFflldU5@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

[toc] | [prev] | [next] | [standalone]


#37084

Fromlegalize+jeeves@mail.xmission.com (Richard)
Date2015-07-15 16:57 +0000
Message-ID<mo63e4$td8$1@news.xmission.com>
In reply to#37074
[Please do not mail me a copy of your followup]

Ian Collins <ian-news@hotmail.com> spake the secret code
<d0js6iFstspU1@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.
-- 
"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>

[toc] | [prev] | [next] | [standalone]


#37088

FromIan Collins <ian-news@hotmail.com>
Date2015-07-16 09:49 +1200
Message-ID<d0o2riFqegtU3@mid.individual.net>
In reply to#37084
Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Ian Collins <ian-news@hotmail.com> spake the secret code
> <d0js6iFstspU1@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

[toc] | [prev] | [next] | [standalone]


#37114

Fromlegalize+jeeves@mail.xmission.com (Richard)
Date2015-07-16 15:53 +0000
Message-ID<mo8k27$g0q$1@news.xmission.com>
In reply to#37088
[Please do not mail me a copy of your followup]

Ian Collins <ian-news@hotmail.com> spake the secret code
<d0o2riFqegtU3@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.
-- 
"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>

[toc] | [prev] | [next] | [standalone]


#38277

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2015-10-08 13:20 +0000
Message-ID<slrnn1crcg.5q5.grahn+nntp@frailea.sa.invalid>
In reply to#37084
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   .

[toc] | [prev] | [next] | [standalone]


#38318

Fromlegalize+jeeves@mail.xmission.com (Richard)
Date2015-10-12 20:48 +0000
Message-ID<mvh6ae$bqj$1@news.xmission.com>
In reply to#38277
[Please do not mail me a copy of your followup]

Jorgen Grahn <grahn+nntp@snipabacken.se> spake the secret code
<slrnn1crcg.5q5.grahn+nntp@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.
-- 
"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>

[toc] | [prev] | [next] | [standalone]


#37033

FromJuha Nieminen <nospam@thanks.invalid>
Date2015-07-12 11:32 +0000
Message-ID<mntj93$n8q$1@adenine.netfront.net>
In reply to#37020
Mr Flibble <flibble@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: news@netfront.net ---

[toc] | [prev] | [next] | [standalone]


#37036

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2015-07-12 13:46 +0100
Message-ID<20150712134630.3f753957@bother.homenet>
In reply to#37033
On Sun, 12 Jul 2015 11:32:53 +0000 (UTC)
Juha Nieminen <nospam@thanks.invalid> wrote:
> Mr Flibble <flibble@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

[toc] | [prev] | [next] | [standalone]


#37038

FromMr Flibble <flibble@i42.co.uk>
Date2015-07-12 13:54 +0100
Message-ID<atCdnXyn6-UI_j_InZ2dnUU78XOdnZ2d@giganews.com>
In reply to#37036
On 12/07/2015 13:46, Chris Vine wrote:
> On Sun, 12 Jul 2015 11:32:53 +0000 (UTC)
> Juha Nieminen <nospam@thanks.invalid> wrote:
>> Mr Flibble <flibble@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

[toc] | [prev] | [next] | [standalone]


#37039

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2015-07-12 14:21 +0100
Message-ID<20150712142105.30ce2f07@bother.homenet>
In reply to#37038
On Sun, 12 Jul 2015 13:54:44 +0100
Mr Flibble <flibble@i42.co.uk> wrote:
> On 12/07/2015 13:46, Chris Vine wrote:
> > On Sun, 12 Jul 2015 11:32:53 +0000 (UTC)
> > Juha Nieminen <nospam@thanks.invalid> wrote:
> >> Mr Flibble <flibble@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.

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.)

> The only issue with abstract interfaces is performance
> when using them with C++ (hence the reason for this thread).
> 
> /Flibble
> 

[toc] | [prev] | [next] | [standalone]


#37040

FromMr Flibble <flibble@i42.co.uk>
Date2015-07-12 14:40 +0100
Message-ID<8YidndEo0LfJ8z_InZ2dnUU78eWdnZ2d@giganews.com>
In reply to#37039
On 12/07/2015 14:21, Chris Vine wrote:
> On Sun, 12 Jul 2015 13:54:44 +0100
> Mr Flibble <flibble@i42.co.uk> wrote:
>> On 12/07/2015 13:46, Chris Vine wrote:
>>> On Sun, 12 Jul 2015 11:32:53 +0000 (UTC)
>>> Juha Nieminen <nospam@thanks.invalid> wrote:
>>>> Mr Flibble <flibble@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.
>
> 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.)

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

[toc] | [prev] | [next] | [standalone]


#37042

FromChris Vine <chris@cvine--nospam--.freeserve.co.uk>
Date2015-07-12 14:59 +0100
Message-ID<20150712145916.1a189e50@bother.homenet>
In reply to#37040
On Sun, 12 Jul 2015 14:40:35 +0100
Mr Flibble <flibble@i42.co.uk> wrote:

> On 12/07/2015 14:21, Chris Vine wrote:
> > On Sun, 12 Jul 2015 13:54:44 +0100
> > Mr Flibble <flibble@i42.co.uk> wrote:
> >> On 12/07/2015 13:46, Chris Vine wrote:
> >>> On Sun, 12 Jul 2015 11:32:53 +0000 (UTC)
> >>> Juha Nieminen <nospam@thanks.invalid> wrote:
> >>>> Mr Flibble <flibble@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.
> >
> > 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.)
> 
> 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.

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

[toc] | [prev] | [next] | [standalone]


#37056

Fromlegalize+jeeves@mail.xmission.com (Richard)
Date2015-07-13 17:08 +0000
Message-ID<mo0rb4$hgq$1@news.xmission.com>
In reply to#37011
[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-news@hotmail.com> spake the secret code
<d0bfmqFegarU5@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>

[toc] | [prev] | [next] | [standalone]


#37062

FromMr Flibble <flibble@i42.co.uk>
Date2015-07-13 19:59 +0100
Message-ID<lb6dnXh_r7kMlznInZ2dnUU78dGdnZ2d@giganews.com>
In reply to#37056
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

[toc] | [prev] | [next] | [standalone]


#37063

FromMr Flibble <flibble@i42.co.uk>
Date2015-07-13 20:06 +0100
Message-ID<upOdnUMVgNyukTnInZ2dnUU78f2dnZ2d@giganews.com>
In reply to#37056
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-news@hotmail.com> spake the secret code
> <d0bfmqFegarU5@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

[toc] | [prev] | [next] | [standalone]


#37012

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2015-07-11 05:11 +0200
Message-ID<mnq1el$d3u$1@dont-email.me>
In reply to#37010
On 11-Jul-15 5:04 AM, Mr Flibble 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.
>
> 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?

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.

[toc] | [prev] | [next] | [standalone]


#37057

Fromlegalize+jeeves@mail.xmission.com (Richard)
Date2015-07-13 17:10 +0000
Message-ID<mo0rdv$hgq$2@news.xmission.com>
In reply to#37012
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.steinbach+usenet@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'.
-- 
"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>

[toc] | [prev] | [next] | [standalone]


#37014

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2015-07-11 06:07 +0200
Message-ID<mnq4mt$k83$1@dont-email.me>
In reply to#37010
On 11-Jul-15 5:25 AM, Stefan Ram wrote:
> Mr Flibble <flibble@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.

Cheers & hth.,

- Alf

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

[toc] | [prev] | [next] | [standalone]


#37024

Fromwoodbrian77@gmail.com
Date2015-07-11 14:12 -0700
Message-ID<157316bd-a552-4546-adbd-c28677b80415@googlegroups.com>
In reply to#37014
On Friday, July 10, 2015 at 11:07:29 PM UTC-5, Alf P. Steinbach wrote:
> On 11-Jul-15 5:25 AM, Stefan Ram wrote:
> > Mr Flibble <flibble@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.
> 

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

[toc] | [prev] | [next] | [standalone]


#37016

FromPaavo Helde <myfirstname@osa.pri.ee>
Date2015-07-11 02:06 -0500
Message-ID<XnsA4D466BFDC19Fmyfirstnameosapriee@216.166.105.131>
In reply to#37010
Mr Flibble <flibble@i42.co.uk> wrote in news:y42dnfPZC9VKGj3InZ2dnUU78Q-
dnZ2d@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?

[toc] | [prev] | [next] | [standalone]


Page 2 of 3 — ← Prev page 1 [2] 3  Next page →

Back to top | Article view | comp.lang.c++


csiph-web