The Linux Documentation Project lists a number of examples of library incompatibilities: http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html#AEN135
--Mark On Dec 13, 2007 4:44 PM, Martin Sebor <[EMAIL PROTECTED]> wrote: > Travis Vitek wrote: > > > > > >> Travis Vitek wrote > >> > >> Martin Sebor wrote: > >>> I've incorporated everyone's feedback and committed an updated > >>> version with a number of enhancements of my own. Among the most > >>> important are the new Goals section with suggested frequencies of > >>> releases, and the integration of the Version Policy (I plan to delete > >>> versions.html). Let me know what you think. > >>> > >>> http://incubator.apache.org/stdcxx/releases.html > >>> > >> Martin, > >> > >> I found this page that documents a few do's and dont's of binary > >> compatibility. I realize that most of the tricky issues involve inline > >> functions or templates, but this gives a list of the common pitfalls. > >> > >> http://tinyurl.com/2gf38p > >> > >> Travis > > > > Here are some examples that I came up with. Each case is written in a > > pseudo diff format. > > Excellent! See my comments below. > > > > > Travis > > > > // neither source nor binary compatible. not source compatible > > // if user might take address of member function A::f. > > struct A > > { > > - int f() const { return 1; } > > + int f(int i = 1) const { return i; } > > }; > > > > // alternative is source and binary compatible. can be changed > > // to a default argument in next source incompatible release. > > struct A > > { > > int f() const { return 1; } > > + int f(int i) const { return i; } > > }; > > > > // is binary compatible, but not be source compatible because > > // the compiler has no way to handle A().f(1) > > struct A > > { > > int f(long i) const { return 2; } > > + int f(unsigned i) const { return 2; } > > }; > > > > I would tend to throw these in the bag of "obvious no-no's." > > > // not binary compatible, changing access specifier on windows is a > > no-no. if the > > // new access modifier is more restricted, this may be source > > incompatible, but > > // only if the user code calls or takes the address of the function. > > class A > > { > > -private: > > +public: > > int f() const { return 1; } > > }; > > This one is much less obvious and so it might be worth mentioning > in the document. > > > > > // source and binary compatible, not functionally compatible. f() will > > square v > > // in user code, and ctor will square v in library code. if an instance > > is > > // created in library and passed to user code, it will be squared > > twice. if the > > // other way, it will not be squared at all. > > // > > // if the definitions were outlined, this would be compatible. > > class A > > { > > public: > > - A(float f) : v(f) { } > > - float f() const { return v*v; } > > + A(float f) : v(f*f) { } > > + float f() const { return v; } > > private: > > float v; > > }; > > This is an interesting case. Why (when) does it matter that the result > of f() is different? What does it mean for STDCXX-226? > > > > > > > // binary and source compatible, but not functionally compatible > > // because call to g() is inlined. > > // > > // this would be compatible if f() were outlined, or g() behaved > > // the same for input values 2 and 3. > > struct A > > { > > - void f() { g(2); } > > + void f() { g(3); } > > void g(int i); > > }; > > Same as above. > > > > > > > // it appears that this could be fully compatible in some cases. > > // it might not be source/functionally compatible if the user is > > // exposed to this type. a switch on an E instance might cause a > > // default block to be hit, which could trigger a failure in user > > // code. > > // > > // if A::Z is used as a `last enum' marker, this might introduce > > // a binary compatibility issue if a global or member array is > > // declared to have A::Z elements. > > // > > // this might also be binary incompatible if the enum is persisted. > > struct A > > { > > - enum E { W, X, Z }; > > + enum E { W, X, Y, Z }; > > }; > > I'd say this is both source and binary incompatible. > > Consider: > > switch (e) { > case A::Z: break; > case 4: break; // okay in version 1 but error on version 2 > } > > and: > > template <int> struct S { }; > > void foo (S<A::Z>()); // ==> mangled as foo_S_A_2 in version 1 > // but foo_S_A_3 in version 2 > > Thanks again. These are exactly the kind of examples I was hoping for: > innocuous looking changes that are fully compatible in most situations > but can be actually be breaking in some edge cases. > > Martin >