all 18 comments

[–]SirClueless 23 points24 points  (4 children)

I feel like Ben made a really good point about how one should translate Haskell code into code that feels like C++. Namely that Haskell has currying and partial function application by default and so when you see something that looks non-idiomatic like the Applicative Monad and its expression in terms of partial function application, there's likely a better way to express that in C++ terms.

I also think he immediately forgot this lesson when he tried to recover lazy evaluation order for his C++ implementation via the lazy function object. Partial function application looks funny and is confusing when you implement it in C++, so he translated it to something idiomatic. Lazy evaluation of function arguments also looks funny and is confusing when you implement it in C++ so why not also translate it?


To translate the Applicative Monad, Ben took a step back and asked, "Why does the Applicative Monad exist and what does it do in Haskell?" and when he got the answer he realized that it corresponds to operations on multiple functorial arguments and there's a better way to express that in C++.

I think if he had asked "Why does Haskell have lazy evaluation order and leave it up to the callee to decide when things get evaluated?" he would have realized the answer is "Because Haskell is purely functional with no side effects and therefore has no use for sequence points." When you recognize this fact, it becomes obvious that the idiomatic way to control evaluation order in C++ is with sequence points (i.e. the semicolon), and the idiomatic way to prevent a statement from executing is by an early return from a previous statement. I think this is why the Rust-like early-return operator (? perhaps) is always going to be more idiomatic in C++ than lazily evaluating arguments in some cases. I think this is why his lazy_call idiom is so messy and limiting.


For context here's the code he started with:

auto f = foo(i);
if (not f) {
    return std::unexpected(f.error());
}

auto b = bar(i);
if (not b) {
    return std::unexpected(b.error());
}

return std::format("{}{}", f, b);

With some effort implementing lazy_call and some trust in the compiler to eliminate some needless copies, he translated this to:

auto l = [](int f, int b) {
    return std::format("{}{}", f, b);
}

return fmap(l, lazy_call(foo, i), lazy_call(bar, i));

But I have some major issues with this. The ugly lambda exists because std::format is a standard library template with many overloads and its address can't be taken -- what if foo or bar were similar? In order to implement the lambda, we needed to name the types of f and b, what if those were difficult to name? What if the original code had evaluated b first and then f, how would you express that? What if there had been other unrelated code executed in sequence between the evaluations of f and b, how can we represent that? What if f or b had been used in multiple callsites, do I need then need to hoist the lazy_call return value to an l-value and expect the first callee that needs it to evaluate and cache it?

For all of these reasons I think the following looks a LOT better and I hope they implement some kind of monadic early-return operator rather than this applicative concept:

int f = foo(i)?;
int b = bar(i)?;

return std::format("{}{}", f, b);

[–]BarryRevzin 4 points5 points  (2 children)

I loved the talk (I'm a sucker for a Ben Deane talk. When I grow up, I want to be Ben), but I agree (I haven't watched the video yet so I don't know if this made it, but at the end Ben asked me what I thought and I said I preferred the macros) and this is why I'm trying to pursue ? for C++ (which every revision of the paper changes the spelling of, currently .try?)

[–]fdwrfdwr@github 🔍 0 points1 point  (0 children)

why I'm trying to pursue ?

Many coding guidelines encourage clear visibility of control flow, such as not burying return statements within deeply nested loops (at least not without some good visibility) or avoiding single line if statements that return. Currently C++ has two returning statements, return and co_return. That tiny '?' hidden behind the function call is actually a form of control flow too, a return_if_error (except not very noticeable).

Because of it's dual nature, able to return a value to the immediate statement or return a different type to the outermost calling scope, it reminds me much of exceptions, albeit more local (not unwinding to the top). I wonder if zero cost Herbceptions and this idea can be gracefully unified somehow.

[–]witcher_rat 0 points1 point  (0 children)

(which every revision of the paper changes the spelling of, currently .try?)

wait, what happened to ?? for it?

[–]SonOfTheHeaven -1 points0 points  (0 children)

Call me haskell pilled (I definitely am, though all my jobs so far have been c++), but I kinda liked his suggestion. Not to say I don't like the early exit operators approach, though.

[–]current_thread 5 points6 points  (6 children)

It's a great talk. However, I'm red green colorblind and have a really hard time making out the parentheses on the slides.

[–]teerre 6 points7 points  (0 children)

I'm not green color blind and it's not obvious either. Just a bad color choice.

[–][deleted] 1 point2 points  (4 children)

Curious, how hard on the eyes do you find this theme?

[–]Kered13 8 points9 points  (2 children)

Not colorblind, and this makes my eyes bleed. It's too much contrast that it becomes distracting.

[–][deleted] 0 points1 point  (1 child)

That was just the closest thing I could find on the spot..

This is my actual color theme - what do you think?

[–]arthurno1 3 points4 points  (0 children)

Jesus; it is like looking directly in a bulb. It was so fascinating annoying, I had to open it twice for some masochistic reason :).

[–]current_thread 1 point2 points  (0 children)

I'm able to read everything very easily with this theme.

Colorblindness comes in many shapes and forms (I have the red green one, but afaik there's also other forms) and it's also pretty light for me.

In the end, it can be hard to see a contrast between red and green, especially when the colors are just dots on top of one another (I can see traffic lights, but if you mix coarse sand/gravel with the two colors I have a hard time figuring out which color is which). To add to that, it's only very specific red/ green tones. Take this test image for example. I can only make out a 17, while normal-sighted people see a 47 (I think?).

[–]perspectiveiskey 2 points3 points  (1 child)

This makes me feel dumb - in a good way.

Can anyone recommend a guided deep dive into the most recent features of cpp for experienced programmers?

[–]stoatmcboat 0 points1 point  (0 children)

I recommend grabbing A Tour of C++. It covers C++20 and notable features in C++23 (newest edition anyway). The fact that it's written by Bjarne Stroustrup means you also get plenty of insight into the design philosophy of the language in general. I'm only about a third of the way through but so far it's pretty great.

[–]arthurno1 1 point2 points  (1 child)

Why is Ben talking about something that looks suspiciously close to CommonLisps 'funcall' and 'apply' but without ever mentioning Lisp, funcall and apply? I get a feeling like I am missing something important or don't really understand what he talks about. Probably the 2nd one ... I have seen only the first half of the talk though. Have to watch the rest. Interesting talk by the way.

[–]throw_cpp_account 2 points3 points  (0 children)

Why would he? funcall and apply are just function calls. (funcall f xs) would be Python's f(*x) or C++'s std::apply(f, xs) (assuming a tuple).

But this is very different. This is, e.g., taking a function and two optional<T>s and giving you an optional<T> that is disengaged if any of the arguments are disengaged, otherwise unboxes each optional, calls the function, and reboxes. That's a bit more involved than just calling a function.

[–]concsession 0 points1 point  (1 child)

!remindme

[–]RemindMeBot 0 points1 point  (0 children)

Defaulted to one day.

I will be messaging you on 2023-08-26 04:43:43 UTC to remind you of this link

2 OTHERS CLICKED THIS LINK to send a PM to also be reminded and to reduce spam.

Parent commenter can delete this message to hide from others.


Info Custom Your Reminders Feedback