The Artima Developer Community
Sponsored Link

Weblogs Forum
Separation of Concerns

17 replies on 2 pages. Most recent reply: Nov 10, 2005 5:09 AM by Terje Slettebø

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 17 replies on 2 pages [ 1 2 | » ]
Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Separation of Concerns (View in Weblogs)
Posted: Nov 2, 2005 7:11 AM
Reply to this message Reply
Summary
A very important programming principle is that of separation of concerns. A class should have one clearly defined responsibility. When this is violated problems arise, for instance in the STL.
Advertisement
One of the design problems with the STL, is that the containers have multiple responsibilities . Understanding the STL limitations can allow you to more effectively use it, and become a better coder.

In the STL the containers are actually factory classes. They manage object lifespans,and memory allocation. This makes them behave rather strangely as abstract data types (ADT, e.g. stack, list, array, deque). For instance: you might think that you could create a reference to an object within an STL container, but unfortunately the object can be easily moved invalidating your reference silently. This kind of behaviour is frustrating at first, but logical when you consider that an STL collection has to grow/shrink to accomodate insertion/deletion.

In order to deal with this I apply the principle of separation of concerns: I create separate classes for my objects: an object lifetime manager, and an ADT. Usually the object manager is implemented as a linked list of arrays. I then create the appropriate ADT (e.g. tree, linked list, heap) which my algorithms operate on. To quote David Wheeler out of context:

"Any problem in computer science can be solved with another layer of indirection."

Do you have other examples of problems which are solved through application of the principle of separation of concerns?


Greg Jorgensen

Posts: 65
Nickname: gregjor
Registered: Feb, 2004

Re: Separation of Concerns Posted: Nov 2, 2005 8:13 PM
Reply to this message Reply
> One of the design problems with the STL, is that the
> containers have multiple responsibilities.

I don't see any design problem (yet); the STL containers seem to conform to their original design and intentions. There's a difference between a design problem and something you don't like or agree with.

> In the STL the containers are actually factory classes.

I don't follow: STL containers don't create instances of the objects they contain, so how are they factories? If you mean the templates that create the STL containers are analogous to factory classes, OK, though it's more usual to refer to the template mechanism as blueprints (or templates) and to the instantiations as specializations. If you're using novel terminology you need to explain.

> (ADT, e.g. stack, list, array, deque). For instance: you
> might think that you could create a reference to an object
> within an STL container, but unfortunately the object can
> be easily moved invalidating your reference silently.

I wouldn't think I could create a reference to an object inside an STL container without regard to the rules and idioms. Iterators, for example, are invalidated in well-defined circumstances; nothing silently moves things around invalidating references unless your code initiates the move. Whenever I've seen code that has to care about whether a reference to something inside a container, or an iterator, is good that has happened because the container was too widely accessible (not scoped) or not encapsulated appropriately. I don't consider misuse of STL containers or iterators a design problem.

> This kind of behaviour is frustrating at first, but
> logical when you consider that an STL collection
> has to grow/shrink to accomodate insertion/deletion.

That is the documented behavior of the containers, not something programmers should discover by trial and error after much frustration.

> In order to deal with this I apply the principle of
> <i>separation of concerns</i>: I create separate classes
> for my objects: an object lifetime manager, and an ADT.
> Usually the object manager is implemented as a linked list
> of arrays. I then create the appropriate ADT (e.g. tree,
> linked list, heap) which my algorithms operate on.
>
> Do you have other examples of problems which are solved
> through application of the principle of separation of
> concerns?

I don't understand what you're talking about. Do you have anexample of an STL problem and your proposed solution?

Harrison Ainsworth

Posts: 57
Nickname: hxa7241
Registered: Apr, 2005

factoring, encapsulation Posted: Nov 3, 2005 4:28 AM
Reply to this message Reply
I think of this as making a good, fine, factoring. It is fundamental to, almost the essence of, software design. But for a simple rationale: in later development it is much easier to join things together than split them apart.

Providing refs or pointers to class internals is bad generally. It breaks encapsulation. Unless efficiency is needed, or the type *defines* the implementation (eg. 3D point), it is best avoided.

One of the principles of STL must have been efficiency. So weakness in other ways is reasonable.

Greg Jorgensen

Posts: 65
Nickname: gregjor
Registered: Feb, 2004

Re: factoring, encapsulation Posted: Nov 3, 2005 4:28 PM
Reply to this message Reply
> One of the principles of STL must have been efficiency. So
> weakness in other ways is reasonable.

Mr. Diggins has not identified the weakness or design flaw in STL that he alludes to. If we're going to talk about design flaws in STL let's do that with reference to what the designers intended. The STL may be hard to learn or understand because C++ template syntax is a bit opaque, but that isn't a design flaw.

The design principles behind the STL have been described clearly by Alexander Stepanov, one of the designers. From the paper that introduced the STL to the C++ world, The Standard Template Library:

The Standard Template Library provides a set of well structured generic C++ components that work together in a seamless way. Special care has been taken to ensure that all the template algorithms work not only on the data structures in the library, but also on built-in C++ data structures. For example, all the algorithms work on regular pointers. The orthogonal design of the library allows programmers to use library data structures with their own algorithms, and to use library algorithms with their own data structures. The well specified semantic and complexity requirements guarantee that a user component will work with the library, and that it will work efficiently. This flexibility ensures the widespread utility of the library.

Another important consideration is efficiency. C++ is successful because it combines expressive power with efficiency. Much effort has been spent to verify that every template component in the library has a generic implementation that performs within a few percentage points of the efficiency of the corresponding hand coded routine.

The third consideration in the design has been to develop a library structure that, while being natural and easy to grasp, is based on a firm theoretical foundation.


(http://www.stepanovpapers.com/STL/DOC.PDF)

In his introduction to the book STL Tutorial and Reference Guide, Second Edition: C++ Programming with the Standard Template Library Stepanov spelled out the design goals of STL even more succinctly:

STL was designed with four fundamental ideas in mind:
* Abstractness
* Efficiency
* Von Neumann computational model
* Value semantics


(http://www.stepanovpapers.com/MusserForeward.pdf)

So, where exactly did STL fail to meet the original design principles?

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Separation of Concerns Posted: Nov 3, 2005 4:55 PM
Reply to this message Reply
> > One of the design problems with the STL, is that the
> > containers have multiple responsibilities.
>
> I don't see any design problem (yet); the STL containers
> seem to conform to their original design and intentions.
> There's a difference between a design problem and
> something you don't like or agree with.

I am using the term "design problem" to refer to a flawed design. Just because a design is intentional doesn't make it unflawed.

> > In the STL the containers are actually factory classes.
>
> I don't follow: STL containers don't create instances of
> the objects they contain, so how are they factories?


struct fubar { };
fubar x;
std::vector<fubar> v;
v.push_back(x); // the vector makes an internal copy of the object, therefore it is a factory.


> If
> you mean the templates that create the STL containers are
> analogous to factory classes, OK, though it's more usual
> to refer to the template mechanism as blueprints (or
> templates) and to the instantiations as specializations.
> If you're using novel terminology you need to explain.

It appears you are splitting hairs between templates and template instantiations. You obviously know what I am talking about. Furthermore your own usage of the term "blueprints" is novel in of itself.

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: factoring, encapsulation Posted: Nov 3, 2005 4:57 PM
Reply to this message Reply
> > One of the principles of STL must have been efficiency.
> So
> > weakness in other ways is reasonable.
>
> Mr. Diggins has not identified the weakness or design flaw
> in STL that he alludes to.

The STL collections don't have clear and well-defined responsibilities. They are intended as both factories (as evidenced through the use of the allocator template parameter) and ADT's.

Greg Jorgensen

Posts: 65
Nickname: gregjor
Registered: Feb, 2004

Re: factoring, encapsulation Posted: Nov 4, 2005 12:01 AM
Reply to this message Reply
> I am using the term "design problem" to refer to a flawed
> design. Just because a design is intentional doesn't make
> it unflawed.

What is the flaw you're talking about? Maybe STL is flawed but not because you say so.

>

> struct fubar { };
> fubar x;
> std::vector<fubar> v;
> v.push_back(x); // the vector makes an internal copy of
> the object, therefore it is a factory.
>


No. The STL by design uses value semantics. The internal copy of an object is not returned by the container's push_back method and you aren't supposed to take references to objects inside containers. According to Wikipedia (and numerous other references): In object-oriented computer programming, a factory object is an object for creating other objects. (http://en.wikipedia.org/wiki/Factory_object) The STL containers are not specifically for creating objects: the internal copy is incidental. By your definition any class that makes an internal copy of something is a factory.

> It appears you are splitting hairs between templates and
> template instantiations. You obviously know what I am
> talking about. Furthermore your own usage of the term
> "blueprints" is novel in of itself.

I'm not splitting hairs, and I don't know what you're talking about. I'm trying to understand what flaws in STL you are referring to. And you can find plenty of authors (including Stroustrup) using the term "blueprint" to describe both templates and class definitions.

> The STL collections don't have clear and well-defined
> responsibilities. They are intended as both factories (as
> evidenced through the use of the allocator template
> parameter) and ADT's.

The STL containers are not intended to be factories -- they don't act like factories to begin with, and even if you stretch the definition of factory to include internal copies that was clearly not the intention behind the containers. Allocators are for portability, to encapsulate different memory models, not to make the container classes into factories.

STL's containers and algorithms already separate the concerns. The containers and algorithms don't have to know anything about the objects they operate on. You can develop your own objects without regard to how the container classes work internally. The "object lifetime manager" and ADTs you describe are more concerned with each other than an STL container is with its contents.

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: factoring, encapsulation Posted: Nov 4, 2005 6:26 AM
Reply to this message Reply
In
> object-oriented computer programming, a factory object is
> an object for creating other objects.


That defintion fits the STL containers, because they create objects.

> (http://en.wikipedia.org/wiki/Factory_object) The STL
> containers are not specifically for creating objects: the
> internal copy is incidental.

No it isn't, it is part of the design specification. std::vector<T>::operator[]() returns a reference to the allocated object.

> By your definition any class
> that makes an internal copy of something is a factory.

By yours too.

Greg Jorgensen

Posts: 65
Nickname: gregjor
Registered: Feb, 2004

Re: factoring, encapsulation Posted: Nov 4, 2005 10:18 AM
Reply to this message Reply
> That defintion fits the STL containers, because they
> create objects.

They aren't specifically for creating objects, that's my point. Just creating an object (or copy-creating as the STL containers do) does not in itself make a factory class. A factory class is a class for creating objects, not just any class that incidentally creates objects.

> No it isn't, it is part of the design specification.
> std::vector<T>::operator[]() returns a reference to the
> allocated object.

And that allocated object is a copy of whatever was inserted into the container -- the container did not itself create the object as a factory class would. Allocating a copy is not the same as creation as contemplated by the factory pattern. The only sense that the STL containers are factories is for their own internal purposes, and I don't see how that has anything to do with the "separation of concerns" topic because by design your code is not concerned with the internal workings of the STL containers.

In any case this nitpicking is not even relevant. You still haven't explained what "design flaws" in STL you referred to, or what solution you offer. I'm not clear on what problem you are addressing -- the topic is just another buzzword thrown out there with no meaningful explanation.

Bob Dobalina

Posts: 16
Nickname: hiredgoon
Registered: Apr, 2005

Value semantics... Posted: Nov 5, 2005 1:27 AM
Reply to this message Reply
>> struct fubar { };
>> fubar x;
>> std::vector<fubar> v;
>> v.push_back(x); // the vector makes an internal copy of the object, therefore it is a factory.

struct fubar { };
fubar x;
fubar v[1];
v[0] = x; // the array makes an internal copy of the object, therefore it is a factory.

Greg Jorgensen

Posts: 65
Nickname: gregjor
Registered: Feb, 2004

Re: Value semantics... Posted: Nov 5, 2005 1:15 PM
Reply to this message Reply
Dave,

> v[0] = x; // the array makes an internal copy of the object, therefore it is a factory.


Very nice, and fast -- thanks! Can I use your array factory code in the library I'm working on (with attribution)?

Tim LS

Posts: 37
Nickname: parchandri
Registered: Jul, 2005

Re: Separation of Concerns Posted: Nov 6, 2005 12:01 PM
Reply to this message Reply
I feel this post is a little ridiculous, because I consider STL very cleverly designed - to generalise many algorithms across different data structures. Why you would then want to go and use references to the contained parts... is well, still a mystery, but mine not to reason why.

If you want to manage the memory allocation you can - you can write your own allocators - and sometimes have to for good performance characteristics.

If you want references to objects within the containers, maybe you should use containers of pointers, and then the pointers can be moved around without invalidating your references (to the objects pointed to). Yes, I guess that's a layer of indirection, and you probably already thought of this...

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Separation of Concerns Posted: Nov 6, 2005 5:02 PM
Reply to this message Reply
> If you want references to objects within the containers,
> maybe you should use containers of pointers, and then the
> pointers can be moved around without invalidating your
> references (to the objects pointed to). Yes, I guess
> that's a layer of indirection, and you probably already
> thought of this...

This is almost the point of my post. STL containers shouldn't be used to allocate the objects even though they were designed to, but rather to hold pointers to objects allocated by a separate factory class.

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Value semantics... Posted: Nov 6, 2005 5:07 PM
Reply to this message Reply
> >> struct fubar { };
> >> fubar x;
> >> std::vector<fubar> v;
> >> v.push_back(x); // the vector makes an internal copy of
> the object, therefore it is a factory.

> struct fubar { };
> fubar x;
> fubar v[1];
> v[0] = x; // the array makes an internal copy of the
> object, therefore it is a factory.

I should have said, when you call v.push_back, the vector uses the allocator to create an empty instance of the type fubar, and then copies x into it.

It is not the fact that it makes a copy, but the fact that the vector uses an allocator class to create a new object instance dynamically, which makes it a factory.

Christopher Diggins

Posts: 1215
Nickname: cdiggins
Registered: Feb, 2004

Re: Value semantics... Posted: Nov 6, 2005 8:16 PM
Reply to this message Reply
> It is not the fact that it makes a copy, but the fact that
> the vector uses an allocator class to create a new object
> instance dynamically, which makes it a factory.

I should point out that I can see how it can be argued that the standard containers "use" factories but are not themselves factories. I call them factories because they expose the dynamically created -- and not just copy-created as Greg suggests, e.g. std::vector.resize(int) -- objects through references and iterators. I think the STL should have separate factory classes, and separate ADT classes, hence the title "separation of concerns".

Flat View: This topic has 17 replies on 2 pages [ 1  2 | » ]
Topic: IQ is a Relatively Meaningless Number Consumed by Egotistical Narcissists Previous Topic   Next Topic Topic: Functions as Classes: Where did I steal it from?

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use