Compatibility

On yesterday’s thread, I just wrote in a comment:

@Jon: Yes, C++ is complex and the complexity is largely because of C compatibility. I agree with Bjarne that there’s a small language struggling to get out — I’ve participated in private experiments to specify such a language, and you can do it in well under half the complexity of C++ without losing the expressivity and flexibility of C++. However, it does require changes to syntax (mainly) and semantics (secondarily) that amount to making it a new language, which makes it a massive breaking change for programs (where existing code doesn’t compile and would need to be rewritten manually or with a tool) and programmers (where existing developers need retraining). That’s a very big tradeoff. So just as C++ ‘won’ in the 90s because of its own strengths plus its C compatibility, C++11 is being adopted because of its own strengths plus its C++98 compatibility. At the end of the day compatibility continues to be a very strong force and advantage that isn’t lightly tossed aside to “improve” things. However, it’s still worthwhile and some interesting things may come of it. Stay tuned, but expect (possible) news in years rather than months.

That reminded me of a snippet from the September 2012 issues of CACM. When I first read it, I thought it was so worthwhile that I made a magnified copy and pasted it on the window outside my office at work – it’s still there. The lightly annotated conclusion is shown here.

imageThe article itself was about a different technology, but the Lessons Learned conclusion remind us of the paramount importance of two things:

  • Backward compatibility with simple migration path (“compat”). That’s what keeps you “in the ecosystem.” If you don’t have such compatibility, don’t expect wide adoption unless there are hugely compelling reasons to put up with the breaking change. It’s roughly the same kind of ecosystem change for programmers to go from Language X to Language Y as for users to go from Platform X to Platform Y (e.g., Windows to Mac, iPhone to Android) – in each case you have a lot of relearning, and you lose understood tools and services some of which have replacements and some of which don’t.
  • Focusing on complete end-to-end solutions (“SFE” or scenario-focused engineering). This is why it’s important not to ship just a bunch of individual features, because that can leave holes where Steps 1, 2, and 4 of an end-to-end experience are wonderful but Step 3 is awkward, unreliable, or incomplete, which renders much of the good work in the other steps unuseful since they can’t be used as much or possibly at all.

Enjoy.

20 thoughts on “Compatibility

  1. I think Clang represents the greatest possibility for having a New C++ kind of language. The fact that it exports an AST syntax tree that can be converted back and forth from text to tree without losing any information allows it to become the basis of a transformation into a new language.

    And thus, backwards compatibility can be achieved by simply running code through a tool that is able to convert 100% of the code into the new language. Variables are renamed to avoid conflicts with new keywords, and so forth. If the new language has the same expressiveness as C++, then such an automated transformation must be possible.

    The problem until now has been that there is no tool to be able to do it. We now have one. This moves the problem from lack-of-tool support to lack-of-will. That is, we need people who actually want to do this and are willing to put in the considerable time and effort to see it done.

  2. perl5 has managed to make big changes to the language while keeping everything in the same ecosystem with it’s “use VERSION” statements. I’ve never understood why it hasn’t been copied by other languages. We would probably need real modules first but as long as you had a compiler that could enable different language features depending on the module (how many compilers don’t already support a ton of dialects as it is?) and had rules for managing the ABI differences I think it would be pretty easy to manage on the development side and would free C++ to become a true modern language.

  3. This seems to follow a bit the same path of “worse is better” principle, regardless of much better a given technology is, if the old way is not taken into account, it might just fail.

  4. there are lots of ‘why c++?’ and ‘is c++ dead?’ and ‘c++ resurrection’ etc.
    and lots of words trying to convince that c++ is good and c++11 is even better.
    I say: enough!
    there is no point in all these talks.
    It starts sound like that the c++ community itself is not certain that c++11 is really good.
    when you talk too much about something you are sure of… well, enough.

  5. It was the Bjarne’s mistake to make C++ backward compatible with C. Instead of inheritance “NewLang IS OldLang” it is better to use composition plus code-generators to fill the gap.
    Sometimes I wonder how the world would look if Bjarne choose this way with C++.

  6. Out of curiosity, did your private experiments come up with any insight about what stands in the way of a simple migration path? Will modules be enough? Will we need a standardized AST format to make compiled modules inter-compatible?

  7. I’m with Ran. It’s really hard to get behind a technology that the technologist are not even sure if it’s good enough. It is a little scary.

  8. @Nicol : I agree, CLang paves the way, and helps noob experimenters like me to use C++ parsers and code generator.
    @HotDeal, Ran : I do not agree. I think C++ committee has a definite aim and is doing a good job. There is more discussion because people are curious. And its nice of the C++ community to talk and educate people, its not worthless rambling.
    @Rick Yorgason: I am not an expert, but i don’t think a standard AST will be enough, because again then it may not give enough room for improvement and optimization. I thinks its not only language that will make it compatible, but the way we design our systems. Now a days no one uses a single language, with a plethora of languages at work, design should dictate the communication. Apart from that CLang has a novel way of integrating languages, but CLang is a tool. So leas leave the AST part to tools.
    @tivadj : I think it was an excellent decision, C++ could not let go of “struct” keyword, so it would be good to maintain compatibility with C. C++ is not bigger C, its different, its just similar.
    @Matt : I think we do not need this, we already have #ifdef’s and compiler options for those kind of things. So it will be better not to introduce VERSION.

  9. I was misunderstood (and got too many thumbs down),
    I’m completely C++ fanatic, I don’t know any other languge!
    the point was that Herb Sutter and others, talk too much about how c++11 is good, that for a listener from the outside, it sounds AS IF they are not convinced themselves.
    like a man telling his wife he loves her twenty times a day. it doesn’t feel right.
    that it what I meant.
    I’m completely into C++, C++11 is great,

    I hope I was clearer now.

  10. @Olaf : Let’s put aside the fact that compatibility with C has already been broken, early, and at least twice. (implicit conversion from a void* to T*, and implicit conversion of a string literal to a non-const char *) I’ The language will still get bigger due to backward compatibility, but the design aims of the committee has always been to replace unsafe C features by safer alternatives, and to simplify the language. (by still making the language bigger for backward compatibility, but providing uniform ways of saying related things)

    I’d say that only one kind of significant improvement is impossible : except breaking compatibility to remove what ought not be used anymore, due to the presence of far superior alternatives.

    @tivadj : C++ is not C. More precisely C++ is not C plus extensions, it’s C plus extensions minus inferior alternatives. The drawback is not “backward compatibility”, it’s that it is the programmer’s responsibility not to use backward compatibility features to produce new code.

    @Ran : I am enthusiastic about C++11, and eagerly waiting for it since back in 2005. It’s a significant improvement over previous versions, more than any other language has ever had. (I love move semantics! I’m moving things around all day now, and “Look, Ma! No pointers in app code!”) I disagree with you. I think it’s perfectly normal to be enthousiastic about C++11, and to show enthusiasm. It’s feels like a more correct language than C++03.

  11. @spmisra
    Imagine they come out with C++15 and that it changes some big but outdated C feature like c-strings (string literals create std::string directly instead). This wouldn’t cause any ABI changes but it would cause tons of old code to break. If I wanted to write new code in the new version but use libraries written in C++11 I would either have to be lucky enough to be using a library that happened not to use c-strings in an incompatible way in it’s headers, or I would have to write a wrapper layer and then hope that my compiler produces compatible ABI for the two different versions (no guarantee of that in the standard). It only gets worse the more things you change.

    This is not a good situation when trying to move the language forward.

    We need:
    1) A module system that the compiler is aware of so it can distinguish between different code bases.
    2) A standard way of specifying language version. This couldn’t be done using flags because the standard has no control over that. If we don’t do this then we depend on the build system to figure out the language versions of our libraries (which may themselves contain multiple versions).
    3) Specify in the standard that a single version of a compiler MUST support outputting ABI compatible code for all supported language versions.
    4) Possibly specify which versions of the language a compiler MUST support to be fully compliant which would change as new versions were added and old ones were rotated out. Not sure if this really necessary or not.

    Without something along those lines we will always be timid when adding and removing features from the language, and we will always have slow uptake of new versions.

  12. @Matt : <> They won’t, and for the following reasons :
    1) out-of-the-box compatibility with C is a top design goal when it comes to changing C++. It is a strength of the language not a drawback. The seldom incompatibilities with C are with regards to C++ having a more consistent, stronger typesystem than C. C-strings are used everywhere in C code, so you’re sure to break code like
    const char *foo = “bar”;
    which is omnipresent in C programs. That’s a no-go for Bjarne and the committee.
    2) They already addressed this specific case. Since C++11, you have a cheap alternative, namely you can define a UDL (user-defined literal) like operator “”s, so that :
    – “foo” has type const char *
    – “foo”s has type std::string

    That’s not the point, I’m just kicking the strawman out.

    <> I agree, that’s why the committee is doing an excellent job breaking C compatibility only over-their-dead-body, while still moving the language forward.

    <> Honestly, I don’t know what we need. There is a 2006 paper presenting a module system http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2073.pdf, with a more complete presentation that I could ever give. I think it’s a good idea because the module manifest would be compiler-generated.

    <> You mean, an ABI version, maybe. This could fit with the proposal in 1), and I think it would be a good thing. It would allow tools to generate correct thunks when calling code from a different ABI version. But there is a catch : C++ must link with existing linkers, not specifically designed for C++. They will encounter the same problem as with “who owns template instantiations?”. Who owns the thunks? Now if the thunks are to be local… Wait a minute! Is it not the same problem as calling a C function from C++ code ? How about just wrapping the headers with :
    extern “C++11” {}

  13. Apparently, the comment system does not like angle brackets, so I’m reposting with adequate quoting.

    @Matt :

    Regarding : Imagine they come out with C++15 and that it changes some big but outdated C feature like c-strings (string literals create std::string directly instead)

    They won’t, and for the following reasons :
    1) out-of-the-box compatibility with C is a top design goal when it comes to changing C++. It is a strength of the language not a drawback. The seldom incompatibilities with C are with regards to C++ having a more consistent, stronger typesystem than C. C-strings are used everywhere in C code, so you’re sure to break code like
    const char *foo = “bar”;
    which is omnipresent in C programs. That’s a no-go for Bjarne and the committee.
    2) They already addressed this specific case. Since C++11, you have a cheap alternative, namely you can define a UDL (user-defined literal) like operator “”s, so that :
    – “foo” has type const char *
    – “foo”s has type std::string

    That’s not the point, I’m just kicking the strawman out.

    Regarding: This is not a good situation when trying to move the language forward.

    I agree, that’s why the committee is doing an excellent job breaking C compatibility only over-their-dead-body, while still moving the language forward.

    Regarding : We need 1)

    Honestly, I don’t know what we need. There is a 2006 paper presenting a module system http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2073.pdf, with a more complete presentation thanI could ever give. I think it’s a good idea because the module manifest would be compiler-generated.

    Regarding : We need 2) 3) 4)

    You mean, an ABI version, maybe. This could fit with the proposal in 1), and I think it would be a good thing. It would allow tools to generate correct thunks when calling code from a different ABI version. But there is a catch : C++ must link with existing linkers, not specifically designed for C++. They will encounter the same problem as with “who owns template instantiations?”. Who owns the thunks? Now if the thunks are to be local… Wait a minute! Is it not the same problem as calling a C function from C++ code ? How about just wrapping the headers with :
    extern “C++11″ {}

  14. In particular, when I say “the supporting infrastructure,” I mean pragma restrictions:
    http://en.wikibooks.org/wiki/Ada_Programming/Pragmas/Restrictions
    http://www.adaic.org/resources/add_content/standards/05rm/html/RM-13-12.html
    http://www.adaic.org/resources/add_content/docs/95style/html/sec_10/10-7-2.html
    They seem be *somewhat* similar in spirit to, say, C++ AMP’s “restrict” keyword, except for a considerably finer control granularity (in terms of what’s configurable — see, for instance, the “language defined restrictions identifiers” in the wikibooks’ article) and scope: “unless otherwise specified for a particular restriction, a partition shall obey the restriction if a pragma Restrictions applies to any compilation unit included in the partition.”

  15. @Olaf van der Spek
    Implicit type conversions (as STL puts it: “C wants desperately to compile your code.”)

  16. I agree with Nicol Bola that backward compatibility should be achieved with upgrade tools for the old code. That qualifies as easy enough migration path.

    I want to remind that backward compatibility is mostly a sacrifice to vendors that are not willing to recompile their code anyway (with or without tool aid) and thus force you to use an old compiler too if you link against their DLLs for e.g. I have three versions of Visual Studio installed as a consequence of such antisocial behavior.

    But the good vendors are probably thankful to get a free check and cleanup of their code and not raise compatibility complaints.

Comments are closed.