Bjarne Stroustrup On Concepts, C++0x
An anonymous reader writes "Danny Kalev has an interview with Bjarne Stroustrup about the failure of concepts, the technical issues of concepts, whether the ISO committee's days are over, and whether C++ is at a dead-end. 'I don't think that concepts were doomed to fail. Also, I don't think concepts were trying to fix many things or to transform C++ into an almost new language. They were introduced to do one thing: provide direct language support to the by-far dominant use of templates: generic programming. They were intended to allow direct expression of what people already state in comments, in design documents, and in documentation. Every well-designed template is written with a notion of what is required from its arguments. For good code, those requirements are documented (think of the standard's requirements tables). That is, today most templates are designed using an informal notion of concepts.'"
Donkey Kong: The specification of concepts has taken seven years. By contrast, the standardization of the entire STL took about half that time. What is so complicated about concepts?
... etc.
Bull Shit! I count the concepts work as started in 2002! I presented my first design papers in 2003! In 1994 Alex Stepanov presented a complete implementation of the STL to Andrew Koenig and me, but 2002-to-2009 and 1994-to-1998 are not comparable time lines! Alex had been working on the STL from at least 1976!
What's really unfortunate is that he's one of the very few language maintainers out there that isn't of the mentality "Rah rah! My language/tool/design-philosophy/whatever is the solution to all your problems and will take over the world tomorrow." (phrase lifted from the interview) Wish we had more people like you out there, Stroustrup. Also, if this isn't fixed by now, I'm sorry Slashdot couldn't even get your name right in the title to this story.
My work here is dung.
What the hell? Do I have to RTFA to find out what C++0x is supposed to mean?
Alexander Peter Kristopeit bought his basement from his mommy for one dollar.
Templates are what Python calls 'duck typing'. ("If it looks like a duck and quacks like a duck...") Why not just do that? You could add methods for introspection and so forth...
My blog
I've seen a lot of people dramatize about concepts being removed from C++0x.
Really, it's no big deal. There are alternative solutions, like some based on SFINAE -- that has now been extended to arbitrary expressions --, that provide almost the same feature set, the same quality in error messages, and are not much harder or more verbose to write or use.
Actually, getting rid of concepts was probably the best solution for C++0x, since they were a lot of work to implement on top of not being that well polished, not integrating that well with the rest (concepts are not types, nor are they templates, they're a whole new category of things) which would probably have led to different categories of compliance to the new standard.
This even gives a new chance to more vital features, such as polymorphic lambdas (understand lambdas were the types of the arguments is not given and which thus exhibit parametric polymorphism), to now being reconsidered.
If any one feature could ensure the continuation of C++ as a language it would be a standardized GUI library.
( i know I know, platform problems, implementation , the venders oppose it).
but when it comes right down to it. If C++ had a set of GUI libraries that were part of the standard and could be counted on to be in every compiler ( even if they didn't always look the quite the same). It would go a long way to providing something most developers need and want that can't be found in a lot of languages.
âoeTolerance applies only to persons, but never to truth. Intolerance applies only to truth, but never to persons.
Stupid name, it should be
C+++=1
or is equiv
C+=2
C++0X is a syntax error!
Uncluttered article, without any extra crap and multiple pages. Printable = readable.
Do you realise that most of the guts of Windows is actually written in C++? And that the secretary of the C++ Standards Committe, Herb Sutter, works for Microsoft?
Are you even a C++ developer at all?
I would be willing to bet that some vendors that make more than one language are probably not too crazy about doing more with an open language like C++. Not that I would make any association with a large software vendor founded in the 1970s that leveraged a pretty good BASIC interpreter into operating system and tools dominance... but
Yeah, Microsoft is so uninterested in C++ that for the Visual C++ 2010 release that they've added in a whole bunch of new features including partial support for this new standard.
Oh, and that's not even getting to the fact that Microsoft still uses C++ extensively throughout it's products. Yes, clearly that is a sign of a company that isn't crazy about C++ anymore.
I believe some features that might help C++ is automatic memory allocation (where objects are automatically resized and freed when they go out of scope), and dynamic types (which automatically convert according to some rules based on the context they are used in), basically to give it the same effects as Ruby. This would be optional and avialable alongside present manual systems. It would be an interesting concept rather than just hardcoding this, instead allow it to be implemented on top of some API, sort of the tie() interface on Perl, that whenever an object goes out of scope or something is stored into it, a callback is triggered where a plugin can handle the desired features. This would allow greater flexibility. These objects would be aware of the data type of the data stored in them, like ASCII or binary integer. If it were used in an arithmatic operation, a certain callback could be triggered provided by the objects controller object, which could convert the value from ASCII into binary required by arithmatic operator. Perhaps even a seperate set of string operators should be considered as well.
Can't we just skip "concepts", and move straightaway to "meta-concepts"? After all, a "concept" is just a concept itself, so with meta-concepts we'll be able to define "concepts" recursively. Which doesn't sound like a win, until you realize then you can redefine concepts to fit your own idiosyncratic needs. Like how in my code, the first thing I always do is overload "+" to mean "*", and vice versa. I've always liked them the other way around, not sure why. Anyway, back on point: Concepts by itself is like the 4-blade razor, a lame, stupid half-measure. The real prize, the 360-dunk-off-the-free-throw-line, is 5 blades on a razor. I move we skip "concepts" and go for the big win. Those effeminate Python dorks will have no answer to this, they'll be stunned to see just how inferior they really are. Who's with me on this?
Broader point: I'm sick and tired of these language designers not giving us enough features. For the last 20 years I've been waiting for a language that will allow me to redefine keywords. If that too much to ask? What if I don't happen to like "for", or "while", or "return"? Do you people lack vision, or competence, or both? Second thing on my must-have list is a pre-pre-processor. I'm tired of writing all these header files all the time. I want a way to generate them programmatically, at compile time. A small embedded scripting language would do fine, just make sure it has templates and operator overloading and multiple inheritance, so I can stretch my legs and get comfy with it. Come on people, start earning your paychecks and get some of this stuff done!
as it is, I think C++ is pretty much dead as it is, and its' probably going to have to be up to gcc to just grab the bull by the horns and implement new features by fiat and create a defacto standard.
Well, that's how it used to be - the standards committee generally checks what all the major implementations implement that isn't specified by the standard, and then try to get the common non-standard parts into the next standard. Basically - see what the industry is doing, and if they all seem to agree then standardise it.
I'm a minority race. Save your vitriol for white people.
C++ is far from dead in all piece of code that need performances. Intel released a C++ library called TBB to use multi-core architecture a few years ago. They do not believe it is dead. Parallel programming framework such as cilk stoped using C to use C++ to gain templates.
Don't get me wrong, for most task people don't care about the performance provided by a low level language and thus don't need it. It is even harmful to use C++ if you are not going to do it properly.
And let's not forget Intel C++. Intel hates C++0x so much that they decided to add the following C++0x features in Intel C++ 11.0 which has been available since November 2008: - Empty macro arguments - Variadic macros - Type long long - Trailing comma in enum definition - Concatenation of mixed-width string literals - Extended friend declarations - Use of ">>" to close two template argument lists - Relaxed rules for use of "typename" - Relaxed rules for disambiguation using the "template" keyword - Copy constructor does not need to be callable on direct reference - Binding to class rvalue - "extern template" to suppress instantiation of an entity - "auto" type specifier - decltype operator - static_assert - compliant __func__ - lambda expressions
Is there some reason that they couldn't have taken some of the work from Eiffel on design by contract and used it for C++0x? Eiffel already compiles to C on its way to object code so I would assume that all of the Eiffel framework stuff could be made to work in C++. Once you've programmed in a design by contract language you really miss it because almost all of the stupid class of bugs go away because they get flagged at compile time.
There are 4 boxes to use in the defense of liberty: soap, ballot, jury, ammo. Use in that order. Starting now.
Yeah, legacy is a bitch.
Fuck systemd. Fuck Redhat. Fuck Soylent, too. Wait, scratch the last one.
and we'll all be calling it C++10.
I, for one, will be calling it C++0x0A.
Reply to That ||
It is a big deal. The two most important things concepts were going to do was make generic programming in C++ (1) explicit and (2) accessible.
Currently, generic programming in C++ is supported through a number of template meta-programming patterns and practices, most of which exist as Boost tribal knowledge - hail King Dave!* It is implicit in many library designs, but there is nothing enforcing it at the language level. If you're not familiar with the concepts of generic programming (pun intended), it's easy to mistake what's going on in the standard libraries as something else. This is especially true if your primary use of the STL is to have polymorphic container classes - you might just design a generic extension to another language that completely misses the point of generic programming (see Java Generics).
At a more fundamental level, a lot of the power in generic programming comes from the specializations that are possible when you meet type requirements. Right now, there is no way, outside the documentation, to state requirements and possible specializations. Making this explicit in the language makes it clear to the library user what the requirements are and what specializations are available.
This leads into the accessibility problem. Generic Programming using template meta-programming is difficult. To use it, you have to understand both the template system and generic programming. The former is defined in the standard, but the latter, as mentioned above, is tribal knowledge. By making generic programming explicit in the language, it immediately becomes accessible to a large number of developers who didn't have the time, patience, or fortitude (dealing with the Boost mailing list requires a large supply of this) to become proficient with template-based generic programming.
As an analogy: consider object-oriented programming in C. Prior to (and even after) C++, lots of OO code was been developed in C. But, each object system was different and based on local best-practices. C++ (and Objective-C) took those practices and codified them into a language extension. As soon as that occurred, one method for OO was standardized. Developers no longer had to implement their own object systems and adhere to documented (but not language enforced) policies. And, with a standard set of rules around this flavor of OO, many other developers felt comfortable jumping in the the fray.
Concepts in C++ should have had the same effect for Generic Programming in C++ that C++ had for Object Oriented Programming in C. The should have democratized generic programming and brought forth a renaissance in C++ library design. Instead, petty politics killed the most exciting change to C-like languages in years.
-Chris
*(Dave - I mean that in the nicest sense... you've done a great job with Boost (oh, we need to jam again, too)).
They wouldn't be continuing to actively develop Visual C++ and implement new C++0x features if they were going to drop C++.
The main difference that springs to mind is that duck typing in Python is dynamic (resolved at runtime), where-as the type system in C++ is static (resolved at compile-time).
Compile-time checking has two purposes: enforce contracts between methods and allow for optimization. I'll cover each of these in turn:
Dynamic languages have more overhead to dispatch a method call. But then static languages have to duplicate the template code for each type that it handles. It is disputed whether the more direct dispatch outweighs the overhead of loading the duplicated instructions into the CPU's instruction cache.
Types of arguments to methods make up part of a contract between a method and methods that call it. It's good to have a compiler that can verify some of a contract at compile time, but the halting problem implies that not all parts of all contracts can be expressed in a way that can a machine can verify. Fans of dynamic languages claim that purpose-written unit tests can verify contracts more thoroughly than a compiler's built-in checking, but fans of static languages claim that properly done static typing writes half the unit test for you.
Kalev's questions came across as ignorant and belligerent, but Stroustrup answered all of them intelligently, thoroughly and patiently. It's good to know that there are men like Stroustrup still working hard on C++, even though I no longer do much work in it.
They are supposed to make the claim against the area for which their language is most appropriate. Although to be fair, it is often the people who are marketing the self-help books that tend to be the most vocal advocates of a particular language. I remember picking up an early O'Reilly book on Perl in a bookstore and reading the introduction and putting it back on the shelf in disgust because of the zealousness of the advocacy in the introduction.
I have also been down the "should not" path on several languages much to my chagrin. Fortunately, I've paid the price allowing me to spare my students the pain.
Atlas stands on the earth and carries the celestial sphere on his shoulders.
The C+-* Language
* pronounced "C, more or less."
Unlike C++, C+- is a subject oriented language. Each C+- class instance known as a subject, holds hidden members, known as prejudices or undeclared preferences, which are impervious preferences, which are impervious to outside messages, as well as public members known as boasts or claims. The following C operators are overridden as shown:
C+- is a strongly typed language based on stereotyping and self-righteous logic. The Boolean variables TRUE and FALSE (known as constants in less realistic languages) are supplemented with CREDIBLE and DUBIOUS, which are fuzzier than Zadeh's traditional fuzzy categories. All Booleans can be declared with the modifiers strong and weak. Weak implication is said to "preserve deniability" and was added at the request of the D.O.D. to ensure compatability with future versions of Ada. Well-formed falsehoods (WFFs) are assignment-compatible with all Booleans. What-if and why-not interactions are aided by the special conditional evenifnot X then Y.
C+- supports information hiding and, among friend classes only, rumor sharing. Borrowing from the Eiffel lexicon, non-friend classes can be killed by arranging contracts. Note that friendships are intransitive, volatile, and non-Abelian.
Single and multiple inheritance mechanisms are implemented with random mutations. Disinheritance rules are covered by a complex probate protocol. In addition to base, derrived, virtual, and abstract classes, C+- supports gut classes. In certian locales, polygamous derivations and bastard classes are permitted. Elsewhere, loose coupling between classes is illegal, so the marriage and divorce operators may be needed:
Operator precedence rules can be suspended with the directive #pragma dwim, known as the "Do what I mean" pragma. ANSIfication will be firmly resisted. C+-'s slogan is "Be Your Own Standard."
http://baetzler.de/humor/c_more_or_less.html
It's Slashdot.
95 percent of the posts are going to be from script language kiddies who have never written a single line of commercial quality production code on a medium to large scale product.
Concepts in C++ should have had the same effect for Generic Programming in C++ that C++ had for Object Oriented Programming in C. The should have democratized generic programming and brought forth a renaissance in C++ library design. Instead, petty politics killed the most exciting change to C-like languages in years.
Given "Things could have been much worse. In particular, we could have made the seriously flawed "concepts" part of the standard." and "By building directly on the pre-Frankfurt concepts and applying modifications along the lines I suggested in "simplifying the use of concepts" we could have had something acceptable (IMO) within months, but that will not happen now. Instead, we must re-evaluate the basics of concepts and rebuild more or less from scratch (relying on the experience gained so far)â"and experiment. My stated estimate is that that will take on the order of five years, but that it will happen.", I'm thinking that concepts being delayed (not killed) means they'll actually be significantly better that they would have been without being kicked out of this particular revision of the standard.
It's kind of sad. The C++ committee has taken the general position that the underlying defects of C++ should be papered over by making it possible to write templates that hide the problem. But the hiding never quite works; the mold always seeps through the wallpaper.
The root of the problem is that C and C++ backed into a type system. Originally, C barely had types at all; there were ints and there were floats. Pointers and ints were almost interchangeable. Fields in structures were just offsets, and field names had to be unique across all structures. Gradually, C evolved into a strongly typed language. Sort of. "void *" was introduced as a sort of escape hatch for the type system.
More importantly, there was never a clear distinction made between arrays and pointers. That single design decision is responsible for most of the buffer overflows in the world. We should have had syntax like
int read(int fd, char buf[n]&, size_t n);
to replace the old
int read(int fd, char *buf, size_t n);
which says nothing about the size of the array. Right there is the cause of most buffer overflows - the language doesn't properly support talking about the size of arrays.
Part of the problem there was a major error in the original design of C++ - it didn't have "&" references. So you couldn't talk about a reference to an array; you had to use a pointer to the first element. That pointer has the type of the element, not of an array. Every time you write "char *buf" instead of "char buf[n]&", you're lying to the compiler. The cost of that lie is millions of crashes a day.
Instead of fixing the mess underneath, C++ papered it over. Arrays were wrapped with classes in the Standard Template Library. The STL is a good thing, but it's not good enough to totally replace built-in arrays. So real-world programs remain a mixture of ambiguous built-in arrays, pointers to arrays, and STL arrays.
Then the STL approached iteration as an extension of pointer arithmetic. For "compatibility" with C pointer arithmetic, iterators are not only unchecked, but are not explicitly bound to the collection over which they iterate. So the safety problems of C were carried over into STL arrays. This was another bad decision. Most modern languages approach iteration by providing a "do this to all that stuff" construct used for most common iteration cases. C++ does not.
This is why I'm so critical of the C++ committee. If they'd focused on safety, instead of cool but obscure template features, software would be much better today.
Yet they released Visual Studio 2008 with a showstopper bug that stopped large C++ projects being compiled (it barfed about being unable to read the pdb file halfway through, then just gave up).
They've made it that unless you #define a load of stuff to switch the crap off or start using proprietary Windows extensions none of your code will compile without warnings.
They deprecated huge chunks of both the C and C++ standards without asking any of the standards committees.
Oh, and they *still* haven't caught up with C99.
It is even harmful to use C++ if you are not going to do it properly.
For example:
Fix the damned error messages. Seeing something referring to "std::vector>" when I used "vector" is bad enough. Having it at the end of a 255 character error message? Even worse.
Best Slashdot Co
Is that some kinda of filthy ASCII art?
Utilizing the synergization of benchmark e-solutions to pre-workaround action items!
Nice explanation, especially the "OOP in C" analogy. Thanks.
-- don't discount flying pigs until you have good air defense
It's only a big deal to certain programming groups and applications. The programming I do cannot use templates so generic programming is useless to me and removal of concepts is not a big deal at all.
Tesla was a genius. Edison however was a overrated hack who liked to torture puppies.
In my opinion, the main thing lacking in c++ is that it's not possible to get a pointer to a function in a class instance. This meant that any code based on the windows API could not be "eloquently" wrapped into objects. The GUI has suffered most because of this, because MFC just isn't really object oriented to me. Of course it is possible to put in workarounds using global functions and storing pointers in some unused spot of the class, but such stuff has always bothered me.
as it is, I think C++ is pretty much dead as it is
So what in your opinion is a viable C++ replacement?
Tesla was a genius. Edison however was a overrated hack who liked to torture puppies.
Uncluttered article, without any extra crap and multiple pages. Printable == readable.
There fixed that for you.
They've made it that unless you #define a load of stuff to switch the crap off or start using proprietary Windows extensions none of your code will compile without warnings.
They deprecated huge chunks of both the C and C++ standards without asking any of the standards committees.
I assume that you refer to the so-called "secure CRT" functions here, such as strcat_s. If so, there are two points to be made.
First of all, those aren't proprietary extensions. It's an implementation of an ISO C++ TR 24731 (as most ISO standards, an electronic version of the final standard isn't available freely, but you can look at the final draft). Yes, the implementation in VC2005 preceded the final release of that TR, and rather went hand in hand with development of the spec; but virtually all C++ compilers did that for ISO C++ itself as well, before it was finalized in 1998.
Regarding "deprecating", it's mostly a poor choice of words. The compiler would complain about "strcpy is deprecated", but it was never supposed to mean deprecation in ISO C++ standardeze meaning. Besides, it was a warning, not an error, and a conformant C++ implementation can produce all kinds of warnings so long as it compiles legal code - warnings are not regulated by the Standard in any way. In any case, you don't need to "#define a load of stuff" - as with any compiler, you can pass preprocessor definitions via compiler switches from command line (or makefile), and you only need a single define - _CRT_SECURE_NO_WARNINGS.
Oh, and they *still* haven't caught up with C99.
No-one has caught up with C99 yet. Even gcc still has quite a few features implemented only halfway, or even outright broken. Heck, VLAs - which is one major C99 feature - were still broken in gcc 4.3, and only properly supported in 4.4. If anything, this just points out how little people do care about most C99 stuff (which you know anyway if you actually follow the discussions on the matter).
At the same time, VC++ supports C++ TR1, which has some more useful bits of C99 (such as stdint.h header with standard typedefs for things such as int32_t).
Concepts are not too different from the way generics work in C#
Concepts are very different from C# generics in one simple (but far-reaching) aspect.
C# generics can be constrained by interfaces. An interface constraint is limited to specifying instance operations (properties, methods, events) available for this particular type only. For example, C# generic type parameter cannot be constrained to say "this type should support operator+", because overloaded operators in C# are static, and need not even belong to be a member of the type substituted as a type parameter. This means that you cannot e.g. write a Complex<T> class in C# which supports all arithmetic properly (well you can if you use reflection and other similar tricks, but performance will be dismal).
C++ concepts are predicates operating on multiple types and compile-time expressions. For example, there was a basic concept called SameType, that would hold true if two types given to it as arguments represent the same type. Because of that, concepts can require all kinds of operations - static members, global functions, overloaded operators, etc.
Yukihiro Matsumoto of Ruby: "Why should you switch to Ruby? If you are happy with Perl or Python, you don't have to. But if you do feel there must be a better language, Ruby may be your language of choice." and then "I believe people want to express themselves when they program. They don't want to fight with the language. Programming languages must feel natural to programmers."
Nice job quoting him out of sequence, and implying that his response regarding his guiding philosophy is even relevant to the question that's posed to him about switching. And also, nice job omitting the phrase "I tried to..." from his guiding philosophy. Since such a qualifier implies personal doubt that he even achieved such a goal, that doubt was endangered your thesis, so kudos removing it -- that makes his response (that you've already completely distorted by quoting out of sequence, and quoted from a totally different question then the one you've put before it) sound even more absolute.
Stewart: Did you have a guiding philosophy when designing Ruby?
Matz: Yes, it's called the "principle of least surprise." I believe people want to express themselves when they program. They don't want to fight with the language. Programming languages must feel natural to programmers. I tried to make people enjoy programming and concentrate on the fun and creative part of programming when they use Ruby.
[...]
Stewart: Why should someone already familiar with Perl or Python switch to Ruby?
Matz: Why should you switch to Ruby? If you are happy with Perl or Python, you don't have to. But if you do feel there must be a better language, Ruby may be your language of choice. Learning a new language is harmless. It gives you new ideas and insights. You don't have to switch, just learn and try it. You may find yourself comfortable enough with Ruby to decide to switch to it.
After skimming the article, what came to mind was:
Is he trying to turn C++ into a functional programming language? Concepts == FP-ish behavior...
With that, I rather choose Scala and it's VM safety net.
I really wish they had chosen some other word - searching for "C++ concepts" gets a lot of introduction to c++ programming websites (yes, I know the trick is to search for "C+0x concepts"). When you pick a word to describe what you are doing, either pick a more accurate description that is unambiguous. Maybe they could have gone with something like "Formalized Templates".
No, I don't trust in god. He'll have to pay up front, like everybody else.
Yes yes, I know, I was being too simplistic (I realized this after I hit submit). Duck typing == dynamic dispatch *and* dynamic typing. Either way, "duck typing" is a stupid marketing term, nothing more.
So what if it is? Stupid or not, it's nevertheless an effective way of conveying a certain concept.
The point is that these languages have taken those language features and used them to embrace a philosophy (Duck Typing) of how types should be used in the language. I would say that your equation isn't quite correct: Duck Typing isn't the combination of dynamic dispatch and dynamic typing: rather, that combination is one way to implement the concept. Duck Typing itself has more to do with removing the formal definition of a common interface, and the philosophy that if two modules happen to implement the same interface consistently enough that they could work interchangeably, then that is a common interface.
Duck Typing is not specific to runtime. It's all about the concept that type compatibility is determined only by the set of operations that can be performed on a value.
Basically it's a convenient form of sloppy, fragile programming, especially in the case of languages where an inconsistency in the interfaces of the "interchangeable" modules can't be detected except at runtime via a coverage test (as in Python). But it's nevertheless an idea that is used (by way of templates) quite a bit in C++. If you implement a function in C++ with a template argument, then the only thing about that argument that the programmer has to concern himself with is whether the usage of that argument inside the function fits the interface of the class used to implement the value passed in for that argument. In this case neither dynamic dispatch or dynamic typing would be used (C++ specializes the function at compile time) - but from the programmer's perspective it's the same concept as duck typing: all that matters is that whatever class is used as the value for that template argument has to match the usage of that argument inside the function body.
Bow-ties are cool.
What failed was the concept of C++. We didn't need it, and the people that wanted it were basically bored with producing software and wanted to play around with programming concepts instead. Here it is, decades later, and I'm coding "cloud computing" infrastructure stuff in C. If you want to write code, write code. If you want to fart around, fart around, but don't take yourself too seriously or trick yourself into thinking that your new paradigm actually is one. Also, don't fool yourself into thinking that .NET is more about producing software than it is about building revenue fences for Microsoft.
I wrote the original post on Lambda calling C++ a dead end, and I think what the article says about the standardization process is pretty accurate.
Essentially there are a set of issues real world C++ programmers must deal with when using the languages, particularly in large projects, that are never addressed by the standards committee. Enumerating a few by importance:
1. Stability, security, and memory safety.
Support for garbage collection, optional safe arrays, safe pointers, and bounds checking for sections of code. Code areas where reinterpret casts and other memory unsafe operations can be disabled and flagged as errors. Secure versions of the standard libraries. Etc.
Can anyone honestly say that security and stability in C++ code is not the singular most important issue for C++ presently? How many times have security, stability, or memory safety been even mentioned in the C++ 0x standardization process? I've browsed through many of the papers and have yet to see it mentioned a single time (possibly there are one or two mentions in the GC papers).
2. Ability to integrate with other languages, particularly managed and dynamic languages.
Reflection support, decidably parsable declarations, support or standardization of in/out semantics on declarations, etc. I would say for many (if not most projects) dealing with the "C++ as an insular world unto itself" is one of the next most glaringly problematic aspect of the language. Few languages go to greater lengths to make integrating with the outside world more difficult.
3. Issues with separate compilation, headers and macros.
BS made a half hearted attempt to mitigate the issues arising from the use of the include file model, and macros in C++, but it was quickly abandon. The problems (particularly in large projects) with the separate compilation model, (increasing time involved in parsing large headers), problems with macro leakage, and other issues in the essentially broken C style compilation model are a major source of continuous pain for C++ programmers.
There is no reason why the language can not continue to be backwards compatible with separate compilation and macros, but can be moved forward towards a more workable model for new code.
4. The inability to ever "deprecate" features.
The language can be progressively improved, but only by some sort of an official program of scheduling certain features for deprecation. Insecure C functions and libraries, unused standards, etc. This kruft unneccessarily complicates the introduction of new useful features, and makes it difficult to maintain production code (which typically become new code combined with a random collection outdated programming practices and library includes which must constantly be "code reviewed" out).
5. The inability to add features from other languages that do actually work.
What is important and "works" for one programmer is a superfluous and useless add-on for another. But there are features of java, C#, and dynamic languages that C++ would do well to imitate. These features are rarely even discussed in favor of serving the template meta-programming community and those who feel the language should add a host of other esoteric features to the corner case use scenarios of the language.
I've been writing C++ for more than 20 years, and I've dealt first hand working with a huge C++ project when working with ILM's large code base that exposed more than a few of the gaping weakness of this language. I was looking forward to.. at least.. some help in dealing with the impossibility of maintaining large amounts of template code, of which that code base had multiple nested layers. An error in one template parameter class cascades downwards into an infinite incomprehensible mess of template substitution errors. But the committee says "No concepts for you!"
Uncluttered article, without any extra crap and multiple pages. Printable == readable.
There fixed that for you.
You know, this tends to bug me a bit...
I mean, yeah, here we are talking about C++ in which "=" means assignment and "==" means an equality test... But the world at large is not governed by these definitions. An equation like "y = 3*x + 4" establishes a relationship in which the two sides of the equation are equal.
If you want to apply the meanings of C operators to English text, then really neither meaning is correct:
"Printable = Readable" - means "Henceforth, until further notice, 'Printable' will have the value that 'Readable' has now" (Assignment)
"Printable == Readable" - means "I want to know if 'Printable' and 'Readable' have the same value". (It's an equality test, not an equality assertion)
Bow-ties are cool.
What's really unfortunate is that he's one of the very few language maintainers out there that isn't of the mentality "Rah rah! My language/tool/design-philosophy/whatever is the solution to all your problems and will take over the world tomorrow."
Care to actually provide the names of those other language maintainers, with appropriate citations, that make such claims?
Very well. They don't out and out say that exact phrase but I'm sick of languages being marketed to me like an automobile. Here are a few after a bit of Googling. I don't really have time to dig more up: ...
If I were in their shoes, I would explicitly say what the language is but also explicitly say what it is not. As someone who's tried to do video analysis in Java, I've been down the "should not" path and wasted my time.
Java was very, very hyped, it's true. However I view the other cases rather differently. I have been working on a language design of my own, and as a result I have given this some thought.
Basically, to a certain extent it doesn't matter how good a language or tool is if people don't try it. And it can be hard to get people to try something new and different for a variety of reasons: there's bound to be a learning curve involved, and even if the language is populated with concepts the user will ultimately enjoy, when they start out it'll all be rather alien. I believe that if you want people to use the language you've developed, you've got to "market" it - otherwise people will never get beyond those initial hurdles standing between themselves and their potential enjoyment of the language. For the language to have any chance at all of success, someone's got to be an advocate for it - if the language creator isn't doing this, then why should anyone else?
As for keeping the proper perspective in this advocacy - that is tough because people involved in development often think in terms of what they want the tool to become rather than necessarily exactly what it is. In the case of independent software developers writing these things, they're often not your consultants either - they're not there to advise you on whether their tool might or might not be good for your task - they wrote something they're enthusiastic about, and they're excited to share it.
As for the Matsumoto quote you cited: he was asked specifically in the interview if there was a philosophy that guided the development of Ruby, and that was his answer. Now, you could say that was a carefully crafted answer designed to win over the hearts of programmers - or you could say that this really was the idea that drove him to create a programming language, and guided its design. Who can say which is right? I read the quote and I see Matsumoto as someone who's enthusiastic about what he's created, and wants people to enjoy it...
Bow-ties are cool.
Sure. And for groups who could not use OOP C++ certainly wasn't a big deal either. And for people writing single-threaded programs, removal of multithreading wouldn't be a big deal either. And I guess people programming toasters don't have any use for the standard I/O facilities of either C or C++, so why not get rid of them?
The Tao of math: The numbers you can count are not the real numbers.
It seems to me that C++ has forked into two languages which coexist in the same spec, like fungus and alga in a lichen. One of the examples given for using concepts is as follows:
template<Container C, Comparator Cmp>
void sort(C& c, Cmp cmp);
This was to specify that type C, used as the type of the first argument, must implement the 'Container' concept. But don't we already have classes and abstract classes for that?
void sort(Container& c, cmp cmp);
You define the abstract class 'Container' using the same boring C++ syntax that's been around since 1985 or so, and then the compiler will check that what you pass implements this interface. So what's the need for another type language? Is it because there is no abstract base class that specifies 'has an [] operator' or 'has ++ and * operators'? If so would it not be better to add that somehow rather than making new language syntax?
Or is it because of the difference between static binding, accomplished with templates at compile time, and virtual functions, which must be looked up at runtime? Is it really worth constructing a whole new language syntax just for the fairly small performance saving of skipping a vtable lookup? C++ advocates point out how std::sort can be faster than C's qsort because of template code generation, but with only slightly more intelligent compilers surely we could write more normal-looking source code and have type-specialized object code generated when needed, if the types used can be determined at compile time.
C++ templates are very useful, but they never seemed to integrate that well with the rest of the language. It's not clear that having them grow their own type system is the best mutation to make the language simpler and more powerful, though it may be the best way to move forward from the situation we have now.
-- Ed Avis ed@membled.com
I'm not really up on C++0x (eh, well) concepts, but, while I appreciate the concept (ehem) of trying to help the guy reading the code to read the minds of the original developers, I have to question the wisdom of trying to shoehorn the wisdom of the ages into a programing language. Especially, if we try to shoehorn the wisdom of the ages in via a generic (erk) mechanism.
Wisdom is experience, experience is what you get in specific application, after reflection.
I could see some use, possibly, for making exceptional code explicit and keeping the generic stuff implicit, but only if we can all agree beforehand what is exceptional and what is generic. Huge semantic issues, huge context issues, and it seems to me we must be careful when trying to drag the entire mental state context of the programer into the code.
We still seem to be fighting the battle of implicit linkage. How does a programer make the linkage explicit when he or she doesn't know what most of his or her assumptions were until after the third or forth major bugs with that section of code have been found? (Speaking of an example of the benefit of "many eyes", ....)
(Oh, and, please don't tell me that somebody is still enamored with the concept of writing bug-free code in the first pass. When are we, as a profession, going to recognize that bugs are a necessary part of the design process?)
Overloading English is not going to help, either, I think, although it will cause one set of problems for people fluent in English, and a different set for those who are not.
(No, I'm not sure of what I'm trying to say, other than that putting something called concepts into C++ is probably byting off more than any committee I know of can chew.)
Computer memory is just fancy paper, CPUs just fancy pens with fancy erasers; the 'net is just a fancy backyard fence.
What follows is all IMHO, of course you are welcome to your own opinion as well.
.. slightly .. but not enough for me to want them. Safer? Well not if you take into account the fact that you are using C++, probably the most dangerous language to work with of all. I'll cast the result of my collection operation manually, thanks.
I've struggled with large C++ codebases on a number of different projects, and while I admit that it is a powerful language, the problem is that there are a half a dozen different ways to do things. The fact that they are trying to give the language even more expressive power is just adding to the amount of rope that we as developers can hang ourselves with.
I yearn for a language which is functionally complete, compiled, small, fast, cross-platform, and oh, NO TEMPLATES PLEASE! Templates/Generics are a blight (a blight I say!) on modern programming -- to say I was pissed when they added them to C# and Java was an understatement. I like my languages without too much syntactic sugar, thanks.
In general, OO programming was never fully grokked by the masses. People spent far too much time trying to make their objects re-usable, and not enough time solving the problem at hand. At least with a language like C you are not fooling yourself, you can write in a procedural style and be happy.
Don't get me wrong, C has a lot of short-comings as well. D is almost perfect, but again, the template blight has reared its ugly head.
I know, a lot of people love templates, and they will argue that they are faster, or they are safer because of type-safety. Faster? Maybe
Plus, you make the compiler work really hard, and your project now takes 40 minutes to compile instead of 5. Thanks for the productivity gains, but no thanks!
f u cn rd ths, u r prbbly a lsy spllr.
Do you realise that most of the guts of Windows is actually written in C++? And that the secretary of the C++ Standards Committe, Herb Sutter, works for Microsoft?
Are you even a C++ developer at all?
Yes, I am a C++ developer, and I'm watching C++ languish on Windows. Half of the new stuff Microsoft comes out won't even work with native code any more. Where's WPF bindings for native C++? Or how about WCF? All of the new technology initiatives are based on .NET.
Sure, Microsoft might be on the committee, and sure Microsoft might be adding a few features to Visual C++, but that's not where the company is headed.
This is my sig.
I think you're overstating things a bit. It's certainly true that Concepts would have been an improvement, and would have made life a whole lot easier for a whole lot of people -- but let's face it, "renaissance" implies that we're currently in a dark age, and that's overstating things quite a bit. Point one, there's pretty substantial work being done right now. Point two, concepts are not going to allow an average programmer to just decide that they're going to recreate something like Spirit or Proto or Xpressive this afternoon, or anything like that.
:-)
I also the think "petty politics" is going overboard, at best. Howard Hinnant seems to have been the one who started the discussion at the last meeting that ultimately led to the removal of concepts from the draft standard -- and I find an accusation of his being involved with petty politics completely unbelievable. Quite the contrary, the (admittedly few) times I've talked with him, he struck me as a very level-headed person who was careful to evaluate ideas on their merits. Likewise, Beman Dawes, Bjarne himself, and (since you brought him up) Dave Abrahams don't seem to me exactly "petty politics" kinds of people either.
I'd also note that when it came to a vote, the overwhelming majority of committee members voted to remove them -- including (for one example) Douglas Gregor, the primary author of ConceptGCC, and one of the coauthors of both N1758 and N1849 (the two versions of the Indiana Proposal).
I think the vast majority of the committee simply believed that including concepts would delay the standard by a minimum of a couple years, and probably longer than that. A fair number of features originally intended to be included in C++0x have been removed for exactly the same reason, though quite a few others have localized enough effects that they're currently scheduled for a TR (Technical Report) rather than waiting for the next major update to the standard itself. Unfortunately, since they make fundamental changes to the type system, I don't think concepts can be added in the same way.
*(Dave - I mean that in the nicest sense... you've done a great job with Boost (oh, we need to jam again, too)).
I object your honor. Everybody knows a proper blues guitarist is short and fat, with black hair and a scraggly beard -- and this "Dave" is about as different from that as humanly possible!
The universe is a figment of its own imagination.
Sure there is. I do it just fine.
See Boost.ConceptCheck for example (for now, the quality of the error messages is not very good, but I'll improve that whenever I have the time to do so). Instead of writing "requires SomeConcept<T, U...>" you write "BOOST_CONCEPT_REQUIRES(SomeConcept<T, U...>)" or "BOOST_CONCEPT_ASSERT(SomeConcept<T, U...>)" (depending on whether you want it in the signature or not).
This is not fundamentally different and it does extensive type checking that is quite useful to find errors in generic programs.
Currently, generic programming in C++ is supported through a number of template meta-programming patterns and practices, most of which exist as Boost tribal knowledge
No.
Meta-programming is not generic programming. Templates were meant strictly for the latter, but the fact that templates are Turing complete makes possible the former.
The interviewer's questions did lack some tact and diplomacy, but they also contained some good insights that Stroustrup dismissed out of hand just because they weren't phrased in a politically-sensitive way.
To my mind, Stroustrup is focussed more on maintaining a good diplomatic position than on producing a good language. The "best" C++ language is not the one that causes the least friction in the committee.
And he is completely and utterly unable to see C++'s continued descent into becoming an unlearnable language.
Maybe he needs to experience first-hand the collapse of a few commercial projects and the loss of time, effort and money through C++ complexity in order to shake up his wishful thinking a bit. Perhaps he's too close to the coal face to see the larger picture. Complexity causes failure.
Programming in the large isn't about being clever. It's about being unclever, and hence producing maintainable code. That hasn't yet sunk in for our dear Bjarne.
"The question of whether machines can think is no more interesting than [] whether submarines can swim" - Dijkstra
In any case, streams are a really poor example (or good, if you are after spreading FUD) - it's the single worst thing in terms of size of compiled code (and performance, actually) in the entire C++ standard library.
There are programs that do nothing but call one method in this "single worst thing". C++ primers tend to push such programs as the first example of C++ code that someone ever reads.
You do C++ programming and cannot use templates? How's that? Broken compiler/linker? A boss with irrational fears of anything younger than fifteen years? I cannot see any other reason; fear of code bloat is not a valid reason to ban /all/ templates,
not even in tiny embedded systems.
Note that templates isn't all about metaprogramming voodoo. It's also about some very simple, straightforward uses: small utility functions and classes which can make plain old C++ code more readable.
Because we do not do generic programming. There is no need of it. There is no need to go beyond the capabilities of a simple macro for the stuff I do.
Tesla was a genius. Edison however was a overrated hack who liked to torture puppies.
Programming in the large isn't about being clever. It's about being unclever, and hence producing maintainable code. That hasn't yet sunk in for our dear Bjarne.
Let's imagine that poor deluded Bjarne follows your advice, sees the light, and realizes that C++ is a complicated mess. What would you have him do at that point? Lobby the C++ committee to strip out all the "difficult" features for the next version of C++, thereby creating a language called "C++" that nevertheless is incompatible with 80% of the C++ code that exists in the world, and guaranteeing that either nobody ever uses the new version, or that the C++ world gets forked into two opposing camps?
Perhaps there is something you haven't realized yet as well -- that "learnability" is far from the only issue to consider when trying to improve a widely-used language. I think Bjarne is well aware of the many trade-offs that have to be made, and he has valid reasons for his decisions. But don't let that interfere with your armchair psychoanalysis.
I don't care if it's 90,000 hectares. That lake was not my doing.
Now, we damn well know that, barring memory corruption or a serious bug in the STL, that this won't overrun the boundaries of the container. So why should i be range-checked ten million times?
It shouldn't. If the compiler, rather than the template library, knew about subscript checking, it could optimize much of it out. Most subscript checks in FOR loops can be hoisted out of the loop. Only a single check at loop entry is required, and that may resolve to a constant expression which is always true, eliminating the test entirely. Most C compilers today know how to hoist expressions and do basic strength reduction; that's why, for loops, pointer arithmetic and subscripts generate almost the same code in modern compilers.
But because the language doesn't know how big arrays are, the compiler can't help out here.
This is another price paid for papering over the problem with templates.
Modern languages need to be more flexible than c++. I have lost count of the number of companies I have contracted for who desperately struggle to make c++ a Functional, Array based language. They should use www.jsoftware.com (an APL) instead. That is the language of the future.
"which says nothing about the size of the array. Right there is the cause of most buffer overflows - the language doesn't properly support talking about the size of arrays." - by Animats (122034) on Friday August 07, @02:49PM (#28989075) Homepage
It's not that hard to determine the size of an array though... even in C++!
HOW TO DETERMINE ARRAY SIZE/LENGTH, USING TWO POINTERS (1 is always DOUBLE the size of the other, 1st "++" vectors thru array, other is always double its size):
----
1.) Make 2 pointers, starting @ the "Zeroeth array element" position (the start, in other words)
2.) Advance the first by/to 1 & then, double the size of the 2nd pointer (to 2 in other words)
3.) Then, advance the first one to 2, double the size of the 2nd pointer (to 4 in other words)
4.) Continue this, always advancing the first pointer ++ by 1, & keeping the 2nd pointer DOUBLE ITS SIZE... do this, until the 2nd pointer can no longer advance... THIS YIELDS THE ARRAY's MIDPOINT!
5.) Simply doubling the midpoint will yield the total # of array elements, & thus, its size...
----
THAT'S HOW YOU CAN DETERMINE THE SIZE OF ANY ARRAY (or string) AND ITS LENGTH/SIZE - this "generic algorithm" works for that!
APK
P.S.=> AND, w/out using functions like StrLen (strings.h), for string lengths in NULL strings or otherwise (strings are, after all, nothing more than "Character Arrays" anyhow)... apk
A few points because I have also had to deal with those warnings:
Microsoft wrote and forced through that standard.
At the time they wrote it, other solutions like strlcpy were FAR more popular, and still are, yet they ignored them and purposely wrote an alternative with different behavior and the argument order rearranged.
The behavior of truncating the destination buffer to an empty string on error is quite useless and can destroy data in the strcat replacement.
They produce the "unsafe" warning for strncpy, which actually is not any less safe then their alternative.
They do not produce the "unsafe" warning for thousands of other calls that can overwrite buffes, only mysteriously for a subset that happens to be in the cross-platform library.
They produce the "unsafe" warning if you use any kind of macro to make _snprintf be called "snprintf" but don't do this if you directly call their function and thus have an unportable program.
Microsoft wrote and forced through that standard.
I've seen other company names backing it. Do you have any references to back up the "forcing it through" claim?
Besides, the spec was made by WG14, which are the same guys that make the ISO C standard itself. It's not the phony OOXML committee - it actually has balanced representation from various C implementors (including e.g. Apple and IIRC someone from RedHat to speak for gcc) - pushing something through would be damn hard unless you manage to convince committee members that it's a good idea - but then it isn't really "pushing" anymore, is it?
At the time they wrote it, other solutions like strlcpy were FAR more popular, and still are, yet they ignored them and purposely wrote an alternative with different behavior and the argument order rearranged.
I haven't seen any code using strlcpy on Win32 in my practice. For that matter, I've heard that it doesn't have high acceptance on Linux, either. In any case, the design goals of strcpy_n are different from strlcpy.
The behavior of truncating the destination buffer to an empty string on error is quite useless and can destroy data in the strcat replacement.
The idea of those functions isn't to do any sort of auto-truncating, as e.g. strncpy or strlcpy do. The idea is to catch constraint violations immediately. Which is why the correct usage is to set a runtime constraint violation handler immediately upon the start of the program that will complain noisily and terminate - the same kind of behavior you get from varions string methods in Java or C# when you use out-of-bounds indices and such. In fact, the spec provides abort_handler_s precisely for that purpose. Note also that the default behavior on constraint violations is implementation defined: "The implementation has a default constraint handler that is used if no calls to the set_constraint_handler_s function have been made. The behavior of the default handler is implementation-defined, and it may cause the program to exit or abort." - the clear intent here is to use some standard error-reporting facilities, such as the usual exception/error crash report dialog on Windows. So, normally, you wouldn't ever see that truncated buffer.
They produce the "unsafe" warning for strncpy, which actually is not any less safe then their alternative.
strncpy does not always null-terminate, which is extremely error prone - it's why strlcpy was made, after all!
They do not produce the "unsafe" warning for thousands of other calls that can overwrite buffes, only mysteriously for a subset that happens to be in the cross-platform library.
Examples?
I know for sure that a bunch of Win32 functions were similarly "deprecated" for the same safety reasons, and strsafe.h devised as a replacement.
They produce the "unsafe" warning if you use any kind of macro to make _snprintf be called "snprintf" but don't do this if you directly call their function and thus have an unportable program.
I just tried this, and I don't get a warning regardless of whether I call _snprintf directly, or "#define snprintf _snprintf" and then call snprintf. I don't see how the behavior you describe is possible at all, since "deprecation" warning modifiers are applied directly to function definitions, and VC headers simply don't contain a definition of snprintf.
As for why _snprintf doesn't produce a warning - it looks like a bug of omission, and not something deliberate. It is properly documented as "deprecated as unsafe" in MSDN, and other similar functions, such as _vsnprintf, do produce the warning.
strlcpy does indeed return a clear "failure" result, because it returns the length of buffer that would be needed. This can be tested on the return value, and also provides information on exactly what needs to be done by the program to fix it.
Here is an example of how to use it, as some people do not seem to understand strlcpy at all. No other function design lets you do this. (in case you don't understand this, please assume this is a function that needs to be very fast and that the programmer knows that 99.99999% of the time the string is less than 200 characters):
func() {
char localbuffer[200];
char* bufferpointer;
int n = strlcpy(localbuffer, x);
if (n > 200) {
bufferpointer = new char[n];
strcpy(bufferpointer, x);
} else {
bufferpointer = localbuffer;
do_something(bufferpointer);
if (bufferpointer != localbuffer)
delete[] bufferpointer;
}
This is immensely more useful than strcpy_s and strncpy.
strlcpy is used in Linux, thousands and thousands of times. It is also used in Windows software just as much. The fact that Ulrich Depper hates strlcpy does not give an excuse for Microsoft. Yes there are asshats in Linux but that does not mean you can't complain about them also being at Microsoft.
Actually _snprintf *DOES* produce a warning, unless they changed things more recently. My mistake. We did have some problem with macros but the switch to turn off the warnings did work for all of the interesting ones. There was some warning about the use of varargs that was unavoidable but is a different bug in vc++.
The default behavior for the strcpy_s error handler is to return, with the buffer truncated. Since programs don't change this (and they can't if any library routines are relying on the behavior) then any theoretical advantages you list are moot.
The default behavior for the strcpy_s error handler is to return, with the buffer truncated.
First of all, the default behavior in the spec is implementation defined (I've already quoted the relevant part in my previous post). Any code that relies on any particular behavior without setting its own handler (or ignore_handler_s) is simply broken. Any library that relies on any definite behavior is even more broken, as the whole purpose of the thing is to let the application override this behavior. Libraries should not assume that they will ever get control back if they try to overflow the buffer, but should also check return values for error codes as specified (in case the current behavior is to return control).
Simply put, all *_s functions are supposed to work the same way preconditions generally work in Design by Contract. It is caller's responsibility to ensure that precondition holds; the point of the check in the callee is not to work around this fact and somehow "fix" it (e.g. by truncating), but to immediately report the contract violation so that caller can be fixed.
As for default VC behavior specifically, I've just tried this on VC9 and VC10:
It doesn't quietly return with buffer truncated. Rather, it produces a debug assertion with a message "Buffer is too small", and if you ignore that (or if you compile in release mode, so assertion doesn't get compiled in), it launches the usual Windows fatal error reporting procedure (Watson), which asks to attach the debugger if one is registered on the system, and terminates the process otherwise. Note that the latter happens even if compiled in release mode.
The standard docs pretty clearly state that the default error hander does nothing and returns to the function, and that the strcpy_s function truncates the buffer and then returns after the error handler returns.
http://www.open-std.org/jtc1/sc22/wg14/www/projects#24731
I never actually tried calling these things as I want to write portable software.
Anyway I don't see how a DOS is much better than a buffer overflow.
The standard docs pretty clearly state that the default error hander does nothing and returns to the function, and that the strcpy_s function truncates the buffer and then returns after the error handler returns.
Okay, let's try this again. Here is the most recent draft. Look at 6.6.1.1 "The set_constraint_handler_s function", paragraphs 2 and 4. Here's what it says:
2 The set_constraint_handler_s function sets the runtime-constraint handler to be handler. The runtime-constraint handler is the function to be called when a library function detects a runtime-constraint violation. Only the most recent handler registered with set_constraint_handler_s is called when a runtime-constraint violation
occurs.
4 The implementation has a default constraint handler that is used if no calls to the set_constraint_handler_s function have been made. The behavior of the default handler is implementation-defined, and it may cause the program to exit or abort.
And also 6.1.4 "Runtime constraint violations":
2 Implementations shall verify that the runtime-constraints for a function are not violated by the program. If a runtime-constraint is violated, the implementation shall call the currently registered runtime-constraint handler (see set_constraint_handler_s in ). Multiple runtime-constraint violations in the same call to a library function result in only one call to the runtime-constraint handler. It is unspecified which one of the multiple runtime-constraint violations cause the handler to be called.
3 If the runtime-constraints section for a function states an action to be performed when a
runtime-constraint violation occurs, the function shall perform the action before calling the runtime-constraint handler. If the runtime-constraints section lists actions that are prohibited when a runtime-constraint violation occurs, then such actions are prohibited to the function both before calling the handler and after the handler returns.
4 The runtime-constraint handler might not return. If the handler does return, the library function whose runtime-constraint was violated shall return some indication of failure as given by the returns section in the functionâ(TM)s specification.
I hope this is clear enough. I expect that you've just looked at the individual description of strcpy_s, and didn't find anything about runtime violations; but the paragraphs cited above apply to all functions for which there's a "runtime constraints" section.
I never actually tried calling these things as I want to write portable software.
But you do use strlcpy. I don't see how this is any different - in both cases, if you want to be portable, you have to use a third-party implementation on all platforms where this functionality isn't available out of the box (as neither is included in the base standard for the language). And yes, there is an independent, open-source (MIT license), cross-platform implementation of TR 24731 - the Safe C Library.
Anyway I don't see how a DOS is much better than a buffer overflow.
Well, it's obvious - a buffer overflow is a potential high-risk security exploit, while a DoS is just a DoS.
Anyway, the philosophy is that if there is a problem in your application, it should be made obvious as early as possible. With strlcat, there are all kinds of interesting possibilities - perhaps someone used it but didn't check the error code, and, in fact, didn't bother to handle the truncation case specially at all. Depending on the circumstances, this may lead to a crash or other form of DoS down the line (e.g. when trying to parse the buffer expecting well-formed data, since it was already validated before the call to strlcat), but worse, it may lead to silent wrong behavior - imagine trun
I certainly did read 6.1.4.4, which is why I thought the default behavior was for the error handler to return. Certainly the description of strcpy_s implied that it returned because it spent some time describing exactly the value it returned.
In any case I think you are underestimating the problem with the buffer being truncated to zero length. In your rm example, it is certainly plausable that it will now remove the ENTIRE DISK, because "" may be the name of the root filesystem. If you don't believe this, try looking at real code, concatenating a slash is really common. I greatly prefer the strlcpy result where the chances of hitting an actual filename are somewhat lower.
I also think you are missing the fact that the DOS is likely to happen when the program is in use and that it could be far worse than the buffer overflow. The buffer overflow will probably crash, and may not be exploitable. The DOS is GUARANTEED to happen.
The biggest problem is that everybody seems to ignore the fact that strlcpy returns a clear error indicator that contains useful information and that it is useful for actual fast code. If you are unconcerned about speed it is nonsense to use char* pointers at all, use some safe string object, this is another reason why I think warningsencouraging you to replace strcpy with some other slightly safer call is wrong, as it justs wastes programmers time when they should be doing a true replacement, or figure out how to use strlcpy correctly.
Anyway, none of my complaints is about the _s functions, except they seem to be typical crap designed by committee. My complaint is about Microsoft putting warnings into their code to try to force people to alter it to be non-portable, that is pretty insidious and inexcusable.
In any case I think you are underestimating the problem with the buffer being truncated to zero length. In your rm example, it is certainly plausable that it will now remove the ENTIRE DISK, because "" may be the name of the root filesystem.
Quite likely, but if I'm going to use the *_s functions, I'd set up my own handler anyway which would ensure no-return (and thus the whole issue of what the buffer ends up with is moot).
I also think you are missing the fact that the DOS is likely to happen when the program is in use and that it could be far worse than the buffer overflow. The buffer overflow will probably crash, and may not be exploitable. The DOS is GUARANTEED to happen.
Well, that's kinda the point - as I mentioned earlier, I'd rather very much have any (potentially) incorrect behavior like that signaled ASAP, rather than it continue to run silently. In that sense, I wouldn't actually mind strlcat if it was called strlcat_trim_to_fit or something like that. But for plain concatenation, I don't want it to second-guess me.
The biggest problem is that everybody seems to ignore the fact that strlcpy returns a clear error indicator that contains useful information and that it is useful for actual fast code. If you are unconcerned about speed it is nonsense to use char* pointers at all, use some safe string object, this is another reason why I think warningsencouraging you to replace strcpy with some other slightly safer call is wrong, as it justs wastes programmers time when they should be doing a true replacement, or figure out how to use strlcpy correctly.
I can actually agree on that - strlcpy is clearly handy in that it lets one avoid the extra strlen call for when allocation is needed (as one has to do with strcpy_s). And I definitely consider all these solutions to be very much deficient, and the proper way to tackle this is to ditch null-terminating strings entirely and use ones with explicit length, a la Pascal/Java/C#. Extra 4 bytes are well worth the added convenience, it's much safer (as you always know the lengths in advance, and can always allocate exactly as much as needed without overhead of scanning the string to figure it out), and it can often improve performance as well, depending on what is done with the string. I consider both strlcpy and strcpy_s to be the last resort measures.
Ideally, of course, I'd just write the whole thing in C++, and use the string classes.
My complaint is about Microsoft putting warnings into their code to try to force people to alter it to be non-portable, that is pretty insidious and inexcusable.
It should be noted that warnings aren't actually displayed by the compiler itself by default (i.e. "cl foo.c" with no compiler switches will not give "deprecation" warnings). The reason is that it's actually a level-3 warning - the default is level-1. Visual Studio does set warning level to 3 by default, however, so VC++ projects created in it display this.
On the other hand, the error message, while confusingly using the term "deprecated", clearly indicates that this check can specifically be turned off, and even explains how:
warning C4996: 'strcpy': This function or variable may be unsafe. Consider using strcpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
Even so, it could definitely explicitly mention that the proposed strcpy_s alternative is not ISO C/C++ conformant, both in the error message text, and in the documentation for it.
the proper way to tackle this is to ditch null-terminating strings entirely and use ones with explicit length, a la Pascal/Java/C#. Extra 4 bytes are well worth the added convenience, it's much safer (as you always know the lengths in advance, and can always allocate exactly as much as needed without overhead of scanning the string to figure it out), and it can often improve performance as well, depending on what is done with the string.
A big advantage you forgot to mention is that all possible byte values (ie 0) can be put into the string.
Pascal (for most of it's history, at least) used 1-byte counts so the string length was limited to 256 bytes. Until about 1990 it seems nobody thought it logical to waste 3 bytes storing the length, so everybody saw the choices as either limiting string length to 256 or not allowing nul, and everybody chose the latter.
On current machines it makes perfect sense to use a length. If you want to save memory and have so many small strings that the space wasted by the length makes a significant difference, you can save far more memory by using either a hash table (because you must have lots of duplicates) or some cryptic compressed encoding.
One advantage C strings have however is that the operation "return the tail of the string" is O(1). This is not true for any other string representation. This does not sound like a big deal but a lot of software depends on it for speed and this has derailed previous attempts to rewrite things away from C strings or into other languages.
So that's 11K for the C++ version
Using iostream and other space-intensive C++ library features makes sense if you can rely on the presence of a shared library implementing the C++ standard library as part of the platform. But because PCs running Windows and embedded systems generally do not include a copy of shared GNU libstdc++, it would have to be distributed with each program, either as a .dll or statically linked into the executable. How big is libstdc++.so.* on your system?