Algorithms + Data Structures = Programs - Episode 113: The C++26 Pipeline Operator with Barry Revzin!

Episode Date: January 20, 2023

In this episode, Conor and Bryce talk to Barry Revzin about the pipeline operator |>, C++ Ranges and more!Link to Episode 113 on WebsiteTwitterADSP: The PodcastConor HoekstraBryce Adelstein Lelbach...About the GuestBarry Revzin is a senior C++ developer at Jump Trading in Chicago, a research and technology driven trading firm. After programming for many years, he got really into the nuances and intricacies of C++ by being unreasonably active on StackOverflow (where he is the top contributor in C++14, C++17, and C++20). A lot of his C++ knowledge comes from just answering questions that he doesn’t know the answers to, especially when he answers them incorrectly at first.His C++ involvement escalated when he started attending standards committee meetings in 2016, having written dozens of papers for C++20 and now C++23. You might know him from such features as <=>, pack expansion in lambda init-capture, explicit(bool), conditionally trivial special member functions and, recently approved for C++23, deducing this.Outside of the C++ world, Barry is an obsessive swimming fan. He writes fun data articles for SwimSwam and also does analysis for the DC Trident, a professional swim team featuring Olympic Gold Medalists Zach Apple and Anna Hopkin, managed by two-time Olympian Kaitlin Sandeno.Show NotesDate Recorded: 2023-01-15Date Released: 2023-01-20Iterators and Ranges: Comparing C++ to D to Rust - Barry Revzin - [CppNow 2021]Keynote: Iterators and Ranges: Comparing C++ to D, Rust, and Others - Barry Revzin - CPPP 2021Kona Photo of Barry and Michael SwimmingCppCast Episode 237: Packs and PipelinesP2011 A pipeline-rewrite operatorP2672 Exploring the Design Space for a Pipeline OperatorC++20/23 Ranges LibaryRanges-v3 LibraryBoost.Lambda LibraryBoost.Lambda2 LibraryTC39 Pipe Operator (|>) for JavaScriptIntro Song InfoMiss You by Sarah Jansen https://soundcloud.com/sarahjansenmusicCreative Commons — Attribution 3.0 Unported — CC BY 3.0Free Download / Stream: http://bit.ly/l-miss-youMusic promoted by Audio Library https://youtu.be/iYYxnasvfx8

Transcript
Discussion (0)
Starting point is 00:00:00 How do you write that as a lambda? Well, it's like open bracket, close bracket, open paren, auto, ref, space, it, close paren, arrow, decl type auto, open brace, return, start it, semicolon, close brace. So it's something like 30 characters to three is what the difference is. Welcome to ADSB, the podcast, episode 113, recorded on January 15th, 2023. My name is Connor, and today with my co-host, Bryce, we interview Barry Revzin about the potential C++26 pipeline operator, C++ ranges, and more. But our guest today is Barry Rebsin. I'll do the introduction.
Starting point is 00:00:53 Barry is an international keynote speaker. Probably, actually, Bryce, I'm not sure if you know anyone that went faster from giving his first talk to international keynote speaker than Barry, because he gave one talk. And then he gave one talk at C++ now. And then boom, that was it. Next talk, international keynote speaker. That's pretty impressive. It's amazing talk. It compares, I actually don't know the title of it. It compares D, C++, and Rust iterator models. Fantastic talk. I'll put both the C++ now.
Starting point is 00:01:32 And I think it was CPPP was the conference that you keynoted at? Yeah, that's right. So there's that. He probably has my favorite C++ blog, although it's not just about C++. But out of all the blogs out there, his is my favorite. So definitely go check out that. And what else can we say? You're one of the most prolific paper writers in contributing to the C++ language and library evolution. I don't know if anybody's done the numbers on it, but for C++23, you probably wrote more papers than anybody else. I don't really count. Yeah,
Starting point is 00:02:05 it's probably, uh, I'm well, yeah, we'll put it out. We'll throw it out there to the listeners. I'm sure there's someone keeping, keeping stats.
Starting point is 00:02:12 Let us know where Barry ranks. If he's not number one, he's probably in the top couple because there's a ton of papers that you've written, not just for the C plus plus 23 cycle, but going back. Yeah. And I'm not sure what else should we say? Should we let you
Starting point is 00:02:28 introduce the things that we haven't said? I'm not sure if you want to say where you work. Some people do, some people don't. Sure. So I work at Jump Trading in Chicago, which is a trading firm that does a little bit of everything. We trade everything, all asset classes, all time zones, all products. Very cool place to be. I've been there for eight and a half years. It's a pretty nice place. Outside of the C++ world, I guess I'm very big into swimming, which is something that a lot of people don't know about me. and it is something that if you see my tweets they're kind of divided into two categories of like random c++ things and whatever's going on in the swimming
Starting point is 00:03:09 world um briefly there was this uh professional swim league called the isl i'm hoping it comes back but we'll see if i not um and i was involved in that which is which is a ton of fun um for for a fan yeah do you run the swim slam i know i've seen swim slam is that something separate that uh i think if you go if you youtube your name you'll get your two c++ talks and then you'll get some swimming related things uh yeah so sometimes it's like the premier swimming media organization um if you if you want to know swimming news that's definitely like the place you want to go um it started i don't know maybe 2012 2011 somewhere around there um and i i contribute to it periodically i write like random data articles i run numbers for them or a bunch of
Starting point is 00:03:54 stuff uh definitely definitely didn't found it or own it or anything like that i just i just contribute periodically okay just a platform that you contribute to. And also too. So were you, uh, did you, I think you told me this, you swim, you used to swim. Um, but now you don't swim as much and you run or do you do both now? Or are you primarily a runner? Cause I'm not sure if you've listened to the most recent episode, but Bryce is thinking about becoming a runner. And I know that you at least have been going on runs cause I've seen you tweet stuff about it over the past year or so. Yeah, definitely.
Starting point is 00:04:27 Definitely run and swim. I'm much better at swimming than running. But it's obviously a lot easier to run because you just like put on a pair of shoes and just go. You don't need to like plan pool time and get there. Actually, that was one of the really nice things about the Kona meeting is that it's just on the ocean. So I don't have to plan to go swim. I just walk out into the ocean and go and I'm already there, which is super nice. During that meeting every day at lunch I would just go swim along with Michael Park
Starting point is 00:04:56 and Matush. It was super nice. I could see why people like Hawaii. Oh yeah. I don't recall where I saw a photo. It might have been on twitter but there was a photo of you michael park and was it matush as well like there's a few of you also i think you were in the water uh and i was like damn that looks quite nice it was it was awesome because it's it's like swimming except you're in the ocean and there's you know fish um on one of the days i nearly ran into a sea turtle uh which is yeah i'm just like i'm kind of you know i'm doing my thing and like there's like i i see this blob out of the days, I nearly ran into a sea turtle. What? Yeah, I'm just like, I'm kind of, you know, I'm doing my thing. And like, there's like, I see this blob out of the corner of my eye.
Starting point is 00:05:30 And I was like, whoa, what was that? And it's like a turtle. So I'm just like start following around for a few minutes. Wow. That's awesome. I thought usually the sea turtles are pretty, pretty timid. Like they don't get too close. No, they're actually, they're pretty like, they don't, they don't really give a about you. They really,
Starting point is 00:05:48 yeah. Like if you're at some of the beaches in, uh, in Kona, um, and like, they think that there's some food like near and area where they are, they'll just come on up. Really? I thought, I guess my impression of that is that I've only been to Hawaii once, but when I did go, I went, what do you call it, snorkeling? And they told us to like give the turtles a lot of space. Yeah, so, and it's actually state law that you're supposed to give them like a good, you know, I don't know, 20 feet or so. You're supposed to sort of stay away from them. I don't know why that is.
Starting point is 00:06:23 I don't know if it's that like it's really easy for humans to to harm them but i i think it's that like they don't want them to like get too used to um uh like being around humans and i think that they also can like give you a pretty nasty bite but i do know that it's like a it's like a state law well we got to cut this out then because clearly Barry was breaking state laws. You're lucky you didn't get arrested. I did not touch it. I don't think it really counts if you're just like swimming around and like the sea turtle just like – Listen, officer.
Starting point is 00:06:53 He approached me. I just don't think – I don't think that's – I don't think Barry's going to get in trouble for that. Well, we apologize if the C++ community loses a luminary figure, an international keynote speaker, because we— Barry can still write papers. And, you know, the jails in Hawaii, not to offend the great state of Hawaii, but, you know, the airports in Hawaii are, like, all outside. So I'm sure the jails in Hawaii probably have like a nice pool. All right. Well, stay tuned, folks. We'll give you live updates as to Barry's incarceration status.
Starting point is 00:07:33 Not where I thought this podcast was going. Yeah. Well, you know. Yeah. Nobody ever knows what this podcast is. Chaos with sprinkles of information. That's our tagline that someone on Reddit gave us. Well, speaking of chaos, I mean, we can – I'm not sure if you had plans of what you want to talk
Starting point is 00:07:49 about, Barry. Definitely at the top of my list is your pipeline operator papers, because it's probably for C++26 the number one thing that I'm excited for, given that we have now a bunch of ranges, adapters in C++23, specifically a bunch that don't work with the pipe operator, which we can talk about in a sec. But before we launch into that paper, and then also the error propagation paper, because I want to talk about that one as well. Is there anything you want to, because you've written so many papers, obviously active in C++, anything you want to start off or things you want to say. Oh, we should also mention you were a guest on CppCast, which is back, but you were a
Starting point is 00:08:28 guest back before it took a hiatus. We'll put that link in the show notes where I think you talk about, I think pipes is in the title of that episode. Yeah, I was talking about, yeah, I remember talking about pipeline there too. Yeah. Yeah. I mean, we can talk about whatever. I have no particular agenda.
Starting point is 00:08:44 All righty. So, I mean, Bryce, you can go Google this paper. Have you read the paper, Bryce? Probably the pipeline. Well, so there's two papers and we'll get Barry to give us a little background both, but there's 2011, which was the first paper. And I believe that was published in 2020. I'm going to say, but that could be wrong about that. But there's more recently a paper, what's the number? 2672. Looks like there's only R0 at the moment. And that came out in October of 2022. That paper is entitled Exploring the Design Space for a Pipeline Operator, which it starts off by sort of referencing the... Yeah, I've only read the first one. Yeah, it starts off referencing 2011, but then talks about the fact that there's a number of
Starting point is 00:09:24 different models. And anyways, I'll throw it over to you, Barry. You can give us an overview of the it starts off referencing 2011, but then talks about the fact that there's a number of different models. And anyways, I'll throw it over to you, Barry, you can give us an overview of the paper and in however much detail you want. And then we can talk about, is it going to show up in C++26? Are people for it, against it, et cetera, over to you. Yeah. So, so that second one is, I think the right way to describe that second paper is abusively long, which is how Zach Lane described it. And I ranges works is it has certain kinds of algorithms are things that you can pipe into. So instead of writing f of x, you can write x pipe f. And those algorithms are all the range adapters. So you can have some range pipe into views transform, piped into views filter, piped into views join um and that gives you this nice linear flow um of of the work that's being done um which which makes it like much nicer to to read um since a lot of these things once you get
Starting point is 00:10:33 to all a lot of the adapters take a second argument in addition to the range and trying to write that um as just function calls tends to be very tedious because you have to read it all inside out, which is, you know, I find it a bit hard to read. But that syntax is really nice, but it has two problems. One is that it requires some library machinery to implement, and that library machinery doesn't lend itself very well to providing good diagnostics. So if you write something like use transform r comma f and f isn't a valid function for that range, you're much likely to
Starting point is 00:11:15 get an error that says something like that than if you do r piped into transform of f. And this is because in the, in the first case, you're actually trying to call the thing. And in the second case, you're trying to call some pipe operator that ends up being removed from consideration. So you'll tend to get errors for like other pipe operators that aren't relevant.
Starting point is 00:11:35 So that's not the best. The other problem is that there's a bunch of other algorithms that you can't pipe them to. So like all the, all the things that like are typically referred to as algorithms, like all this stuff in std ranges. Cause typically what you do is you build up your pipeline and then you consume it somehow,
Starting point is 00:11:52 right? You, you either just iterate over it with a for loop or you pass it into like, now we're going to have ranges two and C++ 23 to like turn it into a collection. Or you, you just use something like, I don't know, ranges min or ranges or you you just use something like i don't know ranges
Starting point is 00:12:05 min or ranges max or ranges fold or something like you you consume it with some kind of algorithm um but you can't pipe into those algorithms because we just decided that that wasn't that wasn't a thing so you you kind of go back to this inside out style so you have to write like ranges min and then your pipeline instead of just doing R pipe to transform pipe to min, which is something that you can write in other languages. Wasn't it quite intentional that we made things like ranges fold, like the algorithms not pipeable because they weren't lazy? So, yeah, it's intentional that the adapters and then so in range c3 also has actions which which aren't lazy they are they are eager as well those are pipeable um but but not the algorithms i don't i don't really think of that distinction as especially meaningful um
Starting point is 00:12:58 piping i think of as then why didn't we make the uh the algorithms well part of it is just like that's that's just like more work that you have to do. There's also this issue of not everything can be easily made pipeable because you don't always have this clear way of determining whether your call is a full function call or a partial function call. So some of the easy examples with range adapters are things like Zip and Concat, where you can't differentiate between which kind of call you're making because well they couldn't just take an arbitrary amount of ranges um so zip zip a is a is a valid thing and you you have no way of knowing at the call side of which which uh that you meant it to be like a partial invocation this is also a problem with
Starting point is 00:13:42 things from like the sender's proposal like things like when all anything that's like very addict like that, it, you can't really make it payable. Yeah. So that's something I noticed when I, I'm not sure if you saw that tweet, but I tweeted a couple of weeks ago that I realized GCC trunk, AKA what will be 13 when they release it has implemented all the range adapters from C++23. And while I was, if you actually look at the code example, it's zip transform, zip adjacent, I think as well. And then the pairwise specializations, none of those are, at least in the GCC implementation, and I didn't go take a look at the standard pipeable. Yeah, they're not, they're not, they're not even specified. That's how they're designed. So the transforms have this other problem in that the first argument is the function.
Starting point is 00:14:28 So if they're pipable, that's not really like the model of piping because we pipe the first argument and you'd want to pipe the second. So this is basically the genesis of this paper is that we have this one problem that getting the piping to work requires library machinery that's just like tedious to implement at best and isn't great for diagnostics at worst and then there's all this other stuff that we want to make pipeable but doing so is possible but but just tedious um and with like we could do it for the standard library algorithms but that doesn't help user algorithms that they might want to write so this is like just like more tedious for everyone. So it would be nice to have a way of getting the syntactic benefits of this without all
Starting point is 00:15:12 of the complexity and all the machinery. So this is where the pipeline idea was born. Well, I should say born. We didn't invent this concept. This concept exists in other languages before us. And I say us because colby pike um better known as vector pool um is is the first person that i saw pushing this idea so he's he's my co-author on that initial
Starting point is 00:15:36 paper um and so the first revision of the paper the first thing that we tried to do was just define the simplest model, which is that X pipeline F of Y evaluates as F of X comma Y. We take the argument on the left-hand side and a call expression on the right-hand side, and that is evaluated as the left-hand argument as the first argument. It gets inserted into the first slide of the call. So there's no intermediate expression. F of Y is never evaluated. It doesn't even have to be valid. It's just a single thing. So this is a fairly simple thing to explain.
Starting point is 00:16:15 It behaves a lot like member function call, if you think about it. Like x dot f of y, what that does is it shifts x over to be the first argument. And especially now with deducing this, it really does behave like that. Like we're moving this parameter around and making one function call.
Starting point is 00:16:34 So that was kind of the initial design that we had. And this was the 2011? Yeah, so that was the R0. And so it turns out, as with a lot of things that are seemingly simple, there's a lot of interesting things to think about in this space. One ends up being, well, what's the precedence of this thing? And it kind of turns into like a surprisingly weird thing to consider. So one example might be, so if, okay, so x pipeline to f of y validates as f of x comma y, what does like f pipeline to f open paren y close paren open paren close paren mean? Which of the two function calls are we moving x into? And the same kind of holds for other kind of like post-script expressions. So you end up kind of wanting to have it to have very high precedence because it behaves a lot like dot.
Starting point is 00:17:25 So you want it to behave like dot. And there are a lot of kind of interesting things there. But then we kind of started talking about, well, like there's a lot of other interesting things you might want to do with piping. So the zip transform example you brought up, you don't want to pipe into the first argument. You want to pipe into the second, maybe even the third, depending on what you want to do. So wouldn't it give more flexibility if we open up to the user where we're moving this argument into? So like if there's a placeholder that we could pipe into. Well, there's also the case where you might want to pipe it into multiple arguments, right? And that also becomes useful if you,
Starting point is 00:18:05 when you want to do like more complex things, like, you know, fork join style models, which you can sort of emulate with some sort of like tuple-like object where, you know, you do something like similar to, similar to like a zip or like a win-all in senders. But then like later in the chain, you want to decompose it into its constituent parts. And maybe you want to call a function
Starting point is 00:18:29 where you want to say like, call this with the first and third argument of this tuple as the two arguments of this function. But without a model that has a placeholder, it's a little tricky to do that cleanly. Yeah, so placeholders are also interesting because arguably they make it more clear what's going on. Like if you see this expression on the right-hand side
Starting point is 00:18:55 and you see a placeholder, you kind of know that like, okay, well, this is where the argument on the left is going. But then once you get into placeholders, so one of the interesting issues with multiple placeholders is like, okay, well, if the left-hand side is an L value, then having multiple placeholders, okay, well, that's obvious, right? You evaluate the left-hand side once and you just like use it in both places. But if the left-hand side is an R value, well, like what do you actually do with it? You definitely don't want to evaluate it twice because that just seems totally, totally wrong
Starting point is 00:19:24 and very surprising. But if you evaluate it once, that just seems totally totally wrong and very surprising um but if you evaluate it once do you like give it as an r value in both places do you like escalate it to be an l value um that's that's kind of hard like i don't know what the right answer for that is so like i think in the in the in the last paper i'm um i suggest escalating it to be an l value like evaluate it once and then treat it as an L value multiple times. Alternatively, make it ill-formed if it's not an L value. Because you can always stick in a function in the middle to turn it into an L value and then pipe that L value twice if that's what you really want. But at least then it's explicit. So this is kind of what I mean
Starting point is 00:20:05 by like once you start diving into things, there's all these like weird issues that come up. So one is like, okay, like where can you pipe things into? Because one of the things, when you look at it syntactically, you have this expression and then you have pipeline and then you have stuff. So like it really looks like you're always evaluating the left-hand side, right? So you don't necessarily want to allow piping into a location that it wouldn't necessarily be evaluated in. So for instance, like x piped to like y or placeholder, well, you're not always evaluating that expression then. So like if you unconditionally evaluate it but then use it in a context that it has short-circuiting, that's kind of weird.
Starting point is 00:20:46 And then what if you then use it in an unevaluated context on the right-hand side? You have an expression, then you pipe it into a decl type of that expression. Also, well, it looks like you're evaluating it, but you're not if we think about the expression rewrite. So is that something you want to allow or no? So this is why the paper ends up being abusively long uh because you have to deal with all this stuff um where it gets even more interesting is that like once you have placeholders you can think about like well what does the we have this right hand expression
Starting point is 00:21:14 that has placeholders in it but like what is how does it behave like if you look at that thing in like if you look at like f open paren let let's say dollars or placeholder, like f open paren, dollar close paren that's kind of like a lambda right? you can kind of think of it as like constructing a lambda with placeholders on the fly and then invoking it
Starting point is 00:21:35 it's not exactly that and in fact in the old library only boost lambda model that's how you would write a lambda function is you would have these um these like underscore one underscore two underscore three uh placeholders that were these you know magic objects and you could do like underscore one plus three and then that would give you back a lambda that would do take one argument and then that would add three to it and i i still know some people who use that library,
Starting point is 00:22:06 even though we have, you know, C++11 lambdas because it's such a, when you're doing something that the library, when you fit into one of the use cases, like, you know, adding up some things that the library is really good at, like it's much more concise to just write your Lambda that way.
Starting point is 00:22:25 Yeah, absolutely. And there's actually, there's a new boost library called boost Lambda too, that Peter Demoff wrote a couple of years ago. And it's, I mean, it's, it's fantastic. So when I was implementing zip as part of like, so Tim Song wrote the paper for zip and then I implemented it kind of from spec to make sure that all the wording was right.
Starting point is 00:22:43 And I use boost Lambda too for all the implementation because a lot of the stuff, so you think about like, so zip iterator is like a tuple of iterators. And every tuple operator, every like iterator operation is an operation on like through this tuple, right? So it's either like a tuple transform or like a tuple for each or something. And all the functions that you want to do are like trivial so like dereferencing zip iterator is like dereferencing all the underlying iterators of of the stuff into to a tuple transform so with boost lambda 2 how do you how do you write the function that is dereferencing the first argument well it's star underscore one yeah uh how do you
Starting point is 00:23:23 write that as a lambda well it's like open bracket close bracket open paren auto ref space it close paren arrow decal type auto open brace return star it semicolon close brace so it's like it's something like 30 characters to three is is what the difference is yeah um this kind of placeholder stuff, if we can have it in Lambdas directly, would be super useful. So once you start dealing with placeholders in pipeline, well, that lends itself to like,
Starting point is 00:23:53 well, what if you use that same technology to actually construct a Lambda directly? Like what if we had a new kind of Lambdas that was just based on placeholders? And so there's a whole section in the paper of what kind of exploring what that means, like what kind of syntax could we use and how do we like differentiate it from the languages that we have today and how do those apply? So if we had that new sort of syntax, would you then, instead of having placeholders directly
Starting point is 00:24:23 in the piping operator, would it just be that you just say that the right-hand side is a function object and then just the convention would be that people would use the super-abbreviated lambda syntax to write them? Or would you still want the placeholders directly in the piping syntax? I think you'd still want the placeholders directly because there's a few significant differences in why you wouldn't want it to just be a function call. One is, for lambdas, we'd still need capture because even with the placeholder case,
Starting point is 00:24:55 we're still C++ and we don't want to do either. You wouldn't want to pick an implicit capture, so you'd want to make it explicit for one reason or another. But then it's not really a function call because if we know we're piping, we know we're evaluating this directly. So we don't want to introduce another scope, which is particularly important because one of the things, once you get into placeholder land, you can put an arbitrary expression on the right-hand side of pipe. We just give pipeline extremely low precedence, and then you could do things like, you know,
Starting point is 00:25:28 maybe the motivating use case is doing like F of placeholder, but you can also do F plus placeholder, F times placeholder, right? You can use placeholder as like a substitute for parentheses. But importantly, one of the things you can do is co-weight placeholder, co-yield placeholder. And so like if you want to do the coroutine operations, then you can't make it a function
Starting point is 00:25:50 because you can't introduce that other function scope because then you break coroutineness. Yeah, that's a good point. Which is actually one of the places where this whole what if we think about it as a language bind kind of model kind of breaks down because if you want to support co-weight, which I think makes perfect sense to support, that doesn't really work by thinking about it as a function.
Starting point is 00:26:10 So it's like, I don't know, it's kind of like a weird thing. One of the things to ask you, and actually you might not know the answer to this question. I think you and I, well, at the end of the paper, you sort of articulate between the design choices, what you're, what you are in favor of and pipeline plus placeholder is definitely something you want, which is definitely something I want as well. Not just for the fact that there are a number of range adapters that I mentioned before that don't work with the pipe operator and the fact that they don't work with the algorithms in those, you know, std colon colon ranges namespace.
Starting point is 00:26:47 It also enables you to do the duplicate things, which is a whole other thing that I like, because you can technically mimic some of the composition patterns that you get from combinatory logic, which is like a big thing that I really like. However, there are some people that are against the placeholder. And I think one time i i tweeted something and then gasper replied gasper asman who is a member of the c++ um committee and he said please no don't put the placeholder uh in and i think i asked why but i don't think he replied
Starting point is 00:27:22 do you know what like the main sort of drawbacks other than, because I know the paper mentions that it's a bit more verbose in the case where you have to, you know, you have a bunch of unary things and yes, having to spell out the unary thing is a little bit uglier. But in my opinion, that's like a weak argument that you're getting something less verbose compared to like giving up the flexibility that you get with the placeholder. Do you know what potentially Gasper and other folks that are against the placeholder, what their motivation for that is? So I think the verbosity is a significant argument against what I hear from people. And it's even something that I've seen multiple people suggest like, okay, well, placeholder, but allow the placeholder to
Starting point is 00:28:05 be optional so that you can pipe to something like f paren paren and have that work as if you had the placeholder. If there's no placeholder, then it has to be a function call and then you stick it into the first argument kind of thing. There are even people that argue against the need for the paren. When we were standardizing ranges two there was a um a point of contention about whether you would need to write like x pipe ranges two with empty parens or not um you know so i i i think that there's there is a great desire for conciseness from certain set of folks. And just to clear up the ambiguity for the listener, this is ranges colon colon T-O, not like a second version of ranges that we're introducing.
Starting point is 00:28:53 Yes, yes. It's hard to speak above that one function. Or maybe a simpler way to explain that is like there are some people that if you have like X pipe F empty parens, some would argue that it'd be more elegant to have just X pipe F. It's definitely more elegant, but like, you know, the language that Barry just spelled out, our lambda,
Starting point is 00:29:14 is like, you know. Yeah, we're not an elegant language in many ways. So yeah, so the two, I think there are actually slightly different arguments. The argument for two, I think they're actually slightly different arguments. So the argument for two, I think, is a little bit different in that if you look at all of our unary adapters,
Starting point is 00:29:33 you don't have to put parens for any of them, right? So if you pipe to views reverse or views join, you can put the parens, but you don't have to. They work without it. And in fact, I'd never see anyone write parens.
Starting point is 00:29:48 And so that works. And so in that sense, if you think about, like, 2TO, like, stood vector, close bracket, that is unary, right? Like, I'm just piping a range and I'm converting it directly to a vector. So why is that the one unary adapter that I have to put parens in? It can take other arguments, but I think the overwhelmingly common use case will be that it won't take any. is that we're not even sure if the core language blesses the implementation and approach to getting rid of the parens. Like if that is actually valid per the language. So it's not even like this is like a structural design reason why the parens
Starting point is 00:30:40 are super important. We're just like not sure if it's actually legit. But the other, for Pipeline specifically, so this is what I find interesting, is that there's a JavaScript proposal for the Pipeline operator. And I link to it in all the papers. And there's been a lot of discussion on there over the years about various designs.
Starting point is 00:31:01 And they've gone through the same kinds of, well, there's three or four different models for Pipeline, which is the right one. about various designs and they're they've going through like the same kinds of like well like there's like three or four different models for pipeline which is the right one and they've also um seriously considered this like um use a placeholder but like make it optional and what does it mean for not having a placeholder um and one of the issues that like the optionality does add complexity to the design right because you have to determine what that means. And in particular, like if you want x pipe f to automatically mean f of x, but you also want x pipe to f open paren, like close paren to mean f of x.
Starting point is 00:31:37 How do you like, so does no placeholder mean you call the right hand side or does no placeholder mean you insert into the right hand side? Do we have different rules for f versus F, paren, paren? This adds complexity. There's also discussion there about, and some of it was more specific to JavaScript, like we wouldn't have this problem. But how do you know that the user intended to do this or not
Starting point is 00:32:00 becomes more of an issue? And the way that they're leading is mandatory placeholder. Because placeholder itself, once you have placeholder at all, that's complexity, right? Because the simplest version that was like the R0 version that we proposed, where the right-hand side has to be call expression, and then you just stick it into the left-hand side, that's a fairly simple thing to explain explain and it's a fairly simple thing to implement um and i can even i can say that because like i implemented this in clang and it did not take me very long um and like it was probably not the right way to implement it in clang like i didn't
Starting point is 00:32:37 like create a new ast node i just kind of hacked it into like the regular function call node um but it it's like a very simple thing to implement versus placeholder is much more complicated. And you have to deal with like, well, what things can you place hold into and not? And can you use it more than one time? And like, what about lambdas? But it lets you do so many more things and it adds a lot more explicitness to it. And so I'm not sure in the grand scheme of things that saving one to three characters per expression ends up being a make or break kind of thing. Yeah, I kind of, I think I agree with you. And I think that there's a, if we're going to do a language, if we're going to add new language support for a pipeline operator, surely one of the rationales and motivations for that is to enable pipelining of things that we can't do today. And I think a lot of those cases, a lot of those more interesting cases,
Starting point is 00:33:47 like ones that Connor and I have talked about in this podcast before, would really benefit from having the placeholders. So if we're going to go through the trouble of adding language support, I think we would lose a ton of utility if we don't have placeholders. And a world with optional placeholders would mean, you know, you essentially have two syntaxes,
Starting point is 00:34:15 and there would be a lot of potential ambiguities, and there'd be more things for people to have to learn. And I don't mean, like, language ambiguities. I mean, just, like, you look at the code, and you're like, huh, what does this mean? Like, mental ambiguities. I mean, just like you look at the code and you're like, huh, what does this mean? Like mental ambiguities. And I don't think that the additional, you know, a couple of characters you have to type is that bad. And I also think, honestly, that it'll be a lot more teachable. You know, when you explain like the pipe piping to people today, you usually tell them it's like Unix, you know, like shells, it sort of works like this. And that's like a good
Starting point is 00:34:53 analogy, but that sort of assumes that the way that like a Unix shell pipeline works is like this intuitive thing. And it is an intuitive thing because we all know it, but I think it's not necessarily natural. If you just look at some of these examples in the paper with the placeholder syntax, I think if you showed somebody who had knowledge of C++ but had no knowledge of the pipe operator and no knowledge of ranges piping and no knowledge of unique shells,
Starting point is 00:35:24 I think that they would look at that and they'd probably understand what it meant. Yeah. All right, chip it. C++26. So what do you think the odds are, Barry? I don't know. You don't put bets on your own papers? I don't. Well, also, because I don't even know what the bets on your own papers i don't um well like also because like i
Starting point is 00:35:46 don't even know what the right answer to any of these questions is so uh i mean i don't i know what some of the wrong answers are like there's a pipeline model where you just where the right hand side just invokes you treat the right hand side as a function and you invoke with the left hand side which is like the f sharp model um that's definitely the wrong model for c++ because that doesn't help us at all it just like makes everything more verbose. So I know some wrong answers, but I don't know what the right approach is. That is the inverted invocation in the paper. So that works very well for languages like F sharp that have a lot of other language support for currying and partial function application. We don't have any of those things. And without those
Starting point is 00:36:24 things, that model just doesn't make any sense. Yeah. That's something that I think about when you're talking about the elegance or the lack thereof in C++ is that for languages that function invocation typically requires parentheses, you end up in a completely different space than when you're you know comparing it to a language like haskell or f sharp because those languages one are functional at their core and two the it's just completely different like the way that you do uh you know quote unquote piping in haskell like it's completely designed around the fact that those languages you know have like you said partial application and currying, and you can do like things super nicely, like flip,
Starting point is 00:37:10 and it's just, you know, flip and insert that in front of a function. And you've, you've swapped the order that you pass arguments in order to do that in C++, you know, you're calling a template metaprogramming function and boost on a, that, you know, does the same thing, but it's, it's nowhere as easy as just putting a function in front of your other function. And, you know, it's just a different, you know, there's a part of me that's like, oh yes, I want this beautiful, elegant model, but like, we're not Haskell. We're not F sharp. We can't get that. And yeah, you have to, at least for me, I put my elegance like heart on the shelf and say, we're in C++ land. Let's just get the flexible thing and sort of live with it.
Starting point is 00:37:48 So I think there's another potentially big advantage to language support for a pipeline operator that we've maybe not talked about before, which is ranges piping is cool and all, but there's a lot of library machinery uh you need to do to make it work and um uh there's this sender's proposal which is a proposal for you know this asynchronous programming framework for c++ which also has used the you know piping uh syntax um and also has a lot of language, a lot of library machinery to support that. And I think that having this in the language would maybe not drastically reduce the inherent complexity of these big library proposals, but I think it would decrease the complexity somewhat.
Starting point is 00:38:45 And that I think is a worthy thing to do. Yeah. Yeah. I would say, I guess, as far as like odds go, it really depends on, cause there, there are people that think that placeholders are obviously the correct design and, and the design without placeholders is totally unpalatable. And then there are people that think that placeholders are bad because they add complexity and they add verbosity to what will be the overwhelmingly common use case where you want to pipe into a function call and you want to pipe into the first parameter. And so I think it largely depends on what the relative sizes of those two groups end up being. And just to some degree, the existing piping that we have in ranges, it's not like we're just going to get rid of that. So the people who don't want placeholders or who want placeholders to be optional, then
Starting point is 00:39:43 that syntax, at least for ranges, is going to be there forever. Yeah, we can't really get rid of it. Yeah. All right, well, we're, I think, roughly 45 minutes into this, and that's about the halfway mark. I have no idea how I'm going to cut this up, but before we move on to the next paper,
Starting point is 00:40:01 and maybe we'll turn this into like a mini Rust episode because we're in our Rust phase of our podcast. We've temporarily turned into a Rust podcast, kind of. Stay tuned to hear Barry's thoughts on the Rust programming language in part two of this two part interview. Thanks for listening. We hope you enjoyed and have a great day.

There aren't comments yet for this episode. Click on any sentence in the transcript to leave a comment.