5 ms·
This is entirely a personal opinion, and probably something I will be lambasted for, but any example using a lambda in C++ I find to be 10,000× worse than the f
by xigency 11y ago
This is entirely a personal opinion, and probably something I will be lambasted for, but any example using a lambda in C++ I find to be 10,000× worse than the functional equivalent.
The benefit of writing code in C or C++ is that it gives your programs structure, and without naming your predicates or organizing your program in a logical way, it's basically a soup of abstract symbols.
My 2¢.
Kudos to the author for explaining how to use them. I naïvely assumed that the keyword `lambda' was involved.
- ska 11y ago...I find to be 10,000x worse than the functional equivalent. ironic.
- xigency 11y ago| Using a named function rather than an inline, anonymous function. Would you prefer 'the procedural equivalent'? 'Named equivalent'?
- ska 11y agoProcedural or imperative would be fine. "Functional" implies functions as first class objects, which is exactly what is being demonstrated. More to the point, your real complaint is that you only know one way to "give your programs structures". This is absolutely not a problem of functional style, but of your own understanding. A separate issue is how successful functional styles are in c++, but they have been there for ages (c.f. the STL). It's better than ok to be confused by new things, it's a great place to learn from.
- xigency 11y ago* Gives a program structure It's entirely possible for functions to be first-class while also requiring them to be named. Also don't get confused into thinking that C++ does have functions as first-class values, because it does not.
- AnimalMuppet 11y agoWhat is your definition of "first-class values" that C++ functions don't fit?
- xigency 11y agoA language that supports creating functions (and function closures) at runtime. Lambdas are essentially syntactic sugar. This requires a whole different runtime paradigm. If there were examples of code that compiles doing this, which there might be, it would probably be analogous to this: int* getVariable() { int x; return &x; } Implementing functions as first-class types generally requires a garbage collector or at minimum a different mechanic than just an ordinary stack and heap. Otherwise, your stack would start to look like swiss-cheese in any moderately functional program. Trying to write something simple, like the Y combinator, leads to a mess like this in C++14: ([](auto f) { return [](int k) { return ([f](auto g, int i) { return f([g](int j) { return g(g, j); }, i); })(([f](auto g, int i) { return f([g](int j) { return g(g, j); }, i); }), k); }; }) While you can find workable examples with template coding (and lambdas), you still won't be able to create code like you would in JavaScript for event handlers.
- AnimalMuppet 11y ago> A language that supports creating functions (and function closures) at runtime. What do you mean by "at runtime"? The only language that I'm familiar with that really lets you define them at runtime is Lisp. > Lambdas are essentially syntactic sugar. Do you mean that lambdas are essentially syntactic sugar for creating functions at runtime? Because C++ has lambdas, and if you mean "lambdas = creating functions at runtime = functions as first-class values", well, C++ has lambdas... Could you clarify? I'm sorry, but I'm having trouble seeing what distinctions you're trying to draw.
- xigency 11y agoI'm trying to explain this in as much brevity as I can, but this will be a long post. > What do you mean by "at runtime"? The only language that I'm familiar with that really lets you define them at runtime is Lisp. Lisp is not the only language that allows this. This is why I mentioned JavaScript at the end of my last comment. In general, it would be easy for a scripting language to support this feature. What's more interesting is that some compiled languages do as well. For example, Chicken Scheme. Scheme being a form of Lisp supports first-class functions, and Chicken Scheme being a compiled form of Scheme does as well. An example from JavaScript: function ValueAlerter(x) { return function () { window.alert(x); } } Any time this function is called (ValueAlerter), a new unnamed function is created that references the closure of ValueAlerter. It's possible to write the same thing with a named function. function ValueAlerter(x) { function result() { window.alert(x); } return result; } Note that this is, using prototypes, generally how OOP is implemented in JavaScript. > > Lambdas are essentially syntactic sugar. > Do you mean that lambdas are essentially syntactic sugar for creating functions at runtime? Because C++ has lambdas, and if you mean "lambdas = creating functions at runtime = functions as first-class values", well, C++ has lambdas... > Could you clarify? I'm sorry, but I'm having trouble seeing what distinctions you're trying to draw. When a language feature is called syntactic sugar, it means that it makes certain ideas easier to express, but it doesn't create new functionality. An example in C++ is the -> operator. The alternative to writing a->b is (*a).b which is more cumbersome. So no, lambdas do not allow you to create "functions" at runtime (when speaking of our complete definition of a first-class function). I would assume that a C compiler is able to isolate the code in a lambda into its own function, so it is equivalent to writing a separate function, depending on how it is referenced. The `auto' type also facilitates this because newer C++ features involve certain types which cannot be used by the programmer. So you can think of C++ lambdas as a sort of macro for writing code locally. It's similar to using a = p ? x : y; instead of if (p) a = x; else a = y; in that it is a language feature that allows for the programmer to type less for the same result. -- For a more illustrated example, think of a basic sequence of function calls. Function A calls B, and B calls C. The callstack in a C++ program for this sequence would look like this: A() B() C() The computer's stack looks like this when it is executed: Top of the Stack ---- A's local variables. ---- B's local variables. ---- C's local variables. ---- Bottom of the Stack Now, it's possible for C() to create a function and store that somewhere. In a C++ lambda, with a captured local variable, this dynamic function would have a reference to one of C()'s local variables. In a JavaScript or Lisp program, this dynamic function would also have access to one of C()'s locals. This is fine if the dynamic function is called when C() is still in scope. If, however, this is stored in a result that is accessible from A() and it is executed after B() is out of scope, and this function references a local value from C(), then the reference would look something like this: Top of the Stack ---- A's local variables. ---- Bottom of the Stack ---- Garbage ---- Garbage (Reference to C() variable) ---- So basically, native C or C++ functions cannot be first-class with this model of computation, while it's trivial for Lisp and Scheme. Now it is possible to use this sort of paradigm with a number of templates, libraries, strategies, added language features, but nothing that approaches native first-class functions. Making a sincere implementation of this would be more daunting than creating a new language.
- evanpw 11y agoI often prefer to use lambdas as (named) inline function definitions: auto lessGold = [](const Hero& h1, const Hero& h2) { return h1.inventory().gold() < h2.inventory().gold(); }; std::sort(heroes.begin(), heroes.end(), lessGold);
- AnimalMuppet 11y agoInteresting. In C++, a variable can have global scope, file scope, class/object scope, or local scope. A function can have global scope, file scope, or class/object scope. This lets you create a function that has local scope.
- doomrobo 11y agoYou can even do that in C (non-standard, of course) using clang with the Blocks extension
- lbrandy 11y ago> any example using a lambda in C++ I find to be 10,000× worse than the functional equivalent. > I naïvely assumed that the keyword `lambda' was involved. I don't understand how this two sentences co-exist. If you are unfamiliar with the syntax, surely you can't have a well informed opinion on which usage, in practice, turns out better? I am assuming "functional equivalent" means the old named functors of C++03. And yea, you are likely super alone on that opinion. I normally say lambdas in C++11 mostly-obsolete (at least as the default) a huge class of the old ways from functors to bind/placeholders and friends. I don't think I've ever heard someone pining for the ol' days on this one.
- xigency 11y agoSuper alone. I don't generally use STL so I mean without language extensions. It's easy enough to implement these things with traditional function pointers.