LWN.net Logo

A look at C++14, part 1

The "Meeting C++" blog looks at some proposed changes to the C++ language to be considered in April. "It is proposed to add a library for pipelines to the C++ Standard, that such a pipeline could be implemented in C++ as such:
    (pipeline::from(input_queue) |
      bind(grep, "^Error") |
      bind(vgrep, "test@example.com") |
      bind(sed, "'s/^Error:.*Message: //") |
      output_queue).run(&threadpool);

(Log in to post comments)

A look at C++14, part 1

Posted Mar 28, 2013 14:28 UTC (Thu) by rriggs (subscriber, #11598) [Link]

It's a little early for April Fool's jokes, isn't it? There's no way you'll ever be able to do something that cool with C++.

If you tell me that the compiler diagnostic on any pipeline error is required to be 20 pages of template instantiations, and that it is impossible for code editors to determine the meaning of such a line before the heat death of the universe, then I might believe you.

A look at C++14, part 1

Posted Mar 28, 2013 16:06 UTC (Thu) by mathstuf (subscriber, #69389) [Link]

I wonder if someone just got jealous from the Haskell libraries such as enumerator, iterator, and pipe. Though they're even more generic (backwards flow and query/response for some). Of course the types in Haskell are scary, so C++ would be even worse. Maybe Boost will do it now...

A look at C++14, part 1

Posted Mar 28, 2013 16:14 UTC (Thu) by tchernobog (guest, #73595) [Link]

Well, it isn't rocket science. You would just need to override operator| () for a std::pipeline class, and add a run () function. Binding the first argument to a function is already in place, look at std::bind and std::function from header <functional>.

It is just a simple monad, with "run" being the execution function for the actions bound through "operator| ()".

A look at C++14, part 1

Posted Mar 28, 2013 20:05 UTC (Thu) by ledow (guest, #11753) [Link]

Rocket science, to a rocket scientist, looks just as simple.

Personally, even the explanation of the "non-rocket-science" is enough to put me off. Seriously, read it back to yourself.

Not saying that it's not simple, or not something you could learn, or even not something that could turn into subconscious mental boilerplate, but damn... programming languages are a language to enable communication with the computer - not to become an isolated language of their own that you have to be an expert to speak with any fluency.

A look at C++14, part 1

Posted Mar 28, 2013 21:39 UTC (Thu) by tchernobog (guest, #73595) [Link]

Nobody forces you to use the whole C++ language (or C++ at all, for that matters; C is there for you, as hundreds of other languages).

But for those of us who understand it, and want to use it, I can't see the damage of having this pipeline thing in the STL. To me, it's a very simple and nifty concept, and I would get a solid implementation of that done in a couple of hours, from scratch. If you don't like it, it's just syntactic sugar over stuff you could do anyway in another, more verbose, way. Or rolling out your own solution; testing is up to you, then.

After all, even Java has a lot of parts that most college students will never touch. RMI, for instance, and the related naming services. But if you need it, it's there (and it's *incredibly* useful for a nice set of problems). Same applies to most languages out there.

I don't see why languages and their associated standard libraries should keep from evolving. To make life easier for some grumpy programmers stuck in the '80?

We develop more complex systems in 2013 than thirty years ago, and static verification is something a lot of us need in the realm of software engineering, so we build the abstractions that enable us to spend a bit more in coding, and much less in QA (which, incidentally, is where real software development costs go).

The matter would be to explain what a monad is to university students, for instance, not holding back progress. Omniscience isn't required to use a language; C++ has many useful subsets for the issue at hand.

A look at C++14, part 1

Posted Mar 29, 2013 2:02 UTC (Fri) by geofft (subscriber, #59789) [Link]

Rocket science is complicated, but plenty of non-rocket-scientists fly airplanes.

The question isn't how hard the language is to implement -- it's how hard the language is to use. This looks straightforward to use, in my eyes.

A look at C++14, part 1

Posted Mar 29, 2013 9:18 UTC (Fri) by Wol (guest, #4433) [Link]

Rocket SCIENCE is easy. Rocket *technology* is hard.

Rocket science is a tube closed at one end, with a supply of two fuels which (spontaneously?) burn when mixed. THAT'S IT!

Rocket technology, on the other hand, is concerned with making sure you don't get too much fuel too quick (explosion) or too slow (rocket doesn't fly), and the controls to make it fly in the right direction, and launch safely etc etc etc.

Rocket SCIENCE is EASY!

Cheers,
Wol

A look at C++14, part 1

Posted Mar 29, 2013 10:29 UTC (Fri) by mpr22 (subscriber, #60784) [Link]

Don't even need two fuels; one can build a liquid-fuel rocket motor that runs by the catalytic decomposition of hydrogen peroxide or hydrazine.

A look at C++14, part 1

Posted Mar 28, 2013 22:35 UTC (Thu) by nix (subscriber, #2304) [Link]

I wrote something similar for C about ten years ago. It is extremely useful, in all sorts of unexpected places. (Just like Unix pipelines are.)

A look at C++14, part 1

Posted Mar 28, 2013 23:47 UTC (Thu) by tpo (subscriber, #25713) [Link]

Pipelines start to be really exciting, when they auto-parallelize their individual stages. If you have that, you can start doing CSP style programming, which spares you a lot of the pain shared state concurrent programming would cause you.

Does your implementation provide nice syntax (via a macro?) and do autoparallelization? I'd would love to see that code... :-)

*t

A look at C++14, part 1

Posted Mar 29, 2013 15:43 UTC (Fri) by nix (subscriber, #2304) [Link]

It didn't provide particularly nice syntax: it just provided a way to chain functions onto the stdin, stdout and stderr (optionally combined) of fork()/exec()ed subprocesses, so it looked like execl() with extra arguments jammed on the start to signify the stdin / stdout / stderr functions (if any: if none, /dev/null got attached to that fd instead). No pretty pipelining unless you invoked the function again in the stdout or stderr functions. But, obviously, the thing was parallelized: it was just pipes under the surface, after all.

This proposal is definitely better than what I hacked up. :)

A look at C++14, part 1

Posted Mar 29, 2013 18:49 UTC (Fri) by guillemj (subscriber, #49706) [Link]

Also for C, there's <http://libpipeline.nongnu.org/>.

A look at C++14, part 1

Posted Mar 31, 2013 14:08 UTC (Sun) by nix (subscriber, #2304) [Link]

That's a nice API. I'll definitely be using that, although its being GPLv3 (not even GPLv2+) greatly restricts the set of projects that can benefit from it...

A look at C++14, part 1

Posted Mar 28, 2013 17:22 UTC (Thu) by hummassa (subscriber, #307) [Link]

This is actually possible today, with C++11...

A look at C++14, part 1

Posted Mar 28, 2013 23:38 UTC (Thu) by tpo (subscriber, #25713) [Link]

* pointer ?

A look at C++14, part 1

Posted Mar 29, 2013 5:26 UTC (Fri) by rriggs (subscriber, #11598) [Link]

It might not be obvious from the tone of my post, but I was being rather facetious. I love C++. But like most C++ programmers, there is a bit of a love/hate thing going on. I love that C++11 rocks. I hate that I cannot yet write C++11 on RHEL. The "experimental" nature of the shipping C++11 compilers and the ABI incompatibility with C++98 libraries on Linux make it a bit of a problem for long-term stability.

Tell me again why GCC had to take on all the ABI breakage with the new standard?

A look at C++14, part 1

Posted Mar 29, 2013 14:09 UTC (Fri) by foom (subscriber, #14868) [Link]

Well, it's actually not broken much, yet. The std::string and std::list classes are still not C++11 conformant right now, and fixing that will certainly cause ABI issues.

Since the change to std::list in C++11 mode was reverted (it was incompatible in 4.7.0 and 4.7.1, reverted in 4.7.2), I've been using C++11 code against C++98 libraries without a problem.

A look at C++14, part 1

Posted Mar 28, 2013 17:59 UTC (Thu) by nelson777 (guest, #90117) [Link]

Ok people got frustrated.
You got 2 options: admit that you are less capable than an average C++ programmer or understand that C++ is a language made by humans for humans and not for some divine creature that has this special powers that makes him understand C++. I hope you choose the 2nd option.
In case you choose it, remember 2 things: you ARE capable of understanding it and using it, if you just have some persistence and not give up in the first frustrations. The effort is rewarding. The power C++ gives to the programmer is second to none.
If you need some begginer material I`ll be glad to point the directions to you.

A look at C++14, part 1

Posted Mar 29, 2013 1:08 UTC (Fri) by HelloWorld (guest, #56129) [Link]

> It's a little early for April Fool's jokes, isn't it? There's no way you'll ever be able to do something that cool with C++.
>
> If you tell me that the compiler diagnostic on any pipeline error is required to be 20 pages of template instantiations, and that it is impossible for code editors to determine the meaning of such a line before the heat death of the universe, then I might believe you.

There's literally *nothing* even remotely complicated going on here. APIs similar to that one can be done even in severely restricted languages like Java (modulo some syntactic details, that is).

A look at C++14, part 1

Posted Mar 29, 2013 19:23 UTC (Fri) by danieldk (guest, #27876) [Link]

In fact, Java 8 has streams, which are fairly similar:

http://cr.openjdk.java.net/~briangoetz/lambda/collections...

Of course, conduits/pipes/... in Haskell are still more elegant ;).

Good grief.

Posted Mar 28, 2013 17:50 UTC (Thu) by oldtomas (guest, #72579) [Link]

Is there an opposite of "syntactic sugar"? Syntactic salt or even syntactic vomicum?

What an ugly language.

Good grief.

Posted Mar 28, 2013 18:31 UTC (Thu) by mpr22 (subscriber, #60784) [Link]

I use "syntactic salt" for what I merely dislike, and "syntactic ipecac" for what I find downright emetic.

Good grief.

Posted Mar 29, 2013 1:32 UTC (Fri) by robert_s (subscriber, #42402) [Link]

The worst habit c++ standards seem to have got into lately has been the

"Ok, new feature: what character haven't we used yet that won't be ambiguous in this context?"

attitude.

"Got it: |"

...

> const type| input. The '|' being a new type qualifier, for input types.

Wonderful.

Good grief.

Posted Mar 29, 2013 5:01 UTC (Fri) by HelloWorld (guest, #56129) [Link]

The | is used in that example as it always was: as an overloadable binary operator. And the reason why it (as opposed to some other operator) was chosen is also clear, it's clearly inspired by Unix shell pipelines. So I don't really follow your reasoning here.

Good grief.

Posted Mar 29, 2013 9:31 UTC (Fri) by oldtomas (guest, #72579) [Link]

Actually I wasn't complaining about the | (still: for me it's not clear whether it's wise to overload operators this way. I mean: overloading + to add complex, quaternions or polynomials would work for me, but this seems borderline). It's mnemonic enough, at least for shell programmers.

I was rather complaining about this (pipeline::from() ... ).run(&threadpool) business. Actually (for me, at least: I know it's a matter of taste), it's the juxtaposition of this very idiomatic | sugar to that very C++ish (...).run(&foo) what conjures up images of Komodo dragons with lipstick on them. Shudder.

Good grief.

Posted Mar 29, 2013 14:07 UTC (Fri) by tchernobog (guest, #73595) [Link]

But that final "run (threadpool)" is exactly the beauty of the whole thing. The pipeline can be stored and ran at a later time; it is an object which retains a closure, and it can be further composed, transformed, etc. before being executed.

This programming style has been adopted in a lot of different languages and situations. Ruby on Rails uses something akin to this with AREL SQL queries. Haskell uses monads and monad transformers everywhere; every program starts in the IO monad and is just the composition of action, that are not evaluated unless needed due to the lazy nature of the language.

This allows, as already explained, for massive parallelisation and memoization, enforcing a good design from the developer to allow for maximum benefit and least effort. Calling:

std::pipeline p = std::pipeline::from (input) | std::bind (sed, "...") | ... | ... ;
run_in_parallel (p);

would be the other less object oriented option, but I'm sorry if I don't see the point.

Good grief.

Posted Mar 29, 2013 11:20 UTC (Fri) by robert_s (subscriber, #42402) [Link]

If you read the article you'd see that my quote was from a different proposal, that of "Pass by const Reference or Value".

A look at C++14, part 1

Posted Mar 28, 2013 21:10 UTC (Thu) by lynxlynxlynx (guest, #90121) [Link]

Anyone else noticed the syntax error in the sed line? I doubt a compiler could catch that bug, so it seems like a disaster waiting to happen.

A look at C++14, part 1

Posted Mar 28, 2013 21:45 UTC (Thu) by FranTaylor (guest, #80190) [Link]

gcc catches problems with static printf strings, why not?

A look at C++14, part 1

Posted Mar 28, 2013 21:47 UTC (Thu) by FranTaylor (guest, #80190) [Link]

and besides, that error will simply explode and cause sed to return -1, which will explode in the developer's face the first time they test their code (developers test their own code in your reality, yes?)

A look at C++14, part 1

Posted Mar 28, 2013 23:42 UTC (Thu) by lynxlynxlynx (guest, #90121) [Link]

Assuming good coverage and excellent sanity checking if the pipes get contructed following user input.

printf syntax is trivial when compared to shell intricacies. Think of all the possible extra expansion and quoting problems this could cause. But yeah, that's mostly for the developer to worry about.

A look at C++14, part 1

Posted Apr 1, 2013 20:49 UTC (Mon) by mathstuf (subscriber, #69389) [Link]

> (developers test their own code in your reality, yes?)

Maybe[1] :) .

[1]http://www.r6.ca/blog/20120708T122219Z.html

Still no fixed template syntax

Posted Mar 29, 2013 13:12 UTC (Fri) by HelloWorld (guest, #56129) [Link]

A major pain point in C++ template programming is the ambiguity between the less-than operator and the opening angle bracket for template parameters. That's what makes the typename and template keywords necessary in all kinds of crazy places.

It's 2013, Unicode has existed for ages and it's time to put it to use. They should allow proper angle brackets (unicode characters U+3008 and U+3009) for template parameters in addition to the conventional syntax.

template<typename T>
typename std::enable_if<T::template foo<42>::value, T>::type bla();
would become
template〈typename T〉
std::enable_if〈T::template foo〈42〉::value, T〉::type bla();
Much nicer.

Still no fixed template syntax

Posted Mar 29, 2013 14:27 UTC (Fri) by DDevine (subscriber, #60717) [Link]

Time to make a template...
Tappa tappa tappa... Oh crap, where's the angle bracket keys on my keyboard?

Code isn't about typography. If you like you could run your code through sed, and the rest of us plebs will use the greater than and less than symbols.

Still no fixed template syntax

Posted Mar 29, 2013 14:49 UTC (Fri) by heijo (guest, #88363) [Link]

Well you could just add keyboard bindings for them (e.g. on RightAlt+lessthan and RightAlt+greaterthan)

Still no fixed template syntax

Posted Apr 4, 2013 13:45 UTC (Thu) by dgm (subscriber, #49227) [Link]

Or you could glue two keys to the side of your keyboard, route the pins through the case to the PCI bus, write a custom kernel module, a driver for X, send patches to Qt and GTK+, and if you care, Microsoft.

Or you could just use < and >.

Still no fixed template syntax

Posted Mar 29, 2013 15:49 UTC (Fri) by tjc (subscriber, #137) [Link]

A major pain point in C++ template programming is the ambiguity between the less-than operator and the opening angle bracket for template parameters.

I agree. Having a language design gaffe like this at the lexical level really makes it a nuisance.

I don't really like source code that requires characters outside the 32-127 range, but if I did, I think my vote would be to use double guillemets, since they visually stand apart from LT and GT.

template «typename T»

I can't say that they're especially pretty.

Still no fixed template syntax

Posted Mar 29, 2013 16:40 UTC (Fri) by HelloWorld (guest, #56129) [Link]

I don't really like source code that requires characters outside the 32-127 range,
Many people don't. Most then complain about how it's hard to type (it's trivial, just add a suitable keyword binding) and how it breaks some tools (they deserve to be broken).

I think this really holds programming languages back. In fact, I think we should go much further than just embracing unicode characters. Mathematicians came up with all kinds of funny notations for sums, integrals, fractions, square roots and all that. The quadratic formula shouldn't look like this: x = -b + sqrt(b*b - 4*a*c)/2*a. It should look like this. And it really annoys me that we still don't have properly readable formulas in our programming languages because some guy in 1970 decided that ASCII was enough. It isn't.

Still no fixed template syntax

Posted Mar 29, 2013 16:57 UTC (Fri) by apoelstra (subscriber, #75205) [Link]

The quadratic formula shouldn't look like this: x = -b + sqrt(b*b - 4*a*c)/2*a. It should look like this.
The image that you linked to was generated by a LaTeX-like language. If programming languages could read LaTeX expressions, they would still be perfectly ASCII-able for those who want it, while others could use smarter text editors.

Still no fixed template syntax

Posted Mar 29, 2013 17:28 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

Yes, why not:
>мойТип тест(КАКАЯ_ТО_КОНСТАНТА);
>if(тест.открыть())
>{
> println("Відкрито.");
>}
BTW, that "i" in "Відкрито" is "i", not "i".

Still no fixed template syntax

Posted Mar 29, 2013 18:10 UTC (Fri) by HelloWorld (guest, #56129) [Link]

What's that supposed to demonstrate? Sure, I have no idea what that code is about. But I wouldn't know what, say, code written in czech is about either, so how does that make things worse for me? Otoh, being able to write code in their native language with the proper alphabet is certainly a boon for slav developers.

Still no fixed template syntax

Posted Mar 29, 2013 20:21 UTC (Fri) by tjc (subscriber, #137) [Link]

Otoh, being able to write code in their native language with the proper alphabet is certainly a boon for slav developers.

Well, maybe not:

http://www.codinghorror.com/blog/2009/03/the-ugly-american-programmer.html

Still no fixed template syntax

Posted Mar 29, 2013 21:02 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

And that's exactly why one should stick to ASCII.

>Otoh, being able to write code in their native language with the proper alphabet is certainly a boon for slav developers.
No it isn't. Code in Russian looks very weird for Russian developers. Besides, Russian is a language with grammar cases and case-neutral identifiers are often very clumsy.

Still no fixed template syntax

Posted Mar 29, 2013 22:15 UTC (Fri) by HelloWorld (guest, #56129) [Link]

> And that's exactly why one should stick to ASCII.
Uh, so one should stick to ASCII because one can screw up with or without unicode characters? Yeah right, that makes sense.

Still no fixed template syntax

Posted Mar 29, 2013 22:18 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

The problem is - I can fix screwups in ASCII.

Fixing non-ASCII code presents several additional and absolutely unnecessary problems. I don't know if you ever had a pleasure of editing code written in an unfamiliar script, but I had. Cut&pasting identifiers can only get you so far before you start crying.

Still no fixed template syntax

Posted Mar 29, 2013 23:08 UTC (Fri) by HelloWorld (guest, #56129) [Link]

> Fixing non-ASCII code presents several additional and absolutely unnecessary problems.
Readability matters, and having keywords in crazy places for reasons that most C++ programmers don't understand doesn't help readability at all.

> I don't know if you ever had a pleasure of editing code written in an unfamiliar script, but I had. Cut&pasting identifiers can only get you so far before you start crying.
You must be really desperate if you need to come up with crazy use cases like that. I never needed to do what you described, nor did 99.9% of developers. Optimising a language for something like that would be insane.

Still no fixed template syntax

Posted Mar 30, 2013 12:36 UTC (Sat) by khim (subscriber, #9252) [Link]

I never needed to do what you described, nor did 99.9% of developers.

Rilly? Let's exclude developers who never worked in the international teams and never had to deal with foreign scripts. Do you still claim 99% of these like Unicode?

Most style guides forbid anything besides US ASCII even in languages where no such limitation exist for a reason. You only need to edit one piece of Java code which has Japanese-specific pieces with names in kanji and Arabic-specific pieces with names in abjad to understand why unicode in programming languages is bad idea (tm). At least if foreign names are transliterated you can least type them (even if you can not always pronounce them), but to even distinguish names in some weird scripts like abjad you need some training.

Even without kanji or abjad it's easy to create extremely hard-to-edit pieces of code. Here is an example:
public class HelloWorld {
  public static void main(String[] args) {
    for (int ⅰ=1;ⅰ<=10;ⅰ++) {
      for (int і=1;і<=10;і++)
        System.out.printf("%4d", і*і);
      System.out.println();
    }
  }
}

It's realtively easy to spot the error (depending on the font in your editor, of course), but if you try to fix it… you'll probably need to use copy-paste and if your piece of code contains not just “ⅰ” and “і” but a straightforward “i” and less straightforward “i” and also “ⁱ” and “ᵢ”, too… then you are in trouble. For java compiler all six are quite different but for programmer some of them may be hard to distinguish and some are impossible to distinguish at all (depending on font).

US Ascii also has couple of pieces where confusion is possible (think "O" vs "0" and "1" vs "l"), but these are well-known and fonts are often specifically designed to distinguish them. With unicode confusion is inevitable: I'm yet to see a font where “і” differs from “i” and often even “ⅰ” is indistinguishable from “і” or “i”.

The whole "let's argue about the taste of oysters with those who actually ate them" just make me sick. Sorry, but I've worked with programs which use Unicode and I most definitely don't want to repeat this experience. Unicode in comments is fine (even if you can not change them in a clean way you can always just replace them with some approximation and if code deal with a nuances of a foreign language then often you need to use a bit of unicode to explain what goes on there), but once Unicode reaches identifiers it becomes a disaster and I shudder to even think about them lever of mayhem when it'll reach the syntax of language itself.

Still no fixed template syntax

Posted Mar 31, 2013 13:57 UTC (Sun) by nix (subscriber, #2304) [Link]

I'm yet to see a font where “і” differs from “i”
FWIW, here, the former (CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I, according to uniname) is differently hinted, so appears slightly different (with more hinting blur) if the patented FreeType bytecode interpreter is turned on. (In my web browser, i FULLWIDTH LATIN SMALL LETTER I is invisible: in my terminals, it's visible since they use a different font, it is visible but ⅰ SMALL ROMAN NUMERAL ONE and ⁱ SUPERSCRIPT LATIN SMALL LETTER I are square boxes. IMNSHO, anyone who uses any of these when programming is a maniac. Even using them in literal strings or translated output is questionable: font coverage for these letters is just too poor.)

oops

Posted Mar 29, 2013 16:14 UTC (Fri) by HelloWorld (guest, #56129) [Link]

Actually, it would become
template〈typename T〉
std::enable_if〈T::foo〈42〉::value, T〉::type bla();
(notice the lack of the template keyword before foo.

Still no fixed template syntax

Posted Mar 29, 2013 16:44 UTC (Fri) by simlo (subscriber, #10866) [Link]

No no no

Keep all code within ASCII!

OS'es for one reason do not agree on how to represent and show other characters.

Still no fixed template syntax

Posted Mar 29, 2013 17:07 UTC (Fri) by HelloWorld (guest, #56129) [Link]

Every decent system out there is able to handle UTF-8 (that's because a system unable to handle UTF-8 isn't decent and should be dealt with by not using it).

Still no fixed template syntax

Posted Mar 29, 2013 17:29 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

My system can handle UTF just fine. It's _me_ that can't handle the full UTF character set.

Still no fixed template syntax

Posted Mar 29, 2013 21:03 UTC (Fri) by tjc (subscriber, #137) [Link]

Keep all code within ASCII!

I think I could get used to this:

template `(typename T)
std::enable_if `(T::template foo `(42) ::value, T) ::type bla();

Still no fixed template syntax

Posted Apr 2, 2013 12:02 UTC (Tue) by hummassa (subscriber, #307) [Link]

Backticks are the evilest ascii chars. :-D

Still no fixed template syntax

Posted Apr 2, 2013 8:53 UTC (Tue) by jezuch (subscriber, #52988) [Link]

Interestingly, early high-level programming languages separated the keyword and identifier namespaces by using e.g. bold or underline for keywords. This way the parser did not get a heart attack if you named your variable "if". (Some later languages dropped the inconvenience of special character attributes and made the keywords all-uppercase. And later still there was C.)

So, another way to fix the '<' ambiguity would be to make the template-initiating angle bracket bold ;)

Still no fixed template syntax

Posted Apr 4, 2013 13:48 UTC (Thu) by dgm (subscriber, #49227) [Link]

That's a bold proposal. Yes it is.

A look at C++14, part 1

Posted Mar 29, 2013 16:12 UTC (Fri) by simlo (subscriber, #10866) [Link]

As a C++ developer I am not too happy hearing about extensions. I like having priority queues or heaps. I had to implement my own. I also like that std::function is part of the standeard now as well as lambda expressions and variadic templates.
But i dislike the all the talk about multithreading. I know it is needed to make programs scale, but 95% of the programs do not need that. The only reason people use threads are due to blocking APIs! To make threads work correctly more low level APIs are often needed.
Instead I do it the UNIX way: split the problem in processes using pipes/sockets, each being single threaded. That way I do not have to worry about locks, and it is far easier to make a deterministic test system.

A look at C++14, part 1

Posted Mar 30, 2013 3:36 UTC (Sat) by elanthis (guest, #6227) [Link]

Threads - when invisible - are super important. No, most programs don't _need_ them, but I rather enjoy when the program I'm running on my modern 8-core desktop does its operations nearly instantly rather than making me wait because at most it's using ~12% of my CPU.

A look at C++14, part 1

Posted Mar 30, 2013 10:38 UTC (Sat) by simlo (subscriber, #10866) [Link]

Most likely the program is not waiting to get CPU - it is waiting for blocking IO. If you have 8 cores, the OS will schedule the other programs to the other CPUs.
Threading is most of the time a hack around blocking API calls. It is very rare that a normal desktop program actually have CPU work for more than one CPU.
And then you forget the cost in programming time and runtime of locking overhead: A single threaded program does not need atomic operations, which can be quite expensive on a multi cored platform. If, for instance, a program uses reference counting (std::shared_ptr), these operations have to be atomic. If you know the program is single threaded, that overhead is not needed. That kind of overhead might make the single threaded program run faster than the multi threaded, which very often can not use all 8 CPUs anyway due to lock contention.

A look at C++14, part 1

Posted Mar 30, 2013 8:44 UTC (Sat) by alankila (subscriber, #47141) [Link]

I suggest that you can't somehow smuggle in multiprocessing without encountering at least some of the hardships you suggest are exclusive to using threads. For instance, if you want to do multiprocessing and communicate using sockets or pipes, you could just as well use a producer-consumer pattern with threads and maintain the level of discipline in your threads that you know they don't need locking because all the resources they need for their work are local to the thread or just immutable.

Multiprocessing has one giant downside that always hits me in practice: the need to serialize and unserialize the datastructures that represent the work items and the results. This is pure overhead. In general the fact that threads can communicate with each other directly is their blessing and curse, but so far the blessings have been much larger to me, so I prefer code based on threads over the other means of achieving concurrency.

A look at C++14, part 1

Posted Mar 30, 2013 11:18 UTC (Sat) by simlo (subscriber, #10866) [Link]

As I see it there are 3 levels of concurrency

1) Use of explicit locks (as in the Linux kernel)

2) Message queues between threads, where data structures are owned by one thread avoiding the need for locks.

3) Messages queues in the form of pipes and sockets between processes.

1) is clearly the hardest to code. In principle it scales well of an unlimited amount of CPUs but it will often it ends up in lock congestion, where every thread waits for a specific resource. There is also a huge runtime overhead in managing the locks and logic around it.

2) and 3) are almost the same. 3) has the downside as you say that everything has to be serialized, which is a (huge) overhead. The upside is that individual processes can crash independently making it a lot easier to debug. You can also use sockets as a debug output, such the system can be inspected while running. 3) also have the possibility to move some of the system to a another machine.

But with a well written framework, where the communication channels are abstracted, 3) can be made into 2) without changing the core application code. No matter if you use 2) or 3), you have to use the same state machines in the application to handle the concurrency problems.

But once the application is written with explicit locks as under 1), there is no way back.

My advice is thus: Start by using 3). With templates and well a well written framework it is really not that hard to avoid threads. Then if the overhead of serialization is too high, merge the processes as in 2).

What I oppose to, is having a C++ runtime assuming it is multi threaded, having the runtime system using atomic operations, when I want to stick to single threaded programs. And what I argue for, is that most people ought to stick to single threaded programs anyway!

A look at C++14, part 1

Posted Mar 30, 2013 17:55 UTC (Sat) by jwakely (subscriber, #60262) [Link]

> What I oppose to, is having a C++ runtime assuming it is multi threaded, having the runtime system using atomic operations, when I want to stick to single threaded programs.

Use a better C++ runtime implementation then, don't argue the rest of us should always have to do things your way.

GCC can be configure with --disable-threads in which case there are no atomic operations used in the runtime. When configured with --enable-threads=posix (on a supported OS) the runtime still doesn't use atomic operations unless the program is linked with libpthread.so so single-threaded programs don't use atomic operations. So I don't really see what you're opposed to.

A look at C++14, part 1

Posted Mar 31, 2013 9:31 UTC (Sun) by simlo (subscriber, #10866) [Link]

What I am opposed to is multi threading!

My experience have shown me that it is the most misunderstood and amused feature in programming. Everybody learn about it in school and think they have to use it and impose it on everybody else. Once a program, framework or API relies on multithreading it is impossible to avoid. But in 95% of the cases the multi threading was complete unneeded if just the API were available in non-blocking versions.

Take Java: when you implement a TCP protocol you have a thread for receive, a thread for transmit and a timer to detect inactivity. Using select() you can do this in one thread avoiding a lot potential race conditions. I have seen instabilities and odd problems popping up in old Java programs due to this.

When using this model in C++ you get into further problems due to missing garbage collector.

In the beginning UNIX user space did not have multi threading. It is mostly a bad habit coming from other OS'es lacking proper processes.

I am not totally against multi threading: realtime system and system with heavy scale able algorithms. But 95% of programs only becomes unstable and much harder to maintain due to threads.

A look at C++14, part 1

Posted Mar 31, 2013 13:59 UTC (Sun) by Cyberax (✭ supporter ✭, #52523) [Link]

I haven't seen real Java apps using separate threads to receive and send data. That's simply stupid in most cases. However, I did see asynchronous servers die under a high load with all but one CPU completely idle.

A look at C++14, part 1

Posted Mar 31, 2013 21:08 UTC (Sun) by simlo (subscriber, #10866) [Link]

Well, as I work with _real_ Java programs (written before select() came to Java), I know it is needed.

For instance: I have some data I have to send to different clients via TCP sockets. Naive solution: Loop through the clients and perform write() on each socket. Problem: If one client is not taking data the write() operation will block halting data for any other client as well.
Therefore I have to make a thread in which to execute write() for each client. And a message queue for each client to get data from the data producing thread(s) to the write thread.
Similarly, the read option is blocking so I have to have a receive thread per client.
And all this is hard to make work in all cases where clients can close the connection, the link is lost or what ever where the different thread are in different states.

On a proper OS (i.e. UNIX) in C++, I can use select() and therefore contain everything in one thread and have a clear picture of my possible states.

A look at C++14, part 1

Posted Apr 2, 2013 4:28 UTC (Tue) by akeane (subscriber, #85436) [Link]

>What I am opposed to is multi threading!

Hooray, finally, a sane voice in the wilderness!

>the most misunderstood and _amused_ feature in programming.

This may be a typo, but yet it is brilliant somehow, I have always regarded pthreads as some evil entity laughing maliciously as some hapless programmer stumbles into it's wake...

If only I had a dollar for every sleep() I have seen to try to push that pesky race condition further into the sunset, and the amount of times I have seen assumptions being made about thread startup time and executions.

Or the nested locks, Oh God, the nested locks!

But back to pipelines in C++, surely the UNIX way would be to write some kind of general program which you could tell the system to take the output of one program and "pipe" it into another. I would call it:

/bin/M*A*S*H

Merry Easter

A look at C++14, part 1

Posted Apr 2, 2013 8:25 UTC (Tue) by jwakely (subscriber, #60262) [Link]

> But back to pipelines in C++, surely the UNIX way would be to write some kind of general program which you could tell the system to take the output of one program and "pipe" it into another.

Shameless plug: http://pstreams.sourceforge.net/

A look at C++14, part 1

Posted Mar 31, 2013 14:04 UTC (Sun) by nix (subscriber, #2304) [Link]

Well, sort of. An awful lot of libraries pull in libpthread just in case they are used with threaded programs. Nonthreaded programs then pull in libpthread transitively, and suddenly get hit with pointless locking overhead even though they will never have more than one thread.

Hell, on my system even ls(1) is linked with libpthread (though that is via librt because of a use of clock_gettime() and will presumably go away when it is rebuilt against glibc 2.17+.)

A look at C++14, part 1

Posted Mar 31, 2013 18:46 UTC (Sun) by jwakely (subscriber, #60262) [Link]

> An awful lot of libraries pull in libpthread just in case they are used with threaded programs.

This is not the C++ runtime's fault though, libstdc++ goes to a lot of effort to avoid locking in non-threaded programs, but sufficiently motivated fools^Wprogrammers can defeat that effort.

If you really need to skin that cat you can build GCC with --disable-threads and use that libstdc++.so

A look at C++14, part 1

Posted Apr 1, 2013 23:03 UTC (Mon) by nix (subscriber, #2304) [Link]

Indeed. Unfortunately, a lot of programmers don't realize they can use pthread locking functions even without linking to libpthread, getting stubs unless something else has loaded libpthread. The total lack of glibc libpthread documentation might explain this :)

(actually, I can't remember if they're stubs or weak symbols. Stubs, I think, so you don't even need to wrap their uses in null checks.)

A look at C++14, part 1

Posted Mar 30, 2013 17:46 UTC (Sat) by jwakely (subscriber, #60262) [Link]

So you like new stuff, but only the stuff you want, and you don't like anything else even if other people want it. Got it.

If you don't like the new threading features don't use them. Sounds like you have no need for them, so it shouldn't be a problem for you.

A look at C++14, part 1

Posted Mar 31, 2013 14:06 UTC (Sun) by nix (subscriber, #2304) [Link]

So you like new stuff, but only the stuff you want, and you don't like anything else even if other people want it. Got it.
This should be called "the user's lament" or something: it is universal. Note that since users often don't know if they'll like something before they try it, predicting this reliably requires not only telepathy but also precognition.

A look at C++14, part 1

Posted Mar 31, 2013 20:58 UTC (Sun) by simlo (subscriber, #10866) [Link]

Before the newest C++ standeard the compiler didn't know about threading. That is it could optimize away as it wanted. Only the OS knew about threading. Now the compiler have to lay out code, which can work in a multi-threaded environment. So unless, I use non-standeard options on the compiler I can't avoid it. Of course you can say the same for exceptions.

I am not against features in libraries: Those I can simply avoid.

I do have as I mentioned above (https://lwn.net/Articles/545352/) a thing against multi threading in general. And now C++ tries to jump the wagon, too.

The good thing about C++ is that it doesn't do much opposite for instance Java. There is no standeard for GUI either. STL is a library of containers and types you can use anywhere on any OS and without an OS (except for file IO).

Of course, to make portable multi threaded programs, wrappers around the OS specific implementations where needed. But then why not wrappers for sockets, serial ports etc?
Or put it another way: Was POSIX not a good enough wrapper?

Before STL and C++ was really not about portability. There weren't even a standeard like int32_t in C++. With threading, atomic types, chrono etc. STL have been given the task of supplying portability.

The thing about threads:
People learn to use threads all over the place. The excuse these days are scale-ability. But very rarely your program can scale anyway. The core reason for using threads is "that is what I am used to" and due to not being used to work with non-blocking IO.

What we need in general (not only C++) is _not_ more support for threading, but non-blocking APIs and a good framework for writing applications using non-blocking IO.

A look at C++14, part 1

Posted Apr 1, 2013 11:43 UTC (Mon) by jwakely (subscriber, #60262) [Link]

> Before the newest C++ standeard the compiler didn't know about threading.

Nonsense, people have been using Pthreads with C++ for decades. The *standard* didn't mention threads, but compilers live in the real world and had to deal with what programmers actually do.

You're making a silly leap from "some people don't use threads correctly" to "I wish noone was allowed to use threads." Luckily you're not actually involved in the standardisation process, you're just whining on the internet.

> What we need in general (not only C++) is _not_ more support for threading, but non-blocking APIs and a good framework for writing applications using non-blocking IO.

There are proposals to add such things to the next C++ standard, because the committee realises not everyone programs the same way and that different tools are suitable for different tasks. Maybe you would benefit from the same realisation.

A look at C++14, part 1

Posted Apr 1, 2013 15:41 UTC (Mon) by tjc (subscriber, #137) [Link]

Thanks for starting the sub-thread on multithreading. I'm not sure if I agree with you or not--I have to think about this more--but it was very interesting.

A look at C++14, part 1

Posted Apr 1, 2013 23:05 UTC (Mon) by nix (subscriber, #2304) [Link]

Before the newest C++ standeard the compiler didn't know about threading. That is it could optimize away as it wanted. Only the OS knew about threading. Now the compiler have to lay out code, which can work in a multi-threaded environment.
I commend to you Hans Boehm's Threads Cannot be Implemented as a Library.

A look at C++14, part 1

Posted Mar 29, 2013 23:43 UTC (Fri) by cry_regarder (subscriber, #50545) [Link]

The Polymorphic Allocators one has me excited. It is frustrating that I can't assign a string to a string defined with an allocator. This makes it somewhat unnatural working with items stored in boost::interprocess segments.

Cry

A look at C++14, part 1

Posted Mar 30, 2013 0:43 UTC (Sat) by Cyberax (✭ supporter ✭, #52523) [Link]

That's one thing that's long overdue. Allocators are really badly designed - containers among other things expect allocators to be stateless, so swapping two strings in different shared memory segments is impossible to do correctly, according to the Standard.

A look at C++14, part 1

Posted Mar 30, 2013 17:44 UTC (Sat) by jwakely (subscriber, #60262) [Link]

No, "according to the Standard" containers do not expect allocators to be stateless. The weasel words allowing them to assume allocators are equal were removed for C++11 and the new propagation traits and scoped allocator model make it well-defined what happens when two containers with non-equal allocators interact.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds