Maxim Yegorushkin
12/4/2008 4:38:00 PM
On Dec 4, 4:29 pm, Jeff Schwab <j...@schwabcenter.com> wrote:
> Maxim Yegorushkin wrote:
> > On Dec 4, 3:15 pm, Victor Bazarov <v.Abaza...@comAcast.net> wrote:
> >> Per wrote:
> >>> I am finding myself doing the following rather often when I have
> >>> template containers in classed, e.g. stl::map
> >>> For example:
> >>> class Foo
> >>> {
> >>> public:
> >>> typedef std::map<std::string, int> direcory_t;
> >>> //More typedefs of the same style...
> >>> private:
> >>> directory_t directory_m;
> >>> //More members of the same style...
> >>> public:
> >>> //Constructors and stuff
> >>> const directory_t& directory() const {return directory_m;}
> >>> };
> >>> The question is what is your opinion on typedefing like this. At the
> >>> same time as it saves a lot of typing. After a while there are very
> >>> many types in a project. And in the end can get confusing about what
> >>> the type really contains. Classes should of course hide their
> >>> implementation but it seams very stupid not to have read access
> >>> directly to a member. If I didn't have that I have to bloat the class
> >>> with wrapper functions for the members. And not using typedefs would
> >>> lead to an awful lot of typing.
> >> I use this approach everywhere. It's an abstraction. The users of your
> >> class will use "Foo::directory_t" when they need the type. The main
> >> thing is not saving typing (although it's a nice side effect) but the
> >> ability to change what 'directory_t' means with a single line, and not
> >> to worry about changing the rest of the code that uses it. That's the
> >> whole idea behind typedefs. It doesn't matter how they are defined, as
> >> a namespace member or as a class member.
>
> I also use this technique quite a bit, though usually with iterators,
> rather than container types.
>
> > More often such an approach is called abstraction leak.
>
> There is the potential for leakage under certain circumstances, but
> there is no abstraction leak in the posted code. For you to list any
> such problem with the code, you're going to have to start with "what if...."
>
> > The interface of directory_t "abstraction" is that of std::map<>. You
> > can only change the type of directory_t to something that supports the
> > full interface of std::map<>, otherwise you break the client code (you
> > may be lucky if there was limited use of std::map<> directory_t
> > interface, so that recompilation after changing the type of
> > directory_t succeeds, but you can't count on that).
>
> The problem you're describing applies when the amount of client code
> that can access the exposed type is unbounded. When the code is already
> encapsulated within some intermediate layer, e.g. it is an
> implementation detail of some stand-alone application, there is no need
> to enforce any tighter enapsulation. The public typedef for the
> otherwise private type is worth having in such a scenario, not because
> it limits potential uses of the type, but because it serves to identify
> them.
>
> The literal text "std::map<std::string,int> tells the reader what type
> is in use, but Foo::directory_t gives the more relevant information of
> why this is the right type for the job. If ever you do need to change
> the type's interface, it's a lot easier to search for Foo::directory_t
> than to figure out which instances of std::map<std::string,int> are
> relevant to Foo.
>
> If you break the interface in a way that the compiler catches, within
> the context of implementing an application, it's not a particularly big
> deal. The potential to break the interface in ways the compiler cannot
> catch, e.g. changing the big-O complexity of an operation, is no less
> prevalent if a custom type is used rather than a typedef.
My point was that it was not an abstraction, because it abstracts away
nothing but the name of the type. Rather a convenience typedef to make
code less fragile.
Sorry for nor being clear on this.
--
Max