More Functional C++?

2024 ж. 17 Мам.
10 989 Рет қаралды

More Functional C++?
This video is a short response to the • Moar Functional with C... conference talk.
Björn Fahller Talks:
• Moar Functional with C...
• Higher Order Functions...
• What do you mean by "c...
Conor's Talks:
• Function Composition i...
GitHub Repo with Code: github.com/codereport/moar_fu...
Chapters:
0:00 Intro
1:20 Conference Talk Clip 1 (Sequence Deltas)
3:26 Response
6:00 Conference Talk Clip 2 (Combinator Rant)
7:45 Response
9:26 Outro
Follow me on Github: github.com/codereport
Follow me on Twitter: / code_report
Follow me on LinkedIn: / codereport

Пікірлер
  • I'm sorry you got the impression I don't like combinators. I need to express myself better if I run this again. I love everything about them except their names. Wonderfully powerful constructions that I wish were used more. Not using pairwise_transform was a deliberate choice ;-) We can talk about that next time we meet.

    4 ай бұрын
    • When i see cpp dev i see future rust dev

      @__a8as@__a8as4 ай бұрын
    • I'm guessing you have the same distaste for those names I do; they're completely arbitrary and unhelpful placeholders, fit only for article context. BQN's names like constant, self, swap, atop, over, before and after at least attempt to convey meaning. So do Haskell's uncurry (albeit again academic) and flip. It's like insisting the only applicable methods on a semaphore must be P and V. They don't even have the symmetry indications of glyphs like ∨ and ∧.

      @0LoneTech@0LoneTech4 ай бұрын
  • Your rewrite lacking a for loop is noteworthy, as is no mention of it. That for loop was the very first thing I noticed after reading the title "More Functional C++?". Imperative habits are seemingly hard to break.

    @c4tubo@c4tubo4 ай бұрын
    • I would think that it's to distinguish iterative code with side effects from the rest.

      @siy2740@siy27404 ай бұрын
    • @@siy2740 That's plausible. It doesn't really feel "functional" to perform I/O inside of a lambda passed to map(...) or similar operation. On the other hand, only the purely functional languages actually prevent that, so we do see them coded that way quite often. And in this lesser case of effect-ful transformations we still gain the benefit of conciseness from filter -> map -> reduce, etc. operations over for loops that often fall prey to off-by-one or other iterator miscalculations (e.g. "is end() the last item or after the last?").

      @c4tubo@c4tubo4 ай бұрын
    • ​@@c4tubo Haskell certainly does not prevent it, merely require labeling it with forM and friends.

      @0LoneTech@0LoneTech4 ай бұрын
  • still quite hard to top `zipWith subtract tail`, though ;)

    @pluieuwu@pluieuwu4 ай бұрын
    • or `\xs -> zipWith subtract xs (tail xs)`, for peeps less familiar with Applicative

      @pluieuwu@pluieuwu4 ай бұрын
    • not saying that all languages should be like haskell of course, but i find the sheer number of ways of doing this in C++ fascinating (indexing, old school begin/end iterators, ranges, views, ...) as a Rust user, the most idiomatic way is obviously `nums.tuple_windows().map(|(a, b)| a - b)`(alternatively with `windows(2)` and slice patterns instead because tuple_windows is iirc not yet stable, or you can also use Sub::sub instead of the closure), and as a Haskell user, zipping a list with its tail is pretty much just an accepted idiom now. (though you should probably use `drop 1` as tail is partial.) just reading this comment section gives me the feeling that this sort of 'best way to write X' consensus just doesn't exist in C++ as it frantically tries to cram itself with more and more features like a blackhole. maybe it's best to start refining what's already here, figure out what people really want, and cleave off the outdated and ugly parts? frankly, it's really hard for me to see std::expected, std::optional, std::variant, std::ranges::* as anything but a frantic wholesale emulation of Rust's success in introducing those patterns to systems programming, without stopping and thinking about how they would fit in C++'s existing paradigms with exceptions, null pointers, polymorphism w/ inheritance and dynamic dispatch, and good ol' begin() and end(). this lack of organically combining the old and the new just makes C++ look like a decent modern language trapped in a bog of ancient language design cruft. but hey, maybe i'm just inadvertently spreading Rust and Haskell propaganda again ;3

      @pluieuwu@pluieuwu4 ай бұрын
    • @@pluieuwu That's my jam.

      @danielhalachev4714@danielhalachev47144 ай бұрын
  • Congratulations, you took perfectly functional code, easily debuggable, with a logical progression, and turned it into a nice spaghetti. The boomer in me would say: 'This is what's wrong with the new generation'.

    @logician1234@logician12344 ай бұрын
  • Hi @code_report! Great video as always! Could you make a video about the Unison Programming Language?

    @luizgabriel98@luizgabriel984 ай бұрын
  • Talk referenced @6:30: kzhead.info/sun/famFk8iSg6SbZqs/bejne.html (Function Composition in Programming Languages - Conor Hoekstra - CppNorth 2023)

    @Topsrek@Topsrek4 ай бұрын
    • Thanks! I added a link to the description as well : )

      @code_report@code_report4 ай бұрын
  • if you have B combinator there would be no need in pairwise_transform function. But it does exist => c++ doesn't have B combinators I have 15 years c++. Calculating differences of array example is so synthetic as driving highway on a bicycle in vacuum

    @lpi3@lpi34 ай бұрын
  • What's the color scheme used in the code examples?

    @gradientO@gradientO5 ай бұрын
    • Dracula

      @code_report@code_report5 ай бұрын
    • wow, found another good scheme other than catppuccin.

      @minibubblegum5108@minibubblegum51084 ай бұрын
  • functional c++ is when you're turning perfectly readable and fast code into unreadable and slower one

    @givikap120@givikap12026 күн бұрын
  • I am the only one, who preferred the lambda to that swizzle function (and everything that branched from it)? Also, if I really needed combinators, or any other so functionally-oriented pattern, I wouldn't be using C++. I personally find the std::views syntax extremely ugly, yet so cute compared to the combinators. I say this as a person, whose first contact with functional programming was with Java's StreamAPI and then Haskell. I think C++ should tame itself and not become something, which it has never been and never will be in a quality manner. Of course, this shouldn't be taken personally and I still like C++. Thanks for the video. You cover some interesting topics.

    @danielhalachev4714@danielhalachev47144 ай бұрын
    • you're definitely not alone - it feels like C++ is currently stuck in a loop of absorbing ideas from other languages, instead of developing new ideas that make sense for C++, or even refining those imported ideas *before* they're rendered permanently as a part of the language. the sheer fact that there has been 3, and there might be soon 4 iterations on ranges/views/streams/etc, all standardized and permanently part of an already bloated language, speaks volumes about the lack of direction at play here - i'm 100% not against experimentation and getting inspired by what other languages did right, but, pardon my language, when you fuck around and find out, you should only keep the end result and not the intermediate steps, else you'll be stuck with those bad/suboptimal design attempts forever

      @pluieuwu@pluieuwu4 ай бұрын
    • You're not alone. To some degree this is a vocabulary issue as swizzle is unfamiliar. Still, «\a b -> b-a» conveys the structure explicitly, «flip (-)» doesn't. Swizzle is the generalized permutation or gather operation, tightly integrated in e.g. GLSL where it's written in forms like coordinate.yx. I think it's great that C++ tries to integrate ideas from elsewhere. Their real problem is hiding them away in awkward forms rather than letting them exist in a programmer friendly syntax.

      @0LoneTech@0LoneTech4 ай бұрын
  • It's important to note that _nobody_ in Haskell who writes Haskell ever uses Aviary seriously. It's more a joke in the dry humour, semi-serious sense. If you ever actually use it seriously - people will look at you like you're of questionable judgement. Even the Aviary package description says it's unwise to actually use it as a library ... seriously the only reverse dependency of the latest data-aviary, on hackage - the haskell package repository - is acme-everything... which is literally a joke package that depends on everything. I'm very disappointed that people might be led to think otherwise by Björn's talk and no one else seeming to be calling that fact out.

    @justinlynn@justinlynn4 ай бұрын
  • This just looks like academic bs to me. Is there any real problem that's being solved by this functional approach? I feel like a simple for loop would be less typing, more readable, more refactorable, and significantly easier to write an optimizing compiler for.

    @pokefreak2112@pokefreak21124 ай бұрын
    • That’s false. It’s easier to optimize ranges than a for loop. The amount of typing is the same, readability is super subjective and for loop might be more readable for you simply because you’ve been programming imperatively for years. Ranges have a ton of advantages besides subjective ones, for one they are lazy, once the pipeline compiles they are guaranteed O(n), it is standardized syntax so you don’t have second guess when you see pipeline as opposed to for loop (stuff like does it handle empty array? I see it advances iterator here, will it go out of bounds? it erased element here, does it handle iterator invalidation?). I can speak only for myself but I found them easier to refactor. The REAL disadvantage is debugging becomes hell. So if it is dealbreaker for you then yeah it is definitely not worth it.

      @germanassasin1046@germanassasin10464 ай бұрын
    • At work, we recently switched from for loops to because of the parallel execution policy. We managed to shave off 1:30 minutes from an algorithm that use to take 5 minutes. I think it's worth knowing when to apply it over an all or nothing approach.

      @chewbaccarampage@chewbaccarampage4 ай бұрын
    • Learn a functional language before proclaiming it as "academic bs". Every functional programmer knows imperative programming as well and still choose functional programming. Most imperative programmers who dislike functional programming have never tried it and still have a strong position on the matter, like yourself.

      @salameez@salameez4 ай бұрын
    • @@salameez I tried to get into functional for years and even did haskell for like a year lmao, stop being presumptuous. This critique is language specific. The point of my comment is that C++ can already do imperative, so if they add functional features they should be >= to the imperative solution or else there is no reason to use them. I think functional makes sense in Rust but only because their safety rules around mutability make imperative unnecessarily annoying to write.

      @pokefreak2112@pokefreak21124 ай бұрын
    • ​@@pokefreak2112 There are two approaches to computation that are popular one being the turing machine and the other the lambda calculus Upto academic bs they are the same, but I think most people would agree that lambda calculus is more readable. ML style languages like Haskell/OCaML tend to resemble lambda calculus while C resembles the turing machine. In the distant future pure functional programming languages are going to end up faster than imperative languages because the compiler can reason more about the code. It's the same reason why the average coder can write faster C than assembly. Using folds instead of for loops and having good data types can actually lead the compiler to improve your algorithms run time. See the bird-merteens formalism After doing many folds I don't see why I should pick up anything other than a pure functional language for anything other than real time systems where the turing machine actually matters.

      @srivatsasrinivas6277@srivatsasrinivas62774 ай бұрын
  • How cute C++ is becoming! I'm getting out of date! But all of this has a negative impact on performance, hasn't it?

    @MrAbrazildo@MrAbrazildo4 ай бұрын
    • Compared to hand-optimised C, probably, but compared to normal, idiomatic C++98, usually not, I think. All those range adapters are templated function objects that can be optimised down to Just A Loop at compile time. It's the same trick that Rust uses for everything.

      @AGeekTragedy@AGeekTragedy4 ай бұрын
    • ​@@AGeekTragedyCompared to raw loops. The point is that, because they are separated algorithms, will later need to be transformed in an entire different 1. I guess it's not that easy for the compiler to understand where the coder wants to go - it's an utterly different way of thinking. Plus, measurements made by this channel showed ranges among the C++ slowest approaches.

      @MrAbrazildo@MrAbrazildo4 ай бұрын
    • Usually the compiler takes time to realise what's happening and optimise for SIMD operations. There haven't been substantial experiments with proper metrics though.

      @danielhalachev4714@danielhalachev47144 ай бұрын
    • ​@@danielhalachev4714For building array values, throughout passing it, it's easy to believe. But with ranges, as long as I understood, it seems like passing the container several times. The compiler must realize 1x is enough, like merging all range algorithms into only 1.

      @MrAbrazildo@MrAbrazildo4 ай бұрын
    • @@MrAbrazildo I honestly don't know, but I'd like to. I saw a significant increase in the number of operations with ranges compares to regular loops once the code is converted to assembly (I believe the video was from the same channel), but number of operations doesn't really mean much, if the operations are more, but easier to compute.

      @danielhalachev4714@danielhalachev47144 ай бұрын
  • Why is 720p?

    @phusicus_404@phusicus_4044 ай бұрын
    • 🤷‍♀ i must have messed something up while rendering. will fix for next time

      @code_report@code_report4 ай бұрын
  • Functional programming is when someone else has written the imperative program for you.

    @TimL_@TimL_4 ай бұрын
    • Imperative programming is when someone else has written the machine code for you.

      @bp56789@bp567894 ай бұрын
    • @@bp56789 Nope, machine code is imperative!

      @TimL_@TimL_4 ай бұрын
    • @@bp56789 "Machine code is when someone else has built the cpu for you". Let's not go down this path that ends in electromagnetism and computation theory. The point is that, very often, functional is too much abstraction.

      @TimL_@TimL_4 ай бұрын
    • @@TimL_ I’m not doing one-upmanship. I’m showing you that you’re being a hypocrite by arbitrarily drawing the line where you most prefer. Your initial comment, while funny, is not as strong of an argument as you thought it was.

      @bp56789@bp567894 ай бұрын
    • @@bp56789 It is not hypocrisy to express my opinion which I believe and practice. That is not the meaning of the word. I would be a hypocrite if I were expressing my rejection of fp while using it, which I am not. Also, it is bizarre that you interpreted my first comment as a serious argument, even though you understood it is a joke. I elaborated in a slightly more serious manner in the response. And it is hardly an arbitrary discrimination, considering the reality of computer architecture and the industry.

      @TimL_@TimL_4 ай бұрын
  • Ugh, terse code is bad code. It might be great for code-golfing, but I don't believe it has much of a place in any other context.

    @emilyingram8567@emilyingram85674 ай бұрын
    • Verbose code is also bad code.

      @bp56789@bp567894 ай бұрын
    • There's a reason terse, tacit and concise are different words, just as there's a reason explicit, verbose and circumlocutory are different words. code_report consistently leans towards unhelpfully terse, Java tradition leans towards unhelpfully logorrheic, and C++ prefers noisy punctuation.

      @0LoneTech@0LoneTech4 ай бұрын
  • No wonder a lot of people hate C++. What in the world is this? I love the core of the language but that is a monster.

    @Denis-in6ur@Denis-in6ur4 ай бұрын
  • Stuff like this makes me hope I never have to write modern C++. Why is it that declarative/functional code looks so cryptic compared to other languages?

    @mirakle9375@mirakle93754 ай бұрын
    • Because you’re not used to it.

      @J-Random-Luser@J-Random-Luser4 ай бұрын
  • This guy is out of breath just standing

    @RedHair651@RedHair6514 ай бұрын
    • Yeah, I worry for his health

      @frydac@frydac4 ай бұрын
  • C++ never stops to amaze me how it manages to get simple stuff more complex and ugly as hell! what would you do that to a for loop! @ 2:36 that's one ugly ass unreadable piece of trash! imho. just accept that c++ needs to die, it cant be good at everything! its getting less and less readable as each version pops out!

    @amortalbeing@amortalbeing4 ай бұрын
    • So, true.. when will these people understand that not everything in this world should be converted to operators that will be used once in a zillion years. I am complaining that C# became complicated but compared to modern ++ it is clean and simple. double penetration = (a __pluss_const_operator b)::move_to_hell | std::backword::odd::even::friday::operator::forward_from_hell_const_mutable_ | go::fuck::this.to_string()

      @DmitryBaranovskiyMrBaranovskyi@DmitryBaranovskiyMrBaranovskyi4 ай бұрын
    • I agree that the code at 2:36 is really ugly, but I think Conor solution at the end is really clean (even without the combinators).

      @LucasOe@LucasOe4 ай бұрын
    • You could just not use those features

      @blocks4857@blocks48574 ай бұрын
    • @@blocks4857 be assured, we don't. we need our code readable for ourselves and others i the future. make it as much cryptic as possible for what exact reason, to "feel" modern ?

      @guruware8612@guruware86124 ай бұрын
    • @@blocks4857 The worry is someone else might...

      @Prenderrem@Prenderrem4 ай бұрын
KZhead