
An empirical study on the impact of C++ lambdas and programmer experience - uaaa
http://dl.acm.org/authorize?N03390
======
porges
> After instructions, participants were given printouts of sample code they
> could refer to while solving tasks. Group Lambda got code of a C++ program
> using lambda expressions and group Iterator received code of the same
> program written using iterators. They then had time to study the samples
> before starting the tasks and could refer to these samples later.

These samples do not appear in the paper, so we don't know what they saw.

The “iterators” discussed are Java-/C#-style iterators, not C++ ones (as I
expected reading the abstract).

In a C++ context I would have expected lambdas vs iterators to be something
like:

    
    
        // lambda
        float retVal = 0;
        std::for_each(mb.cbegin(), mb.cend(), [&](item x) { retVal += item.price; });
        return retVal;
    
        // pure iterator
        float retVal = 0;
        for (auto it = mb.cbegin(); it != mb.cend(); ++it)
        {
            retVal += it->price;
        }
    
        return retVal;
    

... and the first would be better off as:

    
    
        return std::accumulate(mb.cbegin(), mb.cend(), 0f,
            [](float acc, item x) { return acc + x.price; });
    
    

I think the need to use ref-capture (since you only get a side-effecting
`std::function` to play with in their sample) would be the thing most likely
to throw people off – as it’s something that should be avoided in most code,
anyway ;)

~~~
MaulingMonkey
Yeah - from what I can see, neither interface looks like idiomatic C++.

EDIT: Looks like you beat me to the punch on some of these ;)

Instead of:

    
    
      float getSum(marketBasket mb) {
        float retVal = 0;
        // Implement solution here
        // ---------
        marketBasket::iterator iter = mb.begin();
        while (iter.hasNext()) {
          retVal += iter.get().price;
          iter.next();
        }
        // ---------
        return retVal;
      }
    

I'd rather see real SC++L compatible iterators (as hopefully taught) and saner
naming:

    
    
      float getSum(marketBasket market) {
        float sum = 0;
        // Implement solution here
        // ---------
        for (marketBasket::iterator item = market.begin(); item != market.end(); ++item) {
          sum += item->price;
        }
        // ---------
        return sum;
      }
    

And instead of being pre-provided with a function <void(item)>, if I'm reading
the pdf correctly:

    
    
      float getSum(marketBasket mb) {
        float retVal = 0;
        // Implement solution here
        // ---------
        function <void(item)> func = [&](item theItem) {
          retVal += theItem.price;
        };
        mb.iterateOverItems(func);
        // ---------
        return retVal;
      }
    

I'd rather see:

    
    
      float getSum(marketBasket market) {
        float sum = 0;
        // Implement solution here
        // ---------
        market.for_each([&](item theItem) {
          sum += theItem.price;
        });
        // ---------
        return sum;
      }
    

Or venturing into the far more functional style, where lambdas start to shine
for me, personally:

    
    
      float getSum(std::vector<item> market) {
        // Implement solution here
        // ---------
        return std::accumulate(market.begin(), market.end(), 0.0f, [&](float sum, item theItem) {
          return sum + theItem.price;
        });
        // ---------
      }
    

It looks a bit better in C# where your selection of standard functions is a
little less anemic and a little nicer to use:

    
    
      float GetSum(MarketBasket market) {
        // Implement solution here
        // ---------
        return market.Sum(item => item.Price);
        // ---------
      }

~~~
duneroadrunner
"Idiomatic" doesn't necessarily mean better. I think objectively it's hard to
argue that "item != market.end()" is superior to "iter.hasNext()". The latter
accurately reflects the programmer's intent, while the former specifies an
unnecessarily specific (and poor) implementation of the intent. First of all,
using something like "market.cend() != const_iter" instead is arguably better
practice (imagine you unintentionally omit the "!"). But programmers shouldn't
need to consider whether the iterator is const or not when they just want to
know if the loop is done. Also, consider the case where the vector is being
modified (items inserted or deleted) inside the loop. It might be problematic
either way, but "item != market.end()" is particularly bad in that situation.

Shameless plug:
[http://duneroadrunner.github.io/SaferCPlusPlus/#msevector](http://duneroadrunner.github.io/SaferCPlusPlus/#msevector)

~~~
asveikau
> I think objectively it's hard to argue that "item != market.end()" is
> superior to "iter.hasNext()"

Until you realize the purpose of the weird syntax in the former.

Namely: you can write algorithms where an iterator is a drop-in replacement
for a simple loop through all items in an array via pointer arithmetic, if you
write it to take a start and an end iterator as templates.

Plus said algorithm can take sub-ranges instead of requiring it to loop
through all items.

I thought c++ iterators were very strange for many years until I understood
this and other rationales.

~~~
duneroadrunner
Ah yes, that makes total sense. I suppose those that would like a nicer
interface can just implement one on top. Like the proposed array_view<> and
span<> interfaces.

------
byuu
Context always matters. I use lambdas sparingly in my applications, except for
one _major_ area: user interfaces.

I can't begin to stress what a huge timesaver it is being able to bind a
button's callback to a quick lambda instead of having to bind a callback to an
std::function, add the function to the class header, and then put the actual
button-click code somewhere else in the project in a separate function ... and
then repeat that process for a large UI with hundreds of widgets.

It's not even the initial extra typing, it's having all the code right where
it's most relevant instead of scattered around everywhere and having to name
all of these callback functions.

~~~
spacelizard
Yeah I think this is the real win - the examples in the paper don't really
cover any of the real reasons why someone would use functional programming.
The places that I've used C++ lambdas a lot are callback-heavy code, i.e.
things with a lot of asynchronous I/O, multi-threading, etc.

While I don't doubt the validity of the argument that it takes longer for a
programmer to write correct lambda code in C++ (I have been using them since
C++11 was released and still forget the capture list syntax sometime), it's
not much more than an academic exercise to take some iterator-based code and
replace it with higher-order function calls. It's unfortunate that all the
tasks seem to be based around doing that though. I do think it is still
reasonable to do this in C++11 once you know how - with -O1 turned on you can
get basically the same code spit out using std::transform, std::accumulate,
std::for_each, et al, as you would using a for loop.

It's also unfortunate to note that, at least in g++ and clang, there is still
significant advantage to using lambdas over std::function and std::bind.
Lambdas typically end up being faster in both compile-time and run-time, and
end up generating less code. For these reasons I've found myself using them a
lot more, especially anywhere I would have done some type of currying. This I
do miss somewhat, but it's still leaps and bounds ahead of something I would
have written in C++03.

~~~
byuu
> It's also unfortunate to note that, at least in g++ and clang, there is
> still significant advantage to using lambdas over std::function and
> std::bind.

I have to say, std::bind is just a travesty. It's so difficult to bind a
member function pointer that takes multiple arguments to an std::function.

I wrote my own so that you can do this with just: function<void (int, int)> f
= {&Class::func, &object};

Source is here:
[http://hastebin.com/raw/kobudabasa](http://hastebin.com/raw/kobudabasa)

In doing so, it becomes clear there's basically two ways to implement this
idea:

1\. you allocate heap space to perform type erasure. This results in a pointer
indirection plus a virtual function call worth of added overhead. Along with
tremendous costs to allocate and destroy the function objects.

2\. you store a big chunk of raw memory inside the function<> class, and cast
it as necessary to a pointer. This is actually what I did prior to C++11 and
lambdas. It was tricky because the size of member function pointers is
undefined. Having a vtable makes them larger. So for that I made a complex
dummy class to pull its sizeof info.

Option 2 is definitely a good bit faster (at least for
constructing/copying/reassigning/destructing them), but you're really butting
up against undefined behavior and abusing the language. And capturing lambdas
would be even more challenging.

But even with that, yeah, you can't ever really beat concepts that are native
to the language like lambdas and virtual functions themselves. Compilers can
get really clever and inline things in a way that's exceedingly unlikely to
ever occur with std::function, no matter how you implement it.

~~~
ambrop7
I've also written my own "version" of function but intentionally lightweight,
for an embedded project:
[https://github.com/ambrop72/aprinter/blob/master/aprinter/ba...](https://github.com/ambrop72/aprinter/blob/master/aprinter/base/Callback.h)

Callback<void(int, int)> f = APRINTER_CB_OBJFUNC(&ThisClass::function, this);

One magic thing is that the macro is just a value, it figures out the type
itself.

There's zero memory allocation. The Callback class just contains a function
pointer and a void pointer. So you can't bind argument values other than the
object pointer, but I have no need for that.

------
GeneralMayhem
This is ridiculous. C++ lambdas (and std::function) don't replace iterators
except for the most fervent disciples of the Church of Haskell. They replace
single-function interfaces in cases where you would have had to put together a
custom struct that did exactly the same thing as a lambda with capture but in
about 15 more lines.

~~~
noobermin
To be fair, the most fervent disciples of the Church of Haskell would use
Haskell I'd think :)

I only scanned the paper, but I get the impression the title was chosen
specifically to grab attention. "An empirical study comparing the use of C++
lambdas versus C++ STL iterators and programmer experience" wouldn't get eyes
on their presentation, and eventually, being posted to HN...well, it would,
but they'll surely get more reads/downloads this way.

Clickbaiting for conference proceedings, who would have known.

~~~
jytqtrrrrr
Such a title wouldn't be right, either. Their poor iterators don't seem to act
like real iterators.

------
emcq
The paper seems to mainly compare iterators vs lambdas. This seems like a bit
of a strawman; the best use of lambdas is beyond iterators.

For example, consider callback heavy asynchronous code. A promise library with
lambdas is much easier to write and read than the equivalent state machine.

I would go as far to say any mechanism where function chaining is useful, such
as the nice data to mark/SVG abstraction used in D3, and also in promise
libraries, has advantages with lambdas. Not only do you avoid having to write
extra classes or methods, but the code is more succinctly logically grouped
together, requiring fewer indirections to get to the transformations
occurring.

~~~
alfalfasprout
Basically anywhere where you would have used a callback in C code could
probably benefit from a C++ lambda. It's easier to see what's going on, you
don't litter your code with hundreds (or thousands) of tiny functions, and the
compiler can easily inline everything. The fact that you can capture whatever
you need makes it super easy to use inside a class if needed (eg; you need to
access class members).

It seems really dumb to me to declare that lambdas are detrimental to novices
when it's clear they have a great deal of utility outside of something like
replacing iterators.

~~~
eksemplar
I'd much rather have a lot of smaller functions with single responsibilities,
but then being middle management I worry about things I didn't when
developing.

I need the code to be SOLID, I need the time to market to be as small as
possible and I need to be able to replace any developer with any developer on
a moments notice.

When students don't know lambdas you're costing me money by using them,
because you made the training process longer.

~~~
silasdavis
I'm glad I don't work for you...

~~~
criddell
I think I understand why turnover is such an issue. The reluctance to invest
in your people is a little baffling.

------
nice_byte
I'm a professional and you can take the lambdas out of my cold, dead hands.

Also, their examples are removed from reality. I've never seen people use
lambdas like that. Most of the use cases I've seen are callbacks that get
triggered on certain events (i.e. "display notification when background
loading thread completes") and predicates (i.e. find_if). I see neither in
their examples.

~~~
jonstewart
Of course students had problems—-it's one more damn thing for them to learn
about C++, likely from professors that don't know it very well either. But
<algorithm> is way more useful these days, and boost::asio is a dream.

~~~
pjmlp
Unfortunately most teachers aren't like Kate Gregory, and I fully agree with
her, they should stop teaching C -> C++.

Already in 1994 it was obvious to me that it leads to bad unsafe code and
worse, the mentality to micro-benchmark each code line.

~~~
alfalfasprout
There's pitfalls to everything. I find that a lot of people that only learned
C++ end up writing nice-looking safe code that's very well organized but has
awful memory usage and dubious performance characteristics. It's not that
they're bad programmers or made poor algorithmic choices. It's that they've
been indoctrinated with the fear of "premature optimization". Moreover, they
don't really know any better if they do have optimization opportunities.

On the flip-side, the C programmer who starts out learning C++ will often spit
out some hideous abomination that uses no namespaces, consists of obscure
function names, pointers everywhere, and tons of callbacks.

Thing is, sometimes performance really matters. A large part of the HN
audience focuses only on web-oriented programming. But in scientific
computing, finance, etc. being able to squeeze out a few more operations/CPU
cycle can be incredibly important.

I think rather than being dogmatic about the issue, as programmers tend to do,
it's important to introduce students to C but be very clear about why you
might want to use some of its features vs. relying on the safer C++ variants.

~~~
72deluxe
Out of interest, I never learned C but went straight to C++. What in
particular about C++ makes you believe that you'll write memory hogging
programs?

~~~
alfalfasprout
Specifically, the STL has a lot of slow containers that people readily use.
For example, a beginner might see a std::map<T> and think "wow, a handy hash
table class!". First off, it's not a hash table (usually a RB tree). Second,
the closest thing to a hash table in the STL (std::unordered_map<T>) is still
pretty slow.

Then there's std::string. Super nice in 95% of cases but can cripple an
application if you have millions of strings you need to deal with (TONS of
dynamic memory allocation).

And then there's std::shared_ptr. Super convenient but potentially a huge
impact if you have items with very short durations in hot loops.
std::unique_ptr on the other hand has no added overhead. Sure, you can look
these things up. But it's not really obvious.

C++ is an incredibly useful language. It's far from the safest, prettiest,
etc. But when used properly it's a very powerful tool. But knowing C can help
you to better understand when you're not getting something for free and when
undefined behavior can rear its ugly head.

~~~
72deluxe
I see, interesting, thanks. I suppose the same problems arise attempting to
use STL algorithms instead of using algorithms that are better suited to a
specific container, eg. std::set::find instead of std::algorithm::find.

Being aware of what is happening and the best tools for the job I suppose! And
knowing the STL inside out and its idiosyncrasies and foibles.

------
flohofwoe
Title of the research paper should be "C++ is not Haskell", but snark aside, I
find C++11 lambdas useful to replace old-school callback code (of course only
if callbacks make sense in a situation) because:

\- if local variables need to be captured, the code is much less noisy than
using the old std::bind mess

\- non-capturing lambdas also work for C-style function pointers, and in this
case the generated code is very efficient (no std::function object created
under the hood)

If you're aware what happens under the hood (...that in most cases a
std::function object will be created, which in turn might do a dynamic memory
allocation to hold captured variables), lambdas are a useful syntactic sugar
and one of the more useful additions in C++11 (IMHO).

~~~
ahmedtd
I'm pretty sure that most uses of lambda don't involve creation of
std::function (and thus dynamic allocation and virtual function calls).

As long as you maintain the distinct type of the lambda, any captures (by
reference or by value) will just be fields in a stack object.

------
delegate
The only true conclusion of this study is that students find C++ a bit
intimidating.

Which is not surprising at all, because C++ is a very complicated language !

It takes _years_ , even _decades_ before you can master this language - even
then you probably won't be using all of its features.

Back in the day, it took me a long time before I could truly grasp the C
strings and pointers in general.

Yes, I could write code with pointers and C strings (new char[length + 1] and
delete[] str; were my buddies!), but sometimes I was programming with my eyes
closed and fingers crossed, because the implications of sharing raw pointers
were too complex, especially if threads were involved.

Same with these new features. They may 'look' more modern due to the updated
syntax, but the underlying concepts that they are hiding still need to be well
understood.

So not surprising that students struggle with getting it right the first time.
The good news is that with a bit of experience this becomes easier, as with
anything else..persistence is key.

~~~
72deluxe
Yes C++ is complicated and yes students struggle with programming. It takes
years to understand how to put a decent program together (separation of data,
logic and transport etc).

As for your guesswork with C-style strings, you should have been using
std::string and using copy constructors to pass work into a thread (eg. who
owns the data the thread is working on?). With modern things you can move the
data into the thread instead of copying it.

I would recommend students working on their own personal projects as a good
pasttime as it further helps anyone understand how to write a decent program
and learn the language. Also, tell them to read Stroustrup's book.

~~~
delegate
I started programming back in the day when every programmer wrote his own
String class :).

Standard library was, for one reason or another, unpopular back then. Or maybe
because of the C Windows API and later MFC, which came with its own CString
class...

~~~
72deluxe
Add to the confusion CString, BSTR and std::string and std::wstring. What
could go wrong?

------
partycoder
Some people feel comfortable expressing things in a more traditional way, in
part, because you cannot change the habits built over the course of decades by
just announcing a new standard.

After the standard including lambdas came out, compilers did not immediately
comply to it, and it took some time for them to catch up. Then it took even
more time for tutorials and books to catch up. And it will take time for the
C++ community as a whole to catch up as well.

~~~
gpderetta
Compilers (at least clang, MSVC and GCC) released versions supporting lambdas
well before the C++11 standard was finalized.

~~~
partycoder
I see. The feature parity wasn't 100% I remember. There was also Boost Lambda
since at least 2004

------
Fede_V
Lambdas are an incredibly useful construct, and, once you master them, they do
make a lot of programming tasks much easier.

However, C++ lambdas picked the most horrifically ugly syntax possible, and
they switch between three subtly different semantics (copy, reference, move)
depending on a single glyph. I feel bad for the people working on modern C++ -
maintaining backwards compatibility is a huge constraint upon design space.

I'm not surprised that lambdas slow down people that aren't already
experienced with them. Since I rarely program in C++, whenever I go back to
it, I always have to spend a bit of time bashing my head against the horrific
syntax.

~~~
lorenzhs
C++14 improves upon lambda captures a lot. I'm also not aware of a move
capture, only "by reference" (&) and "copy" (=). In C++14 you're allowed to
put arbitrary assignments into the capture, e.g.

    
    
        [foo=std::move(bar)]() {}

~~~
beached_whale
I did that in the C++11 days by creating a bastard class template that would
subvert the copy operator and turn it into a move and capture that by value.

It was ugly as heck and was removed as soon as I have c++14

------
eco
As a working C++ programmer for over a decade this conclusion is absolute
insanity to me. People (myself included) are actually using the STL algorithms
now because you no longer have to go through the pain of writing a functor.
Every time I can avoid writing a for loop I'm a little happier (and my code is
a lot more readable).

When lambdas first came about there was a lot of "meh, I could already write a
functor just fine" but the ease of using them is just so much nicer and the
readability of the code is so much greater. Just writing a plain for loop
would often be less code than using an STL algorithm and a custom functor so
there was very little incentive to use the highly tuned STL algorithms if it
was just going to take more boilerplate. Now there is and we are finally
seeing C++ programmers catching up to the insights that functional programmers
had made a long time ago[1]

Others have said this but comparing lambdas to iterators is a very odd
decision because they are completely unrelated things.

The conclusion should really be that anonymous functions aren't as intuitive
as "regular" imperative code. The regular code walks you through what is going
on in babysteps so even a new user can figure out what is going on. The way
with lambdas requires a bit more knowledge but for working programmers who
aren't learning C++ for the first time they are obviously a big boon.
Sometimes you have to learn something slightly more complex to reap the
benefits of it. Pointers are very hard for brand new programmers to wrap their
heads around but nobody would argue that judicious use of them can be a real
benefit (or essential, even) in some situations. This is like concluding that
smart pointers are bad because they are less explicit about what is going on.
You still need to learn C++ manual memory management but your code will
clearly benefit (both in terms of verbosity and memory safety) by using smart
pointers 95% of the time.

1\. CppCon 2016: Ben Deane "std::accumulate: Exploring an Algorithmic Empire"
[https://www.youtube.com/watch?v=B6twozNPUoA](https://www.youtube.com/watch?v=B6twozNPUoA)
(std::accumulate, fold essentially, has been in C++'s STL since the beginning
and Stepanov probably had it in mind before C++ even existed but we are just
now getting lectures like this and I think lambdas are to thank for this)

------
ryporter
It's important to note that the negative impact documented in this study is in
development time and whether the task is completed. It makes no claims about
impacts on maintainability that show up later in the development process. It
also does not measure the longer term impact on development time if a team
starts using lambdas and gains experience over time.

I say this not to dismiss the study, which appears to be fairly well done and
to provide interesting results. I'm simply saying that its results are not
inconsistent with lambdas providing a net, long-term benefit if introduced to
a development team at work.

------
gohrt
Submitter's editorialized title mischaracterizes the OP

> All the tasks focused on iteration on a collection using a C++ vector
> object.

That's comparing "functional style" collections to iteration.

It is readily apparent that C++ syntax is so troublesome that "functional
collections" won't be a win for small iteration blocks.

We had the same debate for functional Java collection methods (although the
Java 8 lambdas tilt it more closely in functional Java's favor)

The main use case for C++ lambdas is for declaring callbacks.

------
kentonv
As someone who writes a lot of asynchronous code in C++, lambdas have _changed
my life_.

The paper seems to study the use of lambdas specifically as an alternative to
iterators. I actually mostly still use iterators myself, rather than lambda-
based alternatives, so I agree: they don't have a huge impact there.

But the headline is misleading. It should have had "when compared with
iterators" added to the end.

------
ThePhysicist
Recently I wrote a parser generator, which would take a rule structure and
return a function that does the parsing. Lambdas were very useful here, and I
do not know how I would've implemented this without them, at least in an
efficient manner, because they let me do something like this:

    
    
        Parser ParserGenerator::compileLiteral(Rule& rule){
    
            const string literal = rule.value;
    
            Parser parser = [literal] (shared_ptr<State> state){
               //parse the literal...
               state.Advance(literal.size())
               return state;
           }
    
           return parser
        }
    

Solving this without lambdas would require a different encapsulation mechanism
for the rule data, such as a class, which (IMHO) would make the code less
idiomatic.

So lambdas are actually very useful!

~~~
nly
Well, an alternative approach might to not to couple parsing and state
manipulation :)

PEGTL does this. Approximately, you have a template parameter MyAction<> on
the Parser<> template which in turn calls "MyAction<Rule>::apply (state)" when
parsing of each rule is complete.

It's a fantastic library. I highly recommend giving it a whirl.

[0] [https://github.com/ColinH/PEGTL/blob/master/doc/Actions-
and-...](https://github.com/ColinH/PEGTL/blob/master/doc/Actions-and-
States.md)

------
bjourne
Can you always replace lambdas with iterators? For example, to visit a graph
you could implement it using function that takes two arguments; the graph to
visit and a lambda holding the function (functor) to apply to each node.

It is fairly easy to implement and the compiler will inline the functor so
there is no performance penalty. Any solution based on iterators that I can
think of would be much more complicated and would probably not lead to as
efficient code.

I'll admit that the "user interface" for iterators are much nicer than using
functors. The former meshes well with c++:s for loop syntax while the syntax
for lambda constructs is bad.

------
EGreg
I used to really like C++ ... back in 2000. That is before they added the
kitchen sink into the language.

I prefer my computer languages to be like Chess - a few rules but efficient
and expressive. Like C.

Why? Because everyone can read the code others on the team wrote, without
being a language lawyer and knowing tons of esoteric features and magic.

That has implications for maintainability and team productivity, and the
bottom line for a business.

Really, people, having basic coding style conventions instead of tons of
language features wasn't so bad:

    
    
      int Foo_bar(struct Foo* this) {
         // even this is readable
      }

~~~
lambda
Very few people can read and understand C without being a language lawyer an
knowing tons of esoteric magic. There are many things in C which look
perfectly reasonable but which actually result in undefined behavior, and you
cannot reason about what a program will do in the presence of undefined
behavior.

~~~
EGreg
But there is a difference between using C in crazy ways, and using 20 features
of a language in ways that make them interact.

The more features a language has, the more I have to know just to read
someone's code or be productive in a company - and the more chance someone
doesn't know about potential harmful interactions and side effects.

~~~
eropple
_> there is a difference between using C in crazy ways_

As per my sibling, write me something as straightforward as a C++ RAII-using
dtor in C without "using C in crazy ways". I will not hold my breath. The cost
of a very minimal subset of C++ is _literally zero_ , and yet significantly
improves the likelihood of your code actually working. You're picking social
baggage in either case: either understanding the subset of C++ that your team
is using or expecting all of your developers to be perfect where C++ (and
other languages--shouts, Rust!) just do it for you, correctly.

Technology is socially interesting in that incompleteness and inexpressivity
is so often misread as "elegance" or "minimalism". That a language is "simple"
is not a feature when it offloads all of the danger onto the (almost
invariably failing to consider critical information at the worst possible
time, and I include myself at the forefront of that characterization!)
developer. This is why we have tools that compensate for the most common, and
most destructive, of our mistakes.

(This post should not be construed as any particular endorsement of C++. C++
is a gong show when used improperly. But at least it's possible for a mere
mortal to use it properly.)

~~~
beagle3
The reason I dislike C++ (since about the 2000 as well) is that while it is
possible to shackle yourself to only using C++ RAII etc, the vast majority of
code in the wild (and in libraries, etc) does not. It does 90%, but that
doesn't get you 90% of the benefit (maybe 50%, maybe 0%, depending on your
point of view).

You can do essentially all the "C in crazy ways" in C++ as well, and people
do. In my opinion and experience, it isn't what the language provides, it is
how it is used in practice - and again from my experience (YMMV), C is used
sanely and C++ is not.

~~~
eropple
I think the profusion of use-after-free bugs and memory leaks in C code
running all over the place should put the lie to this. And, further, modern
C++ allows you to firewall off the damage of bad C++ and most C, when you are
forced to interact with it, via unique_ptr and your own enforced RAII. (And
the idea that using this is so pejoratively "shackling" is bonkers to me;
being "shackled" to the use of railings on walkways over a pit of fulminating
acid is just _the worst_.)

The idea that people use C "sanely" more often than C++ (or, you know,
something actually good--further shouts, Rust!) doesn't pass the smell test.
Are you checking the retval of every sprintf? Are you writing goto drops in
every method where there's allocated memory, diligently checking every error
code, and properly bailing out, every time? If so, you're that one percent.
But you're probably not. And that's not a slight--I'm not, either. That's why
I am proud to count myself as a member of a tool-using species, because we
build (and have built) better tools to compensate for our flaws.

~~~
EGreg
So that's easy:

    
    
      #define NEW(t, args...) ((t*)malloc(sizeof(t)) && t ## _construct(args))
    
      #define DELETE(t) (t ## _destruct() && !free(t) && (t = NULL))

~~~
eropple
This isn't sufficient unless you consciously error-check and goto-trap _every
single failure point in your code_. Which you might do. But you'd be the
literal one percent. If not the literal one permille.

------
JohnLeTigre
There's a guy at work whose position is unclear to most. It's just that random
guy.

Typically, on monday mornings and friday evenings, he's very loud and looking
busy. This is an age-old trick to superficially keep your job.

Ever so often one would hear his odd sounding voice pierce through the office
talking about some idiosyncratic evidence while looking proud of himself.

Truly, if this guy was a programmer (which I doubt), he would be using
lambdas. See, lambdas might have a use after all...

------
NotThe1Pct
I have used lambdas heavily in the past and then stopped. Getting away from
the rabbit hole that are lambdas + SFINAE + variadics increases productivity
immensely.

------
lcvella
It seems that the most important conclusion of the article is that using
lambdas is more error prone than using iterators. What begs the question: how
many compiler errors were caused by the actual lambadas, and how many were
caused by the declaration of a `std::function` variable, as induced by the
authors (that besides unnecessary, is somewhat of a bad style)?

------
ericmo
Paper says that "those in lambda group received no benefits in regard to [...]
compiler errors".

Really, would anyone expect lambdas to improve compiler errors? Also, isn't
that a problem of the compiler, and not of the lambda idiom in C++ or C++
language itself?

I mean, idk about clang, but at least compiler errors from msvc and gcc have
always been hard to understand, with or without lambdas.

------
alexeiz
Is the paper available in public domain? If not, I won't regret much. Looks
like it's badly written and filled with un-idiomatic C++ code.

------
arunmu
How and who allowed them to publish such a ridiculous paper !!?? There is so
many un-idiomatic C++ code... And does the topic even fit to be published as
part of ACM ??

------
Ericson2314
I'm so relieved the consensus is negative here.

