7 ms·
I keep seeing claims that modern C++ is functional but that is simply untrue. Most so called functional methods in the standard library require mutating the ta
by sakex 3y ago
I keep seeing claims that modern C++ is functional but that is simply untrue.
Most so called functional methods in the standard library require mutating the target (ie std::sort, std::transform, etc.) They are not ergonomic because we have to pass begin and end as arguments, which also means they cannot be chained.
Lambdas are hard to work with because it is difficult to track the lifetime of the values they borrow.
std::variant, std::visit, std::optional have a clunky interface. And because they are not part of the language, they often make it difficult to represent structures that would be trivial in languages with tagged enums (for instance a tree or a Linked List are difficult to model with std::variant or std::optional.) The compiler is also not able to assert that data is present in an option or that the correct variant is accessed.
- juunpp 3y agoThe style of code in this presentation will also result in insane build times. I can't see FP taking off in C++ until it gets proper modules support; until then, it's cursed by the O(N*M) nature of header compilation. And most of the projects I have worked on discourage or prohibit Boost, the STL, and heavy use of template code, for this and other reasons. I think there's a large disconnect by the kind of code in these presentations and what people in the industry actually use. I think wrapping stuff in std::function may also prevent inlining? I'm not sure how much link-time optimizations can help with that, but I'd guess languages like Haskell do better in this area. Also, C++ doesn't even have a function composition operator :/ The presentation starts off with "function application is the essence of FP", but it's really function composition. By his definition, C is a hell of an FP language.
- dataflow 3y ago> I can't see FP taking off in C++ until it gets proper modules support Modules aren't going to help with template instantiations.
- ender341341 3y agothey can, because now instead of having to re-instantiate std::vector<int> in every compilation unit it can just add it to the module's compiled unit and pull it in from there. Basically finally delivering on the promise of `export template foo<bar>` that never materialized after c++98
- dataflow 3y agoNot sure I understand you correctly, but if I do, that has nothing to do with modules. If you already know what your template will be instantiated with (which is rare and hardly going to make a dent here), you can already just do extern template ... in a .h file you #include, and then explicitly instantiate it in some .cpp file. The problem (particularly for "functional programming" purposes) is that you don't generally have the template arguments available in advance; they're different for each client. See for example all the lambdas passed to algorithms like std::find_if(). So this isn't going to get you anywhere, practically speaking.
- ender341341 3y agoextern template was removed from the standard cause it wasn't implemented by any of the common compilers so you can't use it (unless you use Comeau which appears to be abandoned). What it has to do with modules is you can effectively treat the module as a mini 'shared library' and when a template is instantiated you can append the compiled code into the module and re-use it in other compilation units.
- dataflow 3y agoNo, you're mixing up export and extern.
- ender341341 3y agoahh, your right, I do think with the rest of my comment it basically allows automating `extern template` though.
- pjmlp 3y agoThey do in regards to parsing, semantic analysis, and keeping external templates around for common instations.
- dataflow 3y agoThose don't make much of a dent when the vast majority of the problem lies elsewhere. See my reply to the sibling comment.
- juunpp 3y agoThis reminds me that the way Haskell/ghc implements/ed type classes, if I remember correctly, is not by instantiating them, but with a dictionary lookup[1], compiler tricks aside. I think that largely throws away the overhead of compiling template code... at the cost of the runtime overhead that C++ typically dislikes. [1] https://stackoverflow.com/questions/12645254/ghc-code-generation-for-type-class-function-calls https://stackoverflow.com/questions/12645254/ghc-code-genera...
- gumby 3y agoIt seems like the most strident FP enthusiasts don't use (or use and don't like) actual functional languages so are always looking for somewhere else to go. Meanwhile while actual F programmers, and the developers of non-FP languages that receive these claims (like Lisp or C++) aren't interested in making these kinds claims. It's fandom.
- zer8k 3y agoPeople conflate "functional programming" with things like pure functions (for some definition of pure), lambdas, immutability, ADTs, etc. Like many languages called "functional" (rust being one of them) they are not functional at all. However, they have enough uh...functional-ity that can be leveraged to create code that is sometimes easier to reason about. I don't really understand the aversion to imperative programming. There's certainly a level of cargo cult. Add to that the general difficulty of pure functional programming and now you've got a cult complete with it's own ivory tower. It's once again a question to find the ultimate kitchen sink. C++, being one of the first kitchen sinks, doesn't surprise me as the subject of this article.
- pjmlp 3y agoThat prize belongs to PL/I and Algol 68, predating C++ for almost two decades, followed by Ada which in 1983 was definitly more complex than C++ Cfront, and had an additional revision (Ada95), before C++98 came to be. Ironically Ada 202X might be easier to implement than C++23.
- dgb23 3y agoThere are different functional quality layers so to speak. For one, just having lexically scoped closures as first class citizens doesn't cut it in my eyes. Even though perhaps in some contexts and timelines this would suffice to say that your language (or paradigm) is functional. In JS using closures was the tool to create modules and objects to maintain internal state. It really was closer to some version of OO than to functional programming, because you would mutate and construct state with these. Personally I'm not a purist in any sense. I'm all about the interface: - Does the thing I'm passing you change under me? - Is the thing you return the same if I give you the same arguments? Those are the qualities I really care about. In some cases I would even go as far as accepting you violate the former guarantee as long as I'm not using the argument anymore (you own it). What I don't care about is what you do under the hood. > I don't really understand the aversion to imperative programming. This kind of functional quality really shines in certain contexts. For one, a function (in that sense) is easy to reason about and trivial to test. Secondly, if you think of functions as (lazy) questions about your program state, you avoid memoizing and duplicating state all over the place (as you would with a full-on imperative/OO approach), which can have positive effects on memory pressure, GC etc. You avoid passing around pointers and instead construct normalized and write optimized data structures that can be asked questions when needed. A thing that follows is ease of concurrency. You now have a better separation of mutations and reads. The concurrency semantics trivially fall out of that.
- pjmlp 3y agoHaskell is not the definition of FP, rather one possible approach.
- Rexxar 3y agoThe meaning of "functional programming" has changed with time. "functional programming" is now often used for what was called "pure functional programming" before. They just use the older and less restrictive definition.
- krona 3y ago> they are not ergonomic because we have to pass begin and end as arguments, which also means they cannot be chained. C++20: for (int i : ints | std::views::filter(even) | std::views::transform(square)) std::cout << i << ' ';