Stefan Teleman wrote: > > > 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.
But gptr() isn't what is being used ... what is being used is _C_gptr, which is a data member, not a function. The upshot of that is that the implementation of the class winds up being encoded in the consuming application's binary. > > > 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. But we're not talking about things mandated by the standard. And the standard in no way dictates anything about how those functions and data members are encoded by the compiler. That is the problem we seem to be having here. You're mistaking an immutable *programming interface* for an immutable *binary interface*. > > 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. Yes, there are ways to add to the implementation safely without breaking the binary interface, I understand that. > > 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. No, it won't. Adding a new private data member does *not* violate the standard -- because the standard doesn't say anything about the internal implementation of the class. What it *will* do is break the things not spelled out by the standard -- such as the binary interface generated by the compiler and linker. > > 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". But those changes would be equally toxic to any application which included those headers (directly, or indirectly such as via class inheritance or containment.) I've not reviewed the source code to look to see if this is handled properly, but at the moment (based on the other things I've seen in the code), I'd be surprised if this were done properly and safely. > >> 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). See, but I have no reason to believe that they will be. I searched on Apache's website, and I could find no statements indicating any kind of intent about binary compatibility. I suspect, like most of the rest of the C++ world, these folks are concerned primarily (perhaps only) with compatibility at the source code level. Now, if you're able to provide some concrete evidence as to why you believe the Apache C++ group will honor a binary stability level and not break classes in ways that break dynamically linked applications, then I'd be happy to set aside this *particular* portion of my argument. > 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. Maybe. But that doesn't mean they care. I believe Linus Torvalds "understands" how to binary compatible interfaces can be made -- but he has adamantly refused the notion that Linux needs binary stability. I don't know *what* the Apache's team stance is, since I can't find any documented statement one way or the other. > > 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. Yes, this kind of approach could generate a binary safe API, provided that the header files involved in the APIs exposed expose only method prototypes and not method implementation. That might mean that KDE or Gnome could use *whatever* library they wished with little regard to the library underneath changing. *Except* that there is still a link time problem of mixing libraries built against different Standard C++ libraries. I notice you've studiously ignored this problem in your replies. At this point, I'm even more convinced now (both by reading the actual Apache C++ source code, and by Steve Clamage's comments substantiating my concerns) that I was correct and these problems need to be addressed, and the project is way out of bounds as a fast track (at least as specified.) The case remains derailed. I propose that further discussion be taken *off* PSARC-ext, until the project team is ready to present a full case. If the project team believes that my concerns are irrelevant and unfounded, then they can ask to be put on the schedule for Wednesday's meeting, where they can try to convince the other members and ask for a vote at the end of the meeting. Further argument about this case on the public lists at this point is probably fruitless. I'll be happy to respond to private e-mail if you wish to discuss it further. -- Garrett