The best thing that has happened in the last years is not having to depend on C++ anymore
Good changes, but too little, too late.
Of course, we still depend on it, but for an ever smaller set of use cases. Do what you have to do and "get out of there" as fast as you can to your favourite language.
Agreed. Many bad trends emerged in the industry in the last decade, but today I am happy I can afford not to write C++ anymore. And yes, I did say afford there.
Excellent wording. My employer cannot afford my team to write c++ either. It takes way too long to yeah each person the language features. C++ is awesome for seasoned developers but it tak s years to get there. Cannot wait for rust.
The examples remind me again why I turned away from C++ some years ago.
In the first years of C++ it was real joy to write software in it but now the syntax seems to be much more useful for obfuscation rather than maintainability.
Funny: When C++ began Ada 95 looked like a giant animal. Now Ada 2012 looks small and efficient in comparison although it is more powerful than Ada 95.
The point being systems programming languages die if not sponsored by the OS vendors, because they have to fight for mindshare among the so called business languages.
In Ada's case, the high cost of development systems, rise of UNIX use in the enterprise, decline of Pascal based languages.
All contributed to it being used in its field of origin (avionics) and systems where security and human life are of utmost importance.
In Europe there was a rise of Ada projects due to lack of security in the usual C and C++, but these are always specialized projects, like train systems control and such. Not the typical Show HN applications.
I would like to see Ada being more used in the industry, but sadly it won't happen.
Ada is available for Windows, Linux, OSX and ARM. GNAT/GCC is part of many Linux distros (usually Ada95). You can also download Ada2012 and Ada2014 compilers and tools from Adacore's website.
> Decline of Pascal based languages.
Ada looks a bit like Pascal but the language is far superior. In my opinion Ada's syntax makes software easier to maintain than C/Java like syntax. Even after years I have no problem to read into Ada code. C++ code can be difficult to read just after a short time.
I think the real reason of Ada's decline is that it requires a lot of discipline of the developer. The same kind of discipline is required in Haskell. You cannot just sit down and code. You have to think a lot about your design before you hit the first key. Most developers don't like this, they want quick (and dirty) solutions, and they get it with C and C++.
Back when we had to buy compilers for anything we wanted to do.
Ada compilers and hardware requirements were too complex to target home computers, which we were mostly coding in Assembly for performance and space reasons.
On the computer systems able to use Ada compilers, they were either running UNIX or some other mainframe OS.
Maybe you don't know that Rational Software first product was a Ada Machine in the same vein as Lisp Machines, but with Ada.
On the UNIX systems when you bought the SDK, there was only C compiler there, latter C++ as well. Getting Ada meant shelling out for an extra compiler, now get business to pay for it.
Mainframes like VMS were a bit more friendly to Ada, but if I remember correctly, still you need to pay for each language separately.
So it doesn't matter where Ada is available today, but how its use since the early 80's progressed.
Now it has to fight against established languages. Its use has been increasing in Europe (check FOSDEM Ada talks) mainly thanks to C and C++ security exploits and GNAT Core OSS efforts, but it is a slow progress.
It is a different type of safety. Algol type safety, that C designers didn't care when creating the language rather leaving it out to lint.
You cannot directly compare Ada with Haskell just on safety as they use different paradigms.
Anyway, just from the top of my head:
- Bound checked arrays
- Real strings
- Reference parameters
- Real enumerations without implicit conversions to numeric data types
- Type definitions are real types, not synonyms like C's typedef. Just like Haskell's newtype.
- Ability to define type ranges for enumerations and numeric types
- Subtyping
- Generics
- Explicit type conversions required among numeric types.
- Contracts, Eiffel style
- Pointers by default are always valid, unless your are doing unsafe code.
In terms of performance, there are ways to enable unsafe code, if you really really need it, but like other memory safe systems programming languages you need to be explicit about it.
A plus feature over Haskell is that currently the Ada has primitives for hardware access. The guys doing HaLVM and Home had to add extensions to Haskell.
For what types of applications do you think it's actually important to use the native language of the OS? After all, non-native languages can have bindings for the OS APIs. In your opinion, what are the drawbacks of mostly avoiding C++ and using one's favorite language, as the GP said?
If you're developing a fairly complex library for things such as image processing, machine learning, numerics, linear algebra, etc., then I think that C/C++ is the way to go. Most languages have some sort of FFI to interact with C, many are even designed explicitly to work with C (such as Cython). C++ is in a similar situation (though compiler support on esoteric processors such as DSPs is still not quite there yet), and it's fairly easy to get a C-compatible API.
If you write your library in Perl, guess what, only people writing Perl will use it. If you write it in Java, well, maybe the Scala folk will wrap it up, or the Jython folk, but you won't get any people writing in Ruby to use it. If you write it in C++, you can provide efficient bindings to any of those languages.
For an example, look at FFmpeg or ImageMagick. They are libraries that just _won't die_, no matter how hard people have tried. My god, ImageMagick was written in 1987, and it now has Haskell bindings[0]! The only way to get that sort of longevity (and old code is good code, after all [1]) is to write in language that will outlast the ups and downs of the language or framework du jour, and C and C++ have proven to have that staying power. Yeah, they're terrible; I hate them. But there is a reason to use them.
- Not able to use the OS vendor tooling which only support the official languages
- Another layer to debug (FFI)
- Possible loss of performance when crossing the FFI barrier
- Loss of productivity, because that cool API isn't available and so one has to write it
- Writing drivers, daemons/services, OS plugins, ...
One of the reasons I moved from Turbo Pascal to C++, when I started coding on Windows 3.0, was being fed up to write binding libraries by myself. Although I really enjoyed Turbo Pascal back then.
I can confirm that writing bindings is a big time sink. One of the biggest projects I've worked on is a Win32 application that's primarily written in Lua. I chose Lua because of the small interpreter and minimal standard library; a project requirement was to keep the download size small. But I spent a lot of time writing my own Lua bindings for Win32 APIs. Maybe that just means I should have used a more mainstream alternative language like Python, but even in Python-based Windows projects, I've sometimes had to drop down to ctypes, Cython, or the like. In recent years I've wondered if I would have been better off using C++ in a modern style, with smart pointers, string and container classes, etc. Then I would have had direct access to all Windows APIs, plus access to all of Microsoft's tools.
This is still a matter of opinion. My favorite language is still C++.
This is of course personal preference, but also mostly because I realized (and it seems to me that some people haven't, just go around and ask what is C/C++, and people will tell you it's one language...) that C++ is not just anymore "C with classes", and the fact there is C-ish, or even just bad C++ code out in the wild doesn't make the language bad in itself (it can still be less appropriate/completely irrelevant for some applications, which is fine).
True, with STL and the recent changes the "C with classes" thing gets more distant.
But sorry, I don't miss the includes, the huge class hierarchies, the template madness, etc
C++ is good if you stick to a strict code standard and don't let people "go crazy" with it.
But the thing is that good languages end up limiting the amount of "bad code" that naturally emerges. (Java does it through lack of flexibility and enforcement, I prefer the Python and Go way)
> With the addition of generic lambdas, I can define a single lambda with generic parameters. Although the syntax doesn't include the keyword template, this is still clearly a further extension of C++ generic programming
So what are the nuances when comparing this approach to using a template to create a generic function? Aside from stylistic differences, would using one over the other affect compile time or runtime performance in any (meaningful) way?
It just makes it easier to read the magnitude of a number and get that extra visual reassurance that it's correct. It's not easy to (quickly) tell the difference between 1 billion and 100 million unless you count zeros (1000000000 vs 100000000). On the other hand it's very easy to discern 1'000'000'000 vs 100'000'000.
The standard can't use commas as a separator because using commas vs periods to demarcate components is locale specific. Apostrophes look like a reasonable compromise because lots of calculators already use apostrophes to separate digits:
The "already an operator" can be a factor in the design reasoning but if they really really wanted to, they could have made the comma syntax for digit separators by modifying the parsing grammar: e.g. a special prefix and/or contextual parsing.
For example, the "->" was already an operator for pointer indirection but it was reused for lambda definitions. The "[]" was already used for array subscript indexes but was reused for lambda captures.
You can't do that for ",", because it will break the existing code.
For example, int x = 0; x = 1,2; is perfectly valid pre c++11 code. This will assign 1 to x. Now if you make "," as digit separator, it will assign 12 to x
I mentioned the possibility of a special prefix in my previous post. In other words, that parsing ambiguity goes away if the standards committee wanted to define a special prefix such as 'd', 'k', or '_' to inform the parser that the next comma is a "digit separator" instead of "comma operator" such as _1,000,000 . E.g. there's already intelligence about commas in the parser to disambiguate function calls with commas as in "repositionxyz(914,348,122)"
Or, they could have defined C++14 to simply invalidate your example syntax of "x=1,2". As an example, the "auto" keyword was made a "breaking change" such that "for (auto int i = 0;;)" no longer compiles.
The bottom line is that there are a myriad of ways to address (potential) parsing ambiguities when introducing new language features and syntax. (Whether or not a comma digit separator is worth the clumsier syntax of a special prefix or inflicting the pain of a breaking change is a separate concept.)
C++ doesn't have the friendliest grammar for addressing potential parsing ambiguities.
As an example, your proposed solutions
_1,000,000
k1,000,000
Both are already valid if variables or functions _1 or k1 are in scope, and evaluate to (octal) zero.
And I haven't checked, but it would guess that invalidating "x=1,2" in the parser would not be "simple". I cannot think of a reason, but it also might turn out to be more common then one would think due to macro expansions.
User-defined literals can't generally start with a digit, so it should be perfectly fine to allow 1_000_000 syntax for 1000000. Or I'm forgetting something?
I would've gone with spaces. Those are the official standard here in Canada as a pragmatic compromise between anglos and francos that have opposing usage of comma/dot.
So instead of 1,234.56789 (English) or 1.234,56789 (French) we do 1 234.56789 (international)
[0-9]+ [0-9]+ has no meaning in C++, so using space for magnitude decorations would have worked.
Briefly, but I think there are like three people in the world that fully grok C++ grammar, and I'm definitely not one of them. I just know that C++ generally has some kind of infix operator or delimiter between pairs of immediate data or variables, I'm pretty sure it's currently just a compiler error in every case.
I think 'auto' may become a brain-drain like const-ness already is. You try to use it in one place - and it ripples throughout your base classes and libraries. It may be useful in some narrow set of situations (templates? lambdas?) but beyond that it remains to be seen.
You should look at "Back to the Basics! Essentials of Modern C++ Style" talk from Herb Sutter at CppCon 2014[1]. You'd have a great insight on why 'auto' isn't just some kind of "convenience" keyword and why it matters.
Oh I see it can matter. But it may become intractable. Using 'const' matters, but few achieve it - even std library methods rarely use it for immutable arguments, so if I try to use const I end up casting to non-const to call down.
Thanks for the link! Now I know what to tell my students next time. C++ is the language of choice for recognition systems development anyway, and with C++14 it's actually starting to become beautiful.
> The biggest problem are the pre-C++98 codebases or the ones full with C idioms instead of modern C++.
Thanks for pointing that out. THIS is the real problem of C++. Not the language spec (though it can and has to be improved with time), but those codebases, which incidentally make perfectly sane people go nuts about C++... :)
I disagree very strongly with the argument presented there - in fact, I think it provides enough rope to hang itself.
It says:
1. With deduction you always get right type
2. Deduction guarantees no implicit conversion will happen
From this we can conclude that "the right type" never involves an implicit conversion. This is false: see vector<bool>::operator[], or consider the fact that auto allows you to make a variable of a type you cannot name explicitly (i.e. is private), which is surely not "the right type!"
> For example, if a function has multiple return paths, they need to have the same type.
> ...
> [Code sample that returns -1 or record->id]
> Instead of using an integral type to identify the person in the record object, maybe I have a new GUID type. Making that change to the record object will cause a series of cascading changes in things like the return types of functions. But if my function uses automatic return type deduction, the compiler will silently make the change for me.
Yet when this happens, his example function can now return -1 or a GUID, so compilation should fail, no? Haven't worked with C++ in awhile so I might just be missing something on this, but seems like a contradiction to me.
No, the return type can change as long as all return paths return the same value for the same function call. So you can't, in the same execution, return two different types, but two different executions can vary their return type as long as its consistent.
The point is that -1 is not a GUID, though, so in the sample function, if record::id changes to a GUID, the find_id function is now trying to return -1 (an integer) and ii->id (a GUID).
I'm not sure if implicit conversions are applied to type deductions. It could be that GUID has a constructor that takes in an integer, which would mean that if the function were declared with a return type of "GUID", returning -1 would be fine. I don't know if the same applies to functions with "auto" as the return type, but the example with the int and the double suggests not. So, this is a long-winded way of saying "yes, I think it's a bug".
Using 'auto' for return types seems just awful to me. In the context of a collaborative project, I don't want to have to dig through the implementation of someone else's function just to figure out what type it returns. Having an explicit return type is a form of self-documenting code.
Sure, auto probably shouldn't be used on a function that's part of the exposed API of a library, rather than something internal to the unit of code it is part of.
Its kind of weird to see people complaining about a C++ feature because its not appropriate to use indiscriminately and requires some discipline -- that's historically been pretty much the whole of C/C++.
Of course, using such a function in an expression when
only a forward declaration has been seen is ill-formed:
auto f(); // return type is unknown
int i = f(); // error, return type of f is unknown
Agreed - the popularity of implicit typing is surprising to me. It seems to make code much less readable and comprehensible. In a good IDE I suppose it doesn't really matter because type information could be provided automatically, but code isn't always read in a good IDE.
In fact, with an IDE, this argument is moot. You can have the type anyway.
Then, we do use template parameters already, for which we usually don't know the type. I can't see why we'd bitch about 'auto' and not about the template parameters.
It's just the same thing: coding against interfaces and not implementations.
Template is explicit; auto can sneak under your radar and look like things you already think you know how they work. Any change to the mainstream syntax can be troublesome at first.
A key difference is that we are being told to use auto (but not templates) gratuitously, even when there's only one possible type.
I prefer to make functions ordinary, and only templatize functions that need to operate on more than one type. There's good reasons for this: the compiler is less effective at type-checking templates, they require the function body to be visible, and they may fail to warn you when passed the wrong type.
"auto" suffers from all those problems, and yet we are being told to use it whenever possible. That's bad advice.
Function name and context usually is sufficient to know what SomeIterator refers to, there is no need for horrible STL constructs to try to explain it.
Readability is about how quickly you can figure out what's going on. There are only a few bits of syntax you need to know what's going on in the first example, but it requires mentally matching together the angle brackets correctly, and it emphasises the type over the function name.
In most cases you can scan over the type ('map blah blah...iterator') but that's not reading and in any case will quickly fail you with nested template types, if you're unfortunate enough to have those.
Functions that return iterators are never called getSomeIterator(). Instead they're called stuff like erase(), insert(), or even nonsense words like crend().
And whether a function returns an iterator is not consistent even within the STL:
auto loc = container.find("name");
What type is loc? If container is a std::map, then loc is an iterator. If container is a std::string, then loc is a size_t.
If you had used the explicit iterator type, you would at least get an error message immediately with the above line, instead of hoping your code does something that size_t doesn't support.
Remember this is primarily for non-public facing or complex objects. If you are looking at someones API on github it should not be using auto for return types.
I think in any sane library, public API functions will have declared return types. It's only for small helper functions inside a source file that will be autoed. I agree that misuse of auto is going to be terrible, though.
That's a reasonable position, but the popularity of languages without any type declarations at all suggests that there are many people who don't mind. (python, ruby, etc.)
Having the type be inferred is precisely what omitting a type declaration does in a static language. From the point of view of a pedantic type systems theorist, Python is like having a static language where every variable has the the same type, "Object".
Anyway, they are talking about documentation. Many people think that having to peek inside a function to know what it returns is worse than having a compiler-checked type declaration. In fact, in most languages with type inference there is still a strong convention to write full signatures for all top level functions, as a form of documentation (return type inference is left for lambdas)
I suspect that over time the C++ community will settle on a set of conventions around the use of auto in this context. Much like how passing in a mutable reference is considered a no-no and you're expected to instead pass in a mutable pointer so it's obvious to the caller that you can change the value via the parameter list.
That's not a C++ community convention, it's just another bone headed part of the Google C++ coding standards. It's stupid because now everything is potentially nullable and every single function will start with:
if (!arg1 || !arg2 || !arg3 ...) {
what_I_should_do_here_isnt_really_clear();
I'm not a fan of the "pointer means mutable" idiom either. I feel you should only use a raw pointer type instead of a reference if you want nullptr to be a meaningful value. Value semantics are great.
I'm not a fan of idealism for the sake of idealism. It's practical to be able to tell at the callsite that the parameter can be changed by the function/method.
Yeah, we'll end up with some type of Hungarian notation for function naming. A lot of 'Modern C++' seems to be taking over what is really the job of an IDE, just because the original C++ syntax was so verbose.
Same can be said about using 'auto' for variable type declarations. It all comes down to "use, but don't abuse" (as most things in C++) - it can improve readability, if used moderately; and it is up to the programmer to judge where to use it.
Type inference has been a fantastic blessing for me in C#, so I'll never complain about having to type locals... by extension, implicitly-typed privates seems to make sense. But the public interface of a class? That just feels one step too far.
What if it's a private interface, like a local function? Or a public interface with limited consumers? The language should allow you to write your code the way you want.
Requiring pointless verbosity on some hope that somehow that'll help bad programmers write better code seems like an odd conclusion.
Interesting, could you elaborate on this a bit more?
Say I have a header file "foo.h" with an "auto foo();" declaration. Another file (eg, "bar.h") imports foo.h. How can the compiler do type checking when compiling bar.cc without also parsing foo.cc to determine the return type of foo()?
Note that this can be used for static functions, I don't think anyone would find it in an API documentation. The real reason I see for this is reducing voodoo in template libraries, eg forwarding a call T::something() for a generic type 'T'.
The primary use-case of auto returns is for templated functions where the return type depends on the thing passed in. For example, in C++11 you have to write things like the following:
The return type can't be specified by the function[0], and you have to copy and paste the body of the function into the decltype() clause to tell the compiler that the return type is whatever the thing it's wrapping returns. When you have some long and complicated expression rather than just r.begin() in the body, this duplication becomes a major issue.
[0] In this specific case you could require that Range have an iterator typedef and return that, but that approach does not generalize.
C++ templates used to be the most unreadable code this side of Perl, but with auto and a little documentation you can figure out what's happening fairly easily. Templates (and auto) are typically used when dealing with core libraries and should be documented better than average code anyway.
If someone starts using auto for every variable or returning it from every method, then they need a stern talking-to.
He has some good points, but his perspective seems to be biased by a professional focus on writing libraries and more general-purpose code. He's also brilliant and can remember things like this:
const int& cir = val;
auto h = cir;
//The type of h is int.
It's difficult to make generic rules for how to use C++ (because it's used for everything from adware to nuclear reactors), but I can say that Herb's AAA (Almost Always Auto) rule would not fly on any development team I've ever worked with.
The type of h isn't so hard to understand, there. |auto| gives you a value; if you want a reference, use |auto&|. This rule actually makes |auto| more readable: you always know if you're looking at a reference or not.
Probably you expected |auto| to behave like |decltype()|, C++11's other form of type deduction, which gives you the actual type of an expression. C++14 adds |decltype(auto)|, which lets you declare local variables using this behavior if you want it.
I'm not sure whether I'd apply Herb's AAA rule quite as broadly as he suggests, but I think it's broadly right, because far too often in C++ we write a type twice on the same line, which is just redundant. I vastly prefer |auto val = new MyClass;| to |MyClass val = new MyClass;|, and similarly |auto casted = static_cast<MyType>(uncasted);| is completely readable without typing writing "MyType" a second time. C++ programmers are a conservative lot, but I expect using |auto| at least in those cases to be pretty mainstream within a few years.
If there is a feature that could be misused, it will be misused.
It does not matter what the rationale behind the committee's decision was. This is standard practice in duck typed languages, and it will be adopted as well in C++, since it will be (imho, correctly) perceived as another step to bring C++ "to the 21th century".
You can stern-talk as much as you wish... but it won't have much effect unless backed up by an (effectively enforced) internal code style guide.
The barbarians are already at the gate. Which side are you going to pick?
> This is standard practice in duck typed languages
Only because there is no choice in those languages -- and, in those language communities, there's considerable call for finding a good way to include optional explicit and enforced declared typing specifically so that a choice does exist.
So, even given that communities that (unlike C++, even with auto existing) accept languages that don't provide an alternative to to the equivalent of "auto everywhere" push back against that practice to the extent of seeking language features to provide an alternative to it, I don't think that auto becoming an option is going to mean auto everywhere takes over C++.
There'll probably be some overuse (particularly in a brief period before a widely-accepted conventions on appropriate use are established), but its hardly the most dangerously abusable feature of the C/C++ language family.
If there is a feature that could be misused, it will be misused. It does not matter what the rationale behind the committee's decision was.
This is quite a narrow-minded line of thinking. You're saying "Feature X is should be excluded because of <possible consequence>". But we can say the converse about this same feature: "Feature Y should be included because <possible benefit>". Every programming language feature ever has had its pros and cons, and every language designer makes tradeoffs deciding which features to include and which to exclude.[1]
You also most likely overestimate the practical unreadability of the source code. IDEs are (or will be) smart enough to deduce and display the type of an auto declared variable[2] when you want it. For short functions, it will be blindingly obvious what the auto-declared return type of a function is. Using auto will vastly improve readability by reducing textual noise when a function returns (1) heavily templated expressions, (2) any type within a deeply-nested namespace, (3) any type with a long name, or especially (4) combinations of the previous three (e.g. std::vector::const_iterator< std::pair<std::string, double> >). Complicated types are a common issue in languages with static type systems[3].
I could go on. There are tons of use-cases where auto will help out. The biggest complaint I have is that you can auto-declare the return type of methods that return private variables from a class (unless I'm mistaken; I haven't actually tried it). This pokes leaky holes in your class's encapsulation, forming dependencies between external code and your class's private, internal implementation (although this may be possible through template magic...).
The barbarians are already at the gate. Which side are you going to pick?
Oh, cut the drama. Every language has some sort of a style guide, and C++ programmers are already used to following a style guide and programming with discipline. One more feature with a few downsides and a number of benefits is not going to make a difference, and is totally in line with its philosophy[1].
IDEs are (or will be) smart enough to deduce and display the type of an auto declared variable[2] when you want it.
Not to detract from your other points, but personally I wouldn't want to live in a world where my IDE is decided for me. A person sometimes has decades of experience with their text editor. Forcing them to use a different one just to do programming isn't necessarily the best idea.
Interesting question: Will the world benefit from a language that requires an IDE to program in? I can imagine how the answer might be "yes," but also other scenarios where it might be "no."
"Relaxed requirements for constexpr" is an item that I wish would have gone into C++11. Once have you multiple code paths and need to loop over variables constexpr functions get really unreadable.
One thing the C++ standard library IMO needs is a range library, e.g. something like Boost Range. I often would like to use the "range-for" but when I am not looping over all the elements of a container its useless in that case.
constexpr was already difficult to implement (much more difficult than originally thought). As far as I understand, the committee wanted to be conservative in scope in case a limited constexpr could serve the needed use cases without being an limitless source of compiler complexity and bugs.
I agree about the range library, but it will be difficult to impossible to implement in the standard library without concepts. 2020 could be the year of range algorithms.
Since we already have the iterator algorithm defined, there is no room for a range algorithm name 'sort' with two template-deduced parameters. There are workarounds using enable_if, but they're hairy and involve basically recreating concepts at the standard library level.
Herb Sutter:
"I’m hopeful that the standard library will get range-based overloads of all standard algorithms that are enable_if’d to avoid the problem or can use concepts if those make it into a future standard."
Actually, the compiler can distinguish between sort(Range, Pred) and sort(Iter, Iter). This is a C++98 feature, partial ordering of function templates. Basically, if you call sort(range, pred) then the sort(Iter, Iter) overload will be ignored (since template argument deduction can't succeed - Iter can't be two different types). If you call sort(iter1, iter2) then both overloads are viable, but sort(Iter, Iter) is preferred - partial ordering determines that it matches a strictly smaller infinite universe of types.
This is also why C++14's dual-range algorithms didn't lead to ambiguities: equal(InIt1, InIt1, InIt2, Pred) versus equal(InIt1, InIt1, InIt2, InIt2) has the same structure.
(Obviously if you have a type that is both a range and a predicate, then it's ambiguous.)
I'm not a fan of having attribute tokens like [[deprecated]] written between brackets instead of using the keyword normally like a regular attribute. It smells awfully like C99's _Bool and _Complex, which were created to support legacy code but ended up being an ugly headache.
Can we expect to be able to write our own attributes (to be ignored by tools that don't understand what they mean), or will we get compiler errors/warnings there?
So now I need an emacs package that can parse my c++ and can replace all instances of the auto keyword with their actual types. That way I can develop quickly using auto but I can keep the code maintainable by having full type signatures.
Normally I feel the c++ standards committee has great ideas, however this is not one of them. If you want templated lambdas then you should use templates.
> At this point you can get a free copy of the draft proposal here. Unfortunately, when the final standard is published, ISO will have it paywalled.
Since when was a language spec put behind a paywall? I can't comprehend the reasoning behind this, given that open source compilers exist for C++. How much is it to view the spec? Why do they need to charge at all?
ISO has always charged for its standards, which made more sense when they were distributed on paper. It's especially goofy for C++ as the (latex) source code for the final version of the standard is on Github now, so the only thing that's paywalled is the "official" pdf version.
Template variables are really interesting. I had a similar idea years ago, as a bit of "wouldn't it be cool if..." speculation, but never expected to see it in C++.
string c = a + b; // creates temporary object that is copied into C by value - the temporary is just a 'full copy'; so that for the temporary it needs an extra allocation and strcpy and free.
the fix is to add the following to the string class
string(string &&r)
{
...
}
string &operator=(string &&r)
{
...
}
so the operator with the && receives and 'rvalue' reference - which is a special reference to just this temprorary and the implementation of this is supposed to swap the data of the temporary with that of the this object; the temporary is then discarded.
Yes, but the use of auto to auto-deduce the return type is new in C++14, as well as the use of auto as a return type for lambdas to produce generic lambdas - generic functions without having to use template syntax.
142 comments
[ 3.2 ms ] story [ 205 ms ] threadhttp://blog.biicode.com/cpp14/
Good changes, but too little, too late.
Of course, we still depend on it, but for an ever smaller set of use cases. Do what you have to do and "get out of there" as fast as you can to your favourite language.
Yes, Rust looks VERY promising.
In the first years of C++ it was real joy to write software in it but now the syntax seems to be much more useful for obfuscation rather than maintainability.
Funny: When C++ began Ada 95 looked like a giant animal. Now Ada 2012 looks small and efficient in comparison although it is more powerful than Ada 95.
System programming languages need OS vendors support to thrive.
http://www.ada2012.org
Support is provided by AdaCore for instance:
http://www.adacore.com
The point being systems programming languages die if not sponsored by the OS vendors, because they have to fight for mindshare among the so called business languages.
In Ada's case, the high cost of development systems, rise of UNIX use in the enterprise, decline of Pascal based languages.
All contributed to it being used in its field of origin (avionics) and systems where security and human life are of utmost importance.
In Europe there was a rise of Ada projects due to lack of security in the usual C and C++, but these are always specialized projects, like train systems control and such. Not the typical Show HN applications.
I would like to see Ada being more used in the industry, but sadly it won't happen.
Not necessarily.
http://www.adacore.com/press/gnat-gpl-for-bare-board-arm/
Look also for the book "Building Parallel, Embedded, and Real-Time Applications with Ada" by McCormick, Singhoff and Hugues.
Some prominent embedded engineers wonder why Ada is not used much more:
http://www.embedded.com/electronics-blogs/break-points/40082...
> Rise of UNIX use in the enterprise
Ada is available for Windows, Linux, OSX and ARM. GNAT/GCC is part of many Linux distros (usually Ada95). You can also download Ada2012 and Ada2014 compilers and tools from Adacore's website.
> Decline of Pascal based languages.
Ada looks a bit like Pascal but the language is far superior. In my opinion Ada's syntax makes software easier to maintain than C/Java like syntax. Even after years I have no problem to read into Ada code. C++ code can be difficult to read just after a short time.
I think the real reason of Ada's decline is that it requires a lot of discipline of the developer. The same kind of discipline is required in Haskell. You cannot just sit down and code. You have to think a lot about your design before you hit the first key. Most developers don't like this, they want quick (and dirty) solutions, and they get it with C and C++.
Back when we had to buy compilers for anything we wanted to do.
Ada compilers and hardware requirements were too complex to target home computers, which we were mostly coding in Assembly for performance and space reasons.
On the computer systems able to use Ada compilers, they were either running UNIX or some other mainframe OS.
Maybe you don't know that Rational Software first product was a Ada Machine in the same vein as Lisp Machines, but with Ada.
https://www.ibm.com/developerworks/community/blogs/gradybooc...
On the UNIX systems when you bought the SDK, there was only C compiler there, latter C++ as well. Getting Ada meant shelling out for an extra compiler, now get business to pay for it.
Mainframes like VMS were a bit more friendly to Ada, but if I remember correctly, still you need to pay for each language separately.
So it doesn't matter where Ada is available today, but how its use since the early 80's progressed.
Now it has to fight against established languages. Its use has been increasing in Europe (check FOSDEM Ada talks) mainly thanks to C and C++ security exploits and GNAT Core OSS efforts, but it is a slow progress.
Everyone talks up Ada's safety, but they always seem to compare it to other Foogols, like C, C++, and Java/C#.
You cannot directly compare Ada with Haskell just on safety as they use different paradigms.
Anyway, just from the top of my head:
- Bound checked arrays
- Real strings
- Reference parameters
- Real enumerations without implicit conversions to numeric data types
- Type definitions are real types, not synonyms like C's typedef. Just like Haskell's newtype.
- Ability to define type ranges for enumerations and numeric types
- Subtyping
- Generics
- Explicit type conversions required among numeric types.
- Contracts, Eiffel style
- Pointers by default are always valid, unless your are doing unsafe code.
In terms of performance, there are ways to enable unsafe code, if you really really need it, but like other memory safe systems programming languages you need to be explicit about it.
A plus feature over Haskell is that currently the Ada has primitives for hardware access. The guys doing HaLVM and Home had to add extensions to Haskell.
Which happens to be C++, until OS vendors support another one on their SDKs.
So until Ada, Rust, D, Swift, .NET Native or something else get such a position, C++ it is.
If you write your library in Perl, guess what, only people writing Perl will use it. If you write it in Java, well, maybe the Scala folk will wrap it up, or the Jython folk, but you won't get any people writing in Ruby to use it. If you write it in C++, you can provide efficient bindings to any of those languages.
For an example, look at FFmpeg or ImageMagick. They are libraries that just _won't die_, no matter how hard people have tried. My god, ImageMagick was written in 1987, and it now has Haskell bindings[0]! The only way to get that sort of longevity (and old code is good code, after all [1]) is to write in language that will outlast the ups and downs of the language or framework du jour, and C and C++ have proven to have that staying power. Yeah, they're terrible; I hate them. But there is a reason to use them.
[0] http://hackage.haskell.org/package/imagemagick
[1] http://www.joelonsoftware.com/articles/fog0000000069.html
- Another layer to debug (FFI)
- Possible loss of performance when crossing the FFI barrier
- Loss of productivity, because that cool API isn't available and so one has to write it
- Writing drivers, daemons/services, OS plugins, ...
One of the reasons I moved from Turbo Pascal to C++, when I started coding on Windows 3.0, was being fed up to write binding libraries by myself. Although I really enjoyed Turbo Pascal back then.
This is of course personal preference, but also mostly because I realized (and it seems to me that some people haven't, just go around and ask what is C/C++, and people will tell you it's one language...) that C++ is not just anymore "C with classes", and the fact there is C-ish, or even just bad C++ code out in the wild doesn't make the language bad in itself (it can still be less appropriate/completely irrelevant for some applications, which is fine).
But sorry, I don't miss the includes, the huge class hierarchies, the template madness, etc
C++ is good if you stick to a strict code standard and don't let people "go crazy" with it.
But the thing is that good languages end up limiting the amount of "bad code" that naturally emerges. (Java does it through lack of flexibility and enforcement, I prefer the Python and Go way)
So what are the nuances when comparing this approach to using a template to create a generic function? Aside from stylistic differences, would using one over the other affect compile time or runtime performance in any (meaningful) way?
I love the rest of the changes, but that just doesn't sit right with me.
The standard can't use commas as a separator because using commas vs periods to demarcate components is locale specific. Apostrophes look like a reasonable compromise because lots of calculators already use apostrophes to separate digits:
https://www.google.com/search?q=14+digit+calculator&source=l...
Dunno why they didn't use underscores though.
For example, the "->" was already an operator for pointer indirection but it was reused for lambda definitions. The "[]" was already used for array subscript indexes but was reused for lambda captures.
Or, they could have defined C++14 to simply invalidate your example syntax of "x=1,2". As an example, the "auto" keyword was made a "breaking change" such that "for (auto int i = 0;;)" no longer compiles.
The bottom line is that there are a myriad of ways to address (potential) parsing ambiguities when introducing new language features and syntax. (Whether or not a comma digit separator is worth the clumsier syntax of a special prefix or inflicting the pain of a breaking change is a separate concept.)
As an example, your proposed solutions
Both are already valid if variables or functions _1 or k1 are in scope, and evaluate to (octal) zero.And I haven't checked, but it would guess that invalidating "x=1,2" in the parser would not be "simple". I cannot think of a reason, but it also might turn out to be more common then one would think due to macro expansions.
I stand corrected.
So instead of 1,234.56789 (English) or 1.234,56789 (French) we do 1 234.56789 (international)
[0-9]+ [0-9]+ has no meaning in C++, so using space for magnitude decorations would have worked.
[1] https://github.com/CppCon/CppCon2014/blob/master/Presentatio...
Can you give some examples of methods in the standard library that should use const, but doesn't?
The biggest problem are the pre-C++98 codebases or the ones full with C idioms instead of modern C++.
Those aren't going away anytime soon.
Thanks for pointing that out. THIS is the real problem of C++. Not the language spec (though it can and has to be improved with time), but those codebases, which incidentally make perfectly sane people go nuts about C++... :)
It says:
1. With deduction you always get right type
2. Deduction guarantees no implicit conversion will happen
From this we can conclude that "the right type" never involves an implicit conversion. This is false: see vector<bool>::operator[], or consider the fact that auto allows you to make a variable of a type you cannot name explicitly (i.e. is private), which is surely not "the right type!"
> ...
> [Code sample that returns -1 or record->id]
> Instead of using an integral type to identify the person in the record object, maybe I have a new GUID type. Making that change to the record object will cause a series of cascading changes in things like the return types of functions. But if my function uses automatic return type deduction, the compiler will silently make the change for me.
Yet when this happens, his example function can now return -1 or a GUID, so compilation should fail, no? Haven't worked with C++ in awhile so I might just be missing something on this, but seems like a contradiction to me.
Its kind of weird to see people complaining about a C++ feature because its not appropriate to use indiscriminately and requires some discipline -- that's historically been pretty much the whole of C/C++.
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n363...:
And https://isocpp.org/wiki/faq/cpp14-language#generalized-retur...:Then, we do use template parameters already, for which we usually don't know the type. I can't see why we'd bitch about 'auto' and not about the template parameters.
It's just the same thing: coding against interfaces and not implementations.
I prefer to make functions ordinary, and only templatize functions that need to operate on more than one type. There's good reasons for this: the compiler is less effective at type-checking templates, they require the function body to be visible, and they may fail to warn you when passed the wrong type.
"auto" suffers from all those problems, and yet we are being told to use it whenever possible. That's bad advice.
map<unsigned int, map<int, vector<string>::iterator> >::iterator getSomeIterator();
or:
auto getSomeIterator();
Function name and context usually is sufficient to know what SomeIterator refers to, there is no need for horrible STL constructs to try to explain it.
std::map<unsigned int, std::map<int, std::vector<std::string>::iterator> >::iterator getSomeIterator();
I believe you don't need the space between the > > any more, since C++11?
In most cases you can scan over the type ('map blah blah...iterator') but that's not reading and in any case will quickly fail you with nested template types, if you're unfortunate enough to have those.
And whether a function returns an iterator is not consistent even within the STL:
What type is loc? If container is a std::map, then loc is an iterator. If container is a std::string, then loc is a size_t.If you had used the explicit iterator type, you would at least get an error message immediately with the above line, instead of hoping your code does something that size_t doesn't support.
Anyway, they are talking about documentation. Many people think that having to peek inside a function to know what it returns is worse than having a compiler-checked type declaration. In fact, in most languages with type inference there is still a strong convention to write full signatures for all top level functions, as a form of documentation (return type inference is left for lambdas)
func_call(&var1);
is most definitely a C++ convention bud, and it has nothing to do with google.
Not only did you need to use the type correctly, but you needed to declare the desire to use a specific type from the get-go.
You have a point there
what you could do is:
return (int)x;
return (YourClass)value;
(then the header and implementation are auto but you still know what the code is talking about
(Or just put the type there as usual)
Maybe such a tool for C++ will also appear?
Requiring pointless verbosity on some hope that somehow that'll help bad programmers write better code seems like an odd conclusion.
An auto return type means the type is inferred from the type of the expression that the function returns, so it's known from that.
Say I have a header file "foo.h" with an "auto foo();" declaration. Another file (eg, "bar.h") imports foo.h. How can the compiler do type checking when compiling bar.cc without also parsing foo.cc to determine the return type of foo()?
To quote:
> Of course, this requires the function body to be visible.
https://isocpp.org/wiki/faq/cpp14-language#generalized-retur...
[0] In this specific case you could require that Range have an iterator typedef and return that, but that approach does not generalize.
If someone starts using auto for every variable or returning it from every method, then they need a stern talking-to.
http://herbsutter.com/2013/06/07/gotw-92-solution-auto-varia...
http://herbsutter.com/2013/06/07/gotw-93-auto-variables-part...
http://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-...
He has some good points, but his perspective seems to be biased by a professional focus on writing libraries and more general-purpose code. He's also brilliant and can remember things like this:
It's difficult to make generic rules for how to use C++ (because it's used for everything from adware to nuclear reactors), but I can say that Herb's AAA (Almost Always Auto) rule would not fly on any development team I've ever worked with.Probably you expected |auto| to behave like |decltype()|, C++11's other form of type deduction, which gives you the actual type of an expression. C++14 adds |decltype(auto)|, which lets you declare local variables using this behavior if you want it.
I'm not sure whether I'd apply Herb's AAA rule quite as broadly as he suggests, but I think it's broadly right, because far too often in C++ we write a type twice on the same line, which is just redundant. I vastly prefer |auto val = new MyClass;| to |MyClass val = new MyClass;|, and similarly |auto casted = static_cast<MyType>(uncasted);| is completely readable without typing writing "MyType" a second time. C++ programmers are a conservative lot, but I expect using |auto| at least in those cases to be pretty mainstream within a few years.
It does not matter what the rationale behind the committee's decision was. This is standard practice in duck typed languages, and it will be adopted as well in C++, since it will be (imho, correctly) perceived as another step to bring C++ "to the 21th century".
You can stern-talk as much as you wish... but it won't have much effect unless backed up by an (effectively enforced) internal code style guide.
The barbarians are already at the gate. Which side are you going to pick?
Only because there is no choice in those languages -- and, in those language communities, there's considerable call for finding a good way to include optional explicit and enforced declared typing specifically so that a choice does exist.
So, even given that communities that (unlike C++, even with auto existing) accept languages that don't provide an alternative to to the equivalent of "auto everywhere" push back against that practice to the extent of seeking language features to provide an alternative to it, I don't think that auto becoming an option is going to mean auto everywhere takes over C++.
There'll probably be some overuse (particularly in a brief period before a widely-accepted conventions on appropriate use are established), but its hardly the most dangerously abusable feature of the C/C++ language family.
This is quite a narrow-minded line of thinking. You're saying "Feature X is should be excluded because of <possible consequence>". But we can say the converse about this same feature: "Feature Y should be included because <possible benefit>". Every programming language feature ever has had its pros and cons, and every language designer makes tradeoffs deciding which features to include and which to exclude.[1]
You also most likely overestimate the practical unreadability of the source code. IDEs are (or will be) smart enough to deduce and display the type of an auto declared variable[2] when you want it. For short functions, it will be blindingly obvious what the auto-declared return type of a function is. Using auto will vastly improve readability by reducing textual noise when a function returns (1) heavily templated expressions, (2) any type within a deeply-nested namespace, (3) any type with a long name, or especially (4) combinations of the previous three (e.g. std::vector::const_iterator< std::pair<std::string, double> >). Complicated types are a common issue in languages with static type systems[3].
I could go on. There are tons of use-cases where auto will help out. The biggest complaint I have is that you can auto-declare the return type of methods that return private variables from a class (unless I'm mistaken; I haven't actually tried it). This pokes leaky holes in your class's encapsulation, forming dependencies between external code and your class's private, internal implementation (although this may be possible through template magic...).
The barbarians are already at the gate. Which side are you going to pick?
Oh, cut the drama. Every language has some sort of a style guide, and C++ programmers are already used to following a style guide and programming with discipline. One more feature with a few downsides and a number of benefits is not going to make a difference, and is totally in line with its philosophy[1].
1: http://en.wikipedia.org/wiki/C%2B%2B#Philosophy 2: http://stackoverflow.com/q/19625115 3: https://github.com/rust-lang/rust/issues/10448
Not to detract from your other points, but personally I wouldn't want to live in a world where my IDE is decided for me. A person sometimes has decades of experience with their text editor. Forcing them to use a different one just to do programming isn't necessarily the best idea.
Interesting question: Will the world benefit from a language that requires an IDE to program in? I can imagine how the answer might be "yes," but also other scenarios where it might be "no."
One thing the C++ standard library IMO needs is a range library, e.g. something like Boost Range. I often would like to use the "range-for" but when I am not looping over all the elements of a container its useless in that case.
I agree about the range library, but it will be difficult to impossible to implement in the standard library without concepts. 2020 could be the year of range algorithms.
template<typename RANGE, typename PRED> void sort(RANGE, PRED);
and
template<typename ITERATOR> void sort(ITERATOR start, ITERATOR stop);
Since we already have the iterator algorithm defined, there is no room for a range algorithm name 'sort' with two template-deduced parameters. There are workarounds using enable_if, but they're hairy and involve basically recreating concepts at the standard library level.
Herb Sutter:
"I’m hopeful that the standard library will get range-based overloads of all standard algorithms that are enable_if’d to avoid the problem or can use concepts if those make it into a future standard."
http://herbsutter.com/2011/10/07/why-no-container-based-algo...
Why concepts then? The concepts version would look like:
template<Range, Comparator> void sort(Range & r, Comparator const & c);
...and the compiler would be able to tell that iterators wouldn't work with this algorithm.
This is also why C++14's dual-range algorithms didn't lead to ambiguities: equal(InIt1, InIt1, InIt2, Pred) versus equal(InIt1, InIt1, InIt2, InIt2) has the same structure.
(Obviously if you have a type that is both a range and a predicate, then it's ambiguous.)
> The primary use-case of auto returns is for templated functions where the return type depends on the thing passed in.
Since when was a language spec put behind a paywall? I can't comprehend the reasoning behind this, given that open source compilers exist for C++. How much is it to view the spec? Why do they need to charge at all?
Anyone know if compilers will support that?
here is an explanation http://stackoverflow.com/questions/6815685/move-semantics-wh...
it is supposed to save extra copies like here
string a("a"); string b("b");
string c = a + b; // creates temporary object that is copied into C by value - the temporary is just a 'full copy'; so that for the temporary it needs an extra allocation and strcpy and free.
the fix is to add the following to the string class
string(string &&r) { ... }
string &operator=(string &&r) { ... }
so the operator with the && receives and 'rvalue' reference - which is a special reference to just this temprorary and the implementation of this is supposed to swap the data of the temporary with that of the this object; the temporary is then discarded.