Garrett D'Amore wrote:
> Reading the Apache C++ sources (which I didn't want to do, but here you 
> go), I ran into the following example snippet in the include directory 
> (the include file is <streambuf>):
> 
> template<class _CharT, class _Traits>
> inline typename basic_streambuf<_CharT, _Traits>::int_type
> basic_streambuf<_CharT, _Traits>::
> sputbackc (char_type __c)
> {
>    _RWSTD_ASSERT (_C_is_valid ());
> 
>    if (_C_putback_avail () && traits_type::eq (*(gptr () - 1), __c))
>        return traits_type::to_int_type (*--_C_gptr);
> 
>    return pbackfail (traits_type::to_int_type (__c));
> }
> 
> 
> In the above example, the inline function has in it bits which appear to 
> me to be implementation details (_C_putback_avail() is protected for 
> example -- I'm not sure whether the *standard* specifies that it exist 
> or not.  _C_gptr is certainly a private member of the class, and I 
> "presume" that the standard doesn't specify it, though I've not checked 
> the standard since I don't have a copy of it handy.)
> 
> The concern here is what happens if those portions of the implementation 
> need to change?  (What happens if _C_gptr moves in the class, or the 
> implementation needs to change in a way that _C_gptr doesn't exist at 
> all, or changes type?  Bad things, I suspect.)

These changes cannot be made. Not for the duration of Major Release 4.

This is what the Standard says about this particular member function:

27.5.2.2.4 Putback

int_type sputbackc(char_type c);

1       Returns: If the input sequence putback position is not available, or if
        traits::eq(c, gptr()[-1]) is false, returns
        pbackfail(traits::to_int_type(c)). Otherwise, decrements the next
        pointer for the input sequence  and returns
        traits::to_int_type (*gptr()).

The function _C_putback_avail() is private to this implementation of the 
Library 
(in the Apache Library's case all functions, or data members whose names begin 
with "_C" are private to the implementation). The pointer _C_gptr (or a 
functional equivalent thereof) is mandated by the Standard. This naming 
convention is a warning to the developer of the application consuming the 
interfaces exposed by <streambuf>: Do Not Use These Functions Directly Under 
Any 
Circumstances Whatsoever. Also, the fact that is is protected imposes 
restrictions on access.

The important aspect is that the gptr() (which Apache calls _C_gptr) is 
explicitly mentioned in the Standard.

If you compare version 4.2.1 of this Standard header file with the same header 
file from versions 4.2.0, or 4.1.3, you will see that the changes made to this 
header file do not break binary compatibility.

> Will the implementation take care to preserve the *existing* functions 
> so that the above inline (which will now have been compiled into various 
> applications) will continue to function, regardless of what other 
> changes may be necessary for the class?

The implementation *must* preserve those functions and data members (or 
functional equivalents thereof) which are mandated by the Standard. These 
cannot 
be changed in any way -- they are immutable.

New, non-virtual member functions could be added to this class (non-virtual 
functions do not affect the size or the layout of the object, or of the 
__vtbl), 
provided that their names begins with "_C", and are therefore labeled as 
private 
to the implementation. Static member functions could be safely added (they 
don't 
even have an implicit "this" pointer at all, and they do not affect the size or 
the layout of the object), subject to the same naming convention constraints.

New virtual member functions, and/or new data members cannot be added, under 
any 
circumstances whatsoever. But such additions should not be even considered in 
the first place -- this version of the Standard is frozen. Adding a virtual 
function to this class will first and foremost violate the interfaces mandated 
by the Standard.

What could change, with less restrictions, are the private implementation 
details which can be found in the $(top_srcdir)/src directory, and whose names 
begin with "__rw".

> I apologize for my apparently childish C++ example earlier -- as I said, 
> I don't work in the language very often.  But I *think* I've found a 
> real example from Apache C++ that suffers the same  problem.  Do you 
> disagree?

I do not see this example as a reason for binary compatibility breakage 
concern, 
provided that the rules for preserving binary compatibility are observed (which 
I have no reason to believe that they will not be). Everything i've said here i 
can guarantee that is is also very well known by the Apache/RogueWave 
developers 
as well -- most likely much more.

No apologies necessary. There are design circumstances in which the developer 
of 
the library interface simply knows that the class layout cannot change, ever. 
For those circumstances, freezing the object layout is appropriate.

KDE, and QT, intentionally do not use this approach. For all the library 
classes 
which expose public interfaces available to external consumers, the private 
implementation details are hidden by means of the Bridge or Facade Design 
Patterns (pImpl pattern). The actual implementation of the header file only 
exposes member functions, and the only data member is an opaque pointer to the 
private implementation. The actual private implementation is done in the *.cpp 
translation unit.

--Stefan

-- 
Stefan Teleman
Sun Microsystems, Inc.
Stefan.Teleman at Sun.COM


Reply via email to