More Functional C++?

Sdílet
Vložit
  • čas přidán 26. 06. 2024
  • 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
  • Věda a technologie

Komentáře • 67

  •  Před 6 měsíci +35

    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.

    • @__a8as
      @__a8as Před 6 měsíci +2

      When i see cpp dev i see future rust dev

    • @0LoneTech
      @0LoneTech Před 5 měsíci +2

      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 ∧.

  • @c4tubo
    @c4tubo Před 6 měsíci +26

    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.

    • @siy2740
      @siy2740 Před 6 měsíci +1

      I would think that it's to distinguish iterative code with side effects from the rest.

    • @c4tubo
      @c4tubo Před 6 měsíci +1

      @@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?").

    • @0LoneTech
      @0LoneTech Před 5 měsíci +1

      ​@@c4tubo Haskell certainly does not prevent it, merely require labeling it with forM and friends.

  • @logician1234
    @logician1234 Před 6 měsíci +14

    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'.

  • @givikap120
    @givikap120 Před 2 měsíci +2

    functional c++ is when you're turning perfectly readable and fast code into unreadable and slower one

  • @luizgabriel98
    @luizgabriel98 Před 6 měsíci +3

    Hi @code_report! Great video as always! Could you make a video about the Unison Programming Language?

  • @pluieuwu
    @pluieuwu Před 6 měsíci +43

    still quite hard to top `zipWith subtract tail`, though ;)

    • @pluieuwu
      @pluieuwu Před 6 měsíci +3

      or `\xs -> zipWith subtract xs (tail xs)`, for peeps less familiar with Applicative

    • @pluieuwu
      @pluieuwu Před 6 měsíci

      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

    • @Leonhart_93
      @Leonhart_93 Před měsícem

      Good, hopefully it stays away from that kind of spaghetti code forever.

  • @Topsrek
    @Topsrek Před 6 měsíci +2

    Talk referenced @6:30: czcams.com/video/JELcdZLre3s/video.html (Function Composition in Programming Languages - Conor Hoekstra - CppNorth 2023)

    • @code_report
      @code_report  Před 6 měsíci +1

      Thanks! I added a link to the description as well : )

  • @gradientO
    @gradientO Před 6 měsíci +9

    What's the color scheme used in the code examples?

  • @lpi3
    @lpi3 Před 6 měsíci +6

    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

  • @justinlynn
    @justinlynn Před 5 měsíci

    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.

  • @phusicus_404
    @phusicus_404 Před 6 měsíci

    Why is 720p?

    • @code_report
      @code_report  Před 6 měsíci

      🤷‍♀ i must have messed something up while rendering. will fix for next time

  • @Leonhart_93
    @Leonhart_93 Před měsícem

    When will people just accept that functional programming is a great way of taking clear and concise code and then completely murder it, obfuscating its meaning for everyone else in the process?
    Just because someone doesn't like the "normal" way of doing things.
    Yeah yeah, it's stylish because you are the special one doing it, I don't care. Just write the shortest version that uses the most basic tools and avoids std functions where they aren't really required for anything.

  • @MrAbrazildo
    @MrAbrazildo Před 6 měsíci +3

    How cute C++ is becoming! I'm getting out of date! But all of this has a negative impact on performance, hasn't it?

    • @AGeekTragedy
      @AGeekTragedy Před 6 měsíci

      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.

    • @MrAbrazildo
      @MrAbrazildo Před 6 měsíci +1

      ​@@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
      @MrAbrazildo Před 6 měsíci

      ​@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.

    • @0LoneTech
      @0LoneTech Před 5 měsíci

      These structures are easier for a compiler to reason about and vectorize or similar, but the original structure prevents that anyhow using IO in the loop.

    • @Leonhart_93
      @Leonhart_93 Před měsícem

      Those are probably there to appease some fanatic "functional" maintainers of the C++ lib. Safely ignore them and just write the code in the normal straight-forward manner.

  • @Denis-in6ur
    @Denis-in6ur Před 6 měsíci +4

    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.

  • @pokefreak2112
    @pokefreak2112 Před 6 měsíci +29

    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.

    • @germanassasin1046
      @germanassasin1046 Před 6 měsíci +22

      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.

    • @chewbaccarampage
      @chewbaccarampage Před 6 měsíci +13

      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.

    • @salameez
      @salameez Před 6 měsíci +7

      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.

    • @pokefreak2112
      @pokefreak2112 Před 6 měsíci +1

      @@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.

    • @srivatsasrinivas6277
      @srivatsasrinivas6277 Před 6 měsíci +1

      ​@@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.

  • @mirakle9375
    @mirakle9375 Před 6 měsíci +1

    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?

    • @J-Random-Luser
      @J-Random-Luser Před 5 měsíci +4

      Because you’re not used to it.

    • @Leonhart_93
      @Leonhart_93 Před měsícem

      Yes, avoid the "modern" version of C++ at all costs. It's bloated with un-needed functions and makes everything look ugly as hell.

  • @emilyingram8567
    @emilyingram8567 Před 6 měsíci +7

    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.

    • @bp56789
      @bp56789 Před 6 měsíci +2

      Verbose code is also bad code.

    • @0LoneTech
      @0LoneTech Před 5 měsíci +1

      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.

  • @TimL_
    @TimL_ Před 6 měsíci +7

    Functional programming is when someone else has written the imperative program for you.

    • @bp56789
      @bp56789 Před 6 měsíci +1

      Imperative programming is when someone else has written the machine code for you.

    • @TimL_
      @TimL_ Před 5 měsíci

      @@bp56789 Nope, machine code is imperative!

    • @TimL_
      @TimL_ Před 5 měsíci +2

      @@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.

    • @bp56789
      @bp56789 Před 5 měsíci

      @@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.

    • @TimL_
      @TimL_ Před 5 měsíci +2

      @@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.

  • @RedHair651
    @RedHair651 Před 6 měsíci +3

    This guy is out of breath just standing

    • @frydac
      @frydac Před 5 měsíci

      Yeah, I worry for his health

  • @amortalbeing
    @amortalbeing Před 6 měsíci +24

    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!

    • @DmitryBaranovskiyMrBaranovskyi
      @DmitryBaranovskiyMrBaranovskyi Před 6 měsíci +8

      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()

    • @LucasOe
      @LucasOe Před 6 měsíci +1

      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).

    • @blocks4857
      @blocks4857 Před 6 měsíci +1

      You could just not use those features

    • @guruware8612
      @guruware8612 Před 5 měsíci

      @@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 ?

    • @Selendeki
      @Selendeki Před 5 měsíci

      @@blocks4857 The worry is someone else might...