Algorithms + Data Structures = Programs - Episode 34: Tuples, Arrays, APL & More
Episode Date: July 16, 2021In this episode, Conor and Bryce talk about arrays, tuples, APL, C++ concepts/CTAD/structured bindings and so much more.Show NotesDate Recorded: 2021-06-26Date Released: 2021-07-16Tweet of impromptu c...onversation at HOPL IVC++ India AMA with BryceFunctional Geekery (Conor’s favorite podcast)CORECURSIVE #065 From Competitive Programming to APL With Conor HoekstraNew Podcast: ArrayCast!SimCorp (company that uses APL)Companies using APL, J, k or qApril: Array Programming Re-Imagined in Lispbooost::hanaC++ std::tupleC++ std::arraySean Baxter’s CircleSwift Tuple TypeC++ structured bindingsP0931 Structured bindings with polymorphic lambasC++ views::cartesian_productKevlin Henney on TwitterThrust open source algorithm libraryCUB open source algorithm libraryC++ Class template argument deduction (CTAD)P0009 MDSPANC++ conceptsIntro 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)
I have a second podcast now. Do you know about this?
I don't and I feel betrayed.
Welcome to ADSP, the podcast episode 34 recorded on June 26, 2021. My name is Connor and today
with my co-host Bryce, we talk about a plethora of topics
including std tuple and other tuple types, std array, APL, and so much more.
I saw that you were on, like, I saw a tweet where there was a screenshot of you and, like,
some other people on some panel at some programming language conference.
There's a bunch of things.
You're on panels
it wasn't a panel it was an impromptu conversation um uh let's i'm gonna get well so what are all
the things to announce because i we do such a bad job of promoting stuff in general um so one I was on I'm doing an ask me anything
next Friday
July 2nd
at
I don't remember the time
but there's Twitter details I'm doing an ask me anything
for the C++ India
meetup
yeah Connor will put a link in the show notes
so come ask me questions about stuff
okay C++ India AMA Um, yeah, Connor will put a link in the show notes. So come ask me questions about stuff. Okay.
C plus plus India, AMA.
Um, I'm not even sure how much of this stuff you, you know, personally.
So, uh, I was on my maybe second favorite podcast, uh, co-recursive, uh, which was,
it was awesome.
I talked about the first half was talking about this one. This one obviously is your favorite podcast, right?
No.
ADSP is your favorite one?
No.
My own podcast is not my favorite podcast.
My favorite podcast is Functional Geekery, which everyone should go listen to.
Honestly, at some point I'm probably going to go back and re-listen to all the episodes
because they're so awesome.
But yeah, I was on there.
I talked about competitive coding and then APL for the second half um lots of great apl content i have a second podcast now do you know about this i i i i don't
and i feel betrayed uh yeah so i'm i'm host of another podcast called arrayraycast. Yeah. And it's a panel podcast.
Full disclosure, I don't do any of the editing work for this one.
That's Bob Terrio, who's one of the panelists.
So basically it's four folks and we rotate some of the co-hosts.
So like I'm the host that doesn't know anything.
And then we usually have one representative for each of apl uh j which is
like an apl derivative and then uh q slash k which are also apl derivatives and we just talk about uh
array programming language stuff and i'm we're bringing apl back from the dead even though some
people would argue it was never dead um wait which people which people would argue it was never dead uh i
mean like that are which people that are not named con the people that work for uh dialogue apl that
implements the interpreter that many corporations use so there's also who are these who are these mini corporations so simcorp is probably like the
largest uh company that they operate in the financial software section so i'll link it um
here let me find it uh because i tweeted it out you know i'm not sure if you're familiar that like
there's a haskell list companies that use Haskell and like companies that use Elixir.
Um,
there's now a,
and they're usually hosted on, um,
on GitHub.
There's now a companies that use array languages.
Here,
let me send this to you.
It's a short,
what is an,
what is an array language?
Well,
to learn that you should go listen to episodes 1, 2, or 0, 1, 2, and 3.
Literally, I think there was an episode that just got released today, which is June 25th,
and listeners will be listening to this sometime in July.
And we talked about, yeah, what's an array?
What is the array oriented paradigm but it's
basically it's a language that basically only has arrays and um yeah this actually is interesting
because i i have a the the what is an array in this context does it imply contiguous storage or is it just a sequence
um that's actually discussed so like it depends on the language k it's not always contiguous
apparently um k and q they treat their like matrices as uh you know a table of vectors
so like a a list of vectors where each of the vectors are,
I'll bet that's the thing is I think they're vectors.
If I recall Nick,
what he said is that they are not necessarily homogeneous.
So which necessarily implies that you're either going to have to like box
them in order to get them contiguous.
But in J and APL, they're definitely contiguous.
Yeah, I think in C++, the analogy for what an array language is called array
is just the notion of a sequence or perhaps thinking a little bit more modern C++,
the notion of a range.
So when I say a sequence, I mean a sequence as in like what we call the sequence algorithms
in the standard library algorithms that operate on ranges of iterators.
And it's an interesting thing to think about because they're, you know, one-dimensional.
You know, they go from front to end.
They're homogeneous in that they, at least in C++, they have a single type. could, you know, you could through boxing or type erasure, of course, hold things that
have different actual types or kinds in a sequence.
And, you know, we have this notion of different categories of sequences, which are sort of
come from the categories of iterators.
And, you know, the most useful from the perspective of somebody implementing the algorithm,
a sequence algorithm, is, of course, contiguous.
Having a guarantee that all the elements of
this sequence are that you not only have random access to them, but they're all contiguous in
memory. And that's great. If you only have to write an algorithm that works for that, like that's,
that's a lot easier. But from from the user perspective, the most useful thing is when an algorithm supports all classes of sequences.
And I'd actually be curious whether other languages have the same notions of categories
as C++ does.
I think things from forward iterator and up probably do map, but do other languages like apl and j do they have a notion of um of input
of something like input iterators where you can only decrement you can only dereference it you
know once no at least not to my knowledge like apl isL is a much simpler, has like a much simpler model.
Just everything's an array.
It has a rank 0, 1, 2, 3,
to up to like 15 or something,
which just specifies the dimensionality.
So like a zero.
Why up to 15?
I don't know.
Why is it arbitrary?
I think it's arbitrary.
But why isn't it,
why doesn't it just like support
like any dimensionality?
I do not know
um i know that there is an implementation of apl in common lisp uh called april that due to the
fact that lisp supports like infinite dimensions on like nested lists that there's no limit in that
sort of apl implementation implementation called April.
But yeah, I'm not really sure what the limit in APL is for.
And, you know, I think one of the unfortunate tragedies of C++ is when we built heterogeneous sequences,
it stood tuple.
We did not build it in a way
where we could reuse the same series
of algorithmic primitives
for both heterogeneous and homogeneous sequences.
And I don't know about the rest of y'all,
but anytime I end up doing something
non-trivial with stood tuples,
I end up writing some series of tuple algorithms.
And like these just, these just get,
some set of these just gets copy and pasted
from one project to another project to another project. Like, you know, tuple pushback, tuple
pop, et cetera, tuple reverse, a bunch of, a bunch of like little algorithms like that. And, um,
and every time I, I do that, I'm just like, why can't I just call the standard algorithms on these?
Yeah.
Isn't that what Louis Dion's Boost HANA is for?
Yeah.
Yeah, exactly.
That's exactly what it's for.
Yeah.
So why aren't you using that, Bryce?
Yeah, that's a good question.
A lot of the projects that I work with, it's not, you know, I used to work on HPX where we used Boost for everything. And then since I've started working on other things like, you know, Thrust and Cub that Thrust should stand alone, that it shouldn't really have any dependencies.
We'll leave aside the fact that it does actually have some dependencies.
But his philosophy was it should be super simple to use, and so we should avoid the C++ dependency management problem by not having
any dependencies. And amusingly, this doesn't mean that Thrust doesn't use Boost. It just means that
the parts of Boost that Thrust really needed to use, Thrust just copied them into Thrust.
So like Thrust complex is a very, very, very bastardized derivative of like some boost complex data type.
And same for like the thrusts iteratorcessor layer is derived from HPX's preprocessor layer, which is derived from Boost's preprocessor layer.
So the C++ dependency management solution, just copy it into your project.
Control C, control V.
Yeah. But I do wonder whether, you know,
we made a mistake with not making tuple a language construct.
I sort of have two different ways of thinking about this.
I have both an argument for why it's good that we made it a library construct
and an argument for why it was good that we made it a library construct and an argument for why it's, um, uh, why it was maybe a mistake. Um, I'll start with the argument for,
for why things should be library, um, constructs in C++, which is, um,
uh, I don't want to say regularity because that has a specific meaning in, uh, in,
in the notion of types.
And so if I use it casually here,
it won't express what I want.
So I think I'll say familiarity.
Good C++ features have familiarity,
which means that they sort of follow
some core basic set of rules
and they don't have a bunch of caveats.
So let's take an example of something that does not follow familiarity,
which is built-in C arrays in C++.
Built-in C arrays cannot be returned from functions.
They have this weird property where they can decay to pointers.
And they have a bunch of weird conversion rules around that.
And they have this really weird syntax
where when you're declaring a C style array,
you know, you put these brackets and like
the placement of them is like a little bit quirky. And like sometimes you have to put a, you know,
a specific size in there. And then sometimes it can just be like defaulted. And all of that is unfamiliar.
And by that, I mean, it's not consistent with the basic like rules of C++ structs.
Um, now you compare that to something like std array.
So std array is a modern C++, um, uh, abstraction for, you know, the same sort of thing as a C style array.
And when you spell out the type for a std array, it uses a familiar syntax, template syntax.
It doesn't use this weird special syntax where you have to put brackets in a certain place.
And so if you know template syntax, how to instantiate a template,
then you'll understand that std array syntax.
And likewise, std array doesn't have these weird decay rules
where it decays to a pointer.
You can get a pointer from it by calling a member function.
Member functions, that's something that, like if you understand how you call member function, when, like, you
understand how you get a pointer from a std array, there's none of this weird conversion rules to
know. You can return a std array from a function. Like, that's sort of what you'd expect to be able
to do with the thing. And I call things that behave like this, I call them struct abstractions. The nice thing about C++, you know, structs or C++ classes is that there's
a common set of rules that they follow about what you can do with them. And they have a common and
familiar syntax. And so, you know, I think that std array is a much better abstraction than built-in C
arrays because std array follows almost like almost all of the same rules as something like
std vector or std string, where they're all structs. And so they all play by, you know,
a very similar set of rules. And so in that same logic, like, you know, it's nice that std tuple
is, you know, just another struct because it follows all the rules of structs.
And the reason that this is nice is because it minimizes the number of things that you have to
learn, the number of caveats that you have to learn about the core language. You know, if we never had built-in C arrays, if we just had
std array, then you wouldn't have to learn all these caveats of, oh, you can return, you know,
you can return any object from a function except for built-in C arrays. Then it would just be,
you can return any object from a function. Boom. Done.
And likewise you wouldn't have to learn all this weirdness with
pointer decay and all the implications
it has on overloads.
So I
think the best C++
language abstractions
for
object-like things behave
like structs,
like as if they were library abstractions.
Now, perhaps the mistake we made with std tuple
was that we got the...
I would argue that we sort of got some of the basics
of the interface right
and that we decided to make it a struct-like abstraction.
But living within those rules really complicated its interface
and I think prevented us from having something
that could have been a lot more elegant,
like some generalized form of parameter packs. And so like, you look at some of the unwieldiness of dealing with std
tuple, and you wonder, well, okay, you know, is this really worth the cost of having it
behave like all other struct like things? You know, like the std git interface in particular
is just kind of... The whole time you've been saying all this, I've just been like, you know, like the std get interface in particular is just kind of...
The whole time you've been saying all this, I've just been like, you know, whether it's a library or language thing, it's just like having to spell out std colon colon get angle number angle paren, then your tuple type.
Yeah. Um, especially when you compare it to like other languages that have tuples, uh, some
types and like pattern matching and destructuring, like all built in as sort of language, um,
facilities.
Yeah.
It just makes you cringe when you have to like, oh, I need the third, third item from
this tuple.
Let me, let me go.
And what did they call it?
Cancer of the semicolon, um um or that kind of thing it's just it's
very non-elegant um compared to other languages and and if you look in and yeah and you know
like it is familiar but that comes with a cost like it does have a familiar syntax for other
struct like abstractions but it comes with a cost. And if you look at the design of std get in particular,
there's a reason it's not a member function.
And the reason it's not a member function
is that if it was a member function,
then in dependent contexts,
you'd have to write.template get,
which would have just been atrocious.
I think there's probably other reasons
why it's not a member function too,
but I think that was one of the main ones.
And yeah, and the syntax that I think we would have wanted,
you know, just like a bracket syntax
for accessing members of the pack.
You know, perhaps we could have found a way to have done that
while also having tuple be still a struct-like abstraction.
Maybe we could have extended the language in some way
to allow an indexing operator that takes a constant parameter.
And maybe that would have been a better design.
Or maybe we should have just introduced it as a full built-in language facility.
I definitely feel like the way that we went about doing Tuple
was probably not right.
And this is all leaving aside just the implementation burden of Tuple.
Tuple's very difficult to implement.
It's very difficult to implement correctly um and uh at times it can have you
know big compile time or at times if implemented in like uh uh naively it can have big compile
time costs um and you know i've been looking a lot at uh at sean baxter's Circle recently. And that's really sort of made me question
the wisdom of the design of our tuple
because the facilities that he has
for dealing with tuples and parameter packs
in Circle are far more elegant and powerful, and they do actually sort of satisfy my familiarity
goal, that they just sort of seem like natural extensions of the language.
Yeah, it's interesting, because I looked up Swift's tuple, and for the record, for all
those that are cringing because of Bryce's incorrect pronunciation, I do have the correct pronunciation of tuple because Stefan Laowade is the arbiter on this, I believe.
Swift's philosophy is to push as much stuff to the standard library as possible. So like if I'm not mistaken,
like their integer types are like library.
They're implemented in the library, not in the language.
So it's, you know, one of its goals as a language
is to basically push as much stuff as possible
to be implemented in the library,
which then gives like users of the language
just as much power as like the
implementers of the language.
And that being said,
I believe from looking at their docs,
their tuple type is a language facility.
It's not implemented in a library.
So for a language that like has that as a,
as a,
as a goal or sort of a tenant it. It's interesting because I was expecting actually
Swift's tuple to be in the library
and it does not look like it is.
I could be mistaken.
It does seem like it's something,
it does seem like something that's perhaps fundamental enough
that it needs to be part of the language.
But I would, I think that I still believe
that the right answer for most facilities is to implement them as library abstractions because library abstractions have this familiarity.
The place where I think we may have gone wrong is that we did not – we built Tuple as a library abstraction with the tools that we had available and i don't
think we spent enough time asking ourselves how could we have how could we make a better like
what language facilities would we need to make a better library tuple in c++ and i think that that perhaps with with the right set of tools we could have made a better
library tuple but um i mean but you you still you know anything that's in the standard library
you're gonna have to pay that um that five character tax stood colon colon and that is a little bit unfortunate well
i mean we have structured bindings now so uh yeah that that yeah that does avoid stood get many
times we need them everywhere though you i finally remember i i you gotta write me that paper a
couple years ago was like oh we need we need structured bindings in lambda uh lambda uh parameter
lists yeah and then you were like huh why is that useful and then fast forward two years and you
were like yeah then trying to try to i think it was literally with cartesian product which is one
of the it was with cartesian product and i was i was i wanted to make slides and i was like if i don't have this the
slide is less elegant and i need this slide to convince to convince the masses the the hbc masses
that uh c++ standard parallelism is the way to go so now connor yes i care about your thing bring me
bring me that thing technically there was a paper i'll link it in the show notes from a few years ago but it died it was called like generic lambdas and yeah generic lambdas with structure bindings
or something like that but yeah but i want you to revive it okay but um but yeah i was just as i was
saying that about you know the five character tax i was just thinking you know with um with return
type deduction with automatic return type deduction, with automatic return type deduction
and with things like structured bindings, you don't really actually, it doesn't actually really
come up that many places. And structured bindings are really interesting because, um, they,
I think they change a lot about how we design APIs. Um, an example, one of the things I've spent a lot
of time on recently has been shepherding the executor's effort in C++. And in the latest
proposal, there's this notion of a thing called a sender that can send values and it can send potentially
multiple values.
And so that is represented as a tuple.
Usually you don't see the tuple because typically the way that those multiple values get
materialized is as multiple function parameters.
So usually the thing that, you know, if you're building a chain of asynchronous
work, you don't usually see the tuple. It's just that, hey, you have a function that takes, you
know, three parameters and the tuple gets, you know, the tuple that's sent gets unpacked and
passed in as those three function parameters. But at the end of the chain, when you're waiting for that chain of asynchronous work,
then you're getting back the final result.
And that is going to materialize the tuple.
And so there's this function sync weight,
which you give it a sender,
and it returns to you the value that that sender is sent.
And it will block until that sender has
completed and sent its value. And what does that sink weight return? Well, it has to return a
tuple because the sender might send multiple values. And we can actually kind of do that quite elegantly, even in the simple case
of a single value being sent. Because in that simple case of a single value being sent, you
just write auto, open bracket, you know, a, close bracket, equals, sink weight, whatever, the sender.
Now, imagine a world before structured bindings.
In that world before structured bindings, writing that simple case would have required you to
instead say auto a equals std get zero of this sink weight expression. And I think that
if we didn't have structured bindings, if that simple case had to involve that std get call,
I think we probably would have designed that function completely differently. We might have
said, you know, we're going to constrain this sink weight function to only accept senders that send
a single value so that we can just return that value directly. So we don't have to have this horrible syntax for this simple case. But because of structured bindings, we can write this sort of
elegant, you know, code for the simple case. And it extends pretty elegantly for the
more complex cases.
And so it's interesting that, oh, structured bindings is just syntax trigger.
But I think that that syntax trigger
completely changed how we would have designed this API
and what we would have thought
was an acceptable solution for this API.
I don't think it would have been acceptable
for this api to have returned a stud tuple um if not for structured bindings yeah there's there's
two phrases that sort of i don't not the word is not irritate but just like completely obfuscates
um like the importance of something uh one of them is just like syntax sugar
because like lambdas are just syntax sugar,
but it completely changes the way
that like people use algorithms
and how easily it is to reach for an algorithm
and customize its behavior.
So like saying it's just syntax,
it's just like, okay.
Everything's just syntax sugar.
Like it's all just syntax sugar for like writing assembly.
And the other one that irritates me even more is when someone says it's just semantics.
And I'm just like, you realize what you're saying, right?
It's just the meanings that we attach to the words and we're communicating.
Like it's everything is semantics.
Like if we don't. I've never heard somebody say that. Oh, yeah. They say, oh, it's everything is semantics like if we don't i've never heard
somebody say that oh yeah they say oh it's just semantics you know tomato tomato which is actually
not semantics that's two different uh pronunciations of the same word um yeah it's like oh well you
just had a slightly different interpretation of the word and i meant it this way and it's like
well you can't just say it's just semantics. That led to like our complete misunderstanding.
I think Kevin Henney has said that.
He said that in a talk once is that, yeah, he's like, oh, you know, people say it's just semantics.
And it's like, that's literally like the most important thing.
If I say one word and you have a different definition in your head, we're going to have a problem.
He's somebody we should have on the show because I bet he's another guest that will have some pretty good come sit around the fire and hear me stories.
Yeah, we should definitely.
There's no way Kevlin Henning.
There's not no way.
There's a very low probability that he listens to this podcast.
But if you're listening, Kevlin come on come on you know there's another feature which i think is often maligned
but is actually proven to be quite great which is a class template argument deduction
anybody who's been following me on twitter or following what i've been working on the past
couple months knows that i'm very excited about it, in particular in the context of the MD-SPAN proposal, which
I actually joined the committee in 2015 to get something like the MD-SPAN proposal into C++.
It's six years later, but I'm getting closer to delivering on that goal.
But in the MD-SPAN proposal, there's this support for both static and dynamically sized extents.
And, you know, that meant that writing out some simple cases like I want an MD span that represents, you know, a three-dimensional matrix was a bit more verbose than you might like.
Because you'd have to spell out this like fairly complex set of template parameters like you'd have to do like md span
you know left angle bracket double comma extents dynamic underbar extent comma dynamic underbar
extent comma dynamic underbar you know close it was it was really unpleasant and then i realized
like a few months ago hey wait a wait a second, with CTAD,
we can make it so that you never really have to spell that out.
Like you can, in almost all cases,
you can just have those parameters be inferred
from the constructor arguments
and it'll just make the interface so much cleaner.
And yeah, and so I've been working on that.
And it just, like, again, it's an example of how this, quote, syntax sugar changed the
design.
It was such an improvement that one design change that we had made to the MD-SPAN proposal a few years ago to make it to like
optimize for a simple use case, which that design change was we made MD-SPAN a template alias
that made the simple use case a little bit easier to spell. And then we had this other thing called
basic MD-SPAN, which had a more complicated template interface for spelling out the more complicated use cases.
And I sort of realized, hey, with CTAD, we make the simple use case simple enough that we don't
need to have like this two separate names for this thing and two separate sets of template
parameters. Like we can just get rid of that. And I convinced the rest of Library Evolution on that. And I think that's another
example of, you know, hey, through language innovation, we're able to improve our library
design. Because, you know, we care about having simple intuitive syntaxes for things. And when we get new ways to make syntax simple and intuitive,
that then changes how we design things.
Yeah.
This is honestly like what you just said.
It's part of my reason,
like a part of the reason why I love APL so much is like the elegance of
what something looks like,
what your expression that you're building up
or your piece of code that you're writing,
like it affects like the end result.
Like, you know, same thing with auto, you know,
like in the past when you had to declare,
you know, the iterator on a vector,
you know, std colon vector angle type angle,
colon colon, you know, iterator. Like type angle, colon, colon, you know,
iterator, like, that's just, that's just like, it's ridiculous. And then being able to replace
that, like, with auto, I don't know, it just it completely changes, like the readability,
the elegance. And like, and readability is, is an important contributor to like maintainability of code
and like, you know, future you or future other person being able to like quickly comprehend
what that code is doing.
And yeah, like so much of like, you know, if you want to call it syntax sugar or just
like, you know, what we're using to express the algorithm or the code, you know, whatever
problem you're solving, you know, whatever problem you're solving,
you know, expressiveness is so important. And so these little things that if you can,
if you can remove something that was redundant, you know, in Java, I think still,
you end up a lot of the times, and this was previously in C++, like you've got the,
you have to state the type twice. And now it's like a core guideline
in the whatever C++ core guidelines
is like always use auto
whenever the type's redundant
and you're spelling it twice
in the same line.
And anyways, there's just this like,
you know, there's this purity to APL
that like, it's just,
all it is is like the primitives
and it's so pure.
And like whenever there's a reduction you always
see a slash and uh like in in c plus plus that's hidden you know you have to recognize that min
element and stood accumulate and find if you know they're all specializations of uh you know
they're all reductions but it just you just have to recognize it. And the same thing with like accumulate and partial sum.
Those are, those are sibling algorithms.
You know, one is the incremental results on the way to getting the final reduction.
And that's completely obfuscated by the names of those algorithms.
And yeah, there's, there's a lot to be said about, you know, over time, C++ is becoming a much, much like the slideware like that you can write now with CTAD and auto and structure bindings.
You can actually get like someone once commented on one of my talks that like my C++ code looks very Pythonic.
And I was like, that's not a bad thing. thing like well in in one of the you know i i think i think that ctad and concepts have
are sort of like the next step in the expressivity that we got out of um out of auto because the the downside of auto is there are some cases where maybe solely for readability or
documentation not because it's like significant but like you just like you want it to be clear
in the code that this is that this thing is an integral or this thing is a vector you know that
this locally declared variable you know is an integral or a thing is a vector. You know, this locally declared variable, you know, is an integral or a vector, not
necessarily something that's a parameter.
But like to me, that's really the value of auto.
Like I don't, I do use, I guess I'm not a strict adher, like almost always auto. I'll use auto where it like increases readability.
But I really love using CTAD because it lets me get a lot of the benefits of auto while also still making it clear what, making it clear what kind of thing this object is in a line, like in some particular like local declaration, like that can be really, that can be really useful.
Just like solely as documentation.
I mean, there are cases, you know, where I really, you know, I really don't care what it is, where sure, I can just write auto and that's fine. But this gives you more options without having to be completely verbose.
That's the advantage of CTAD.
And I think one of the advantages of concepts is that I can avoid verbosely spelling out the entire type of a thing, but also still, you know, describe some of the
properties of this declaration. Yeah. I have yet to use concepts like as a, uh, qualifier on a
variable type, if that's what you're talking about. Yeah. I mean, it's, it's, it's, I,
I find myself using them a lot when I'm in pseudocode, when I'm communicating with others.
I am not in a place where I can use them in work code quite yet.
I mean, there are some places where I can.
But certainly, whenever I'm just workshopping code with somebody,
I'll just default to using concepts.
And interestingly, I also will default
to using the abbreviated template syntax
where you can declare a template function
just by using like auto in one of the parameters.
And I was one of the people that was a skeptic
about abbreviated template syntax
because I was a little bit concerned
about the implications of being able to write
template functions that were not obviously
template functions.
But I'm sort of a full convert.
Bjarne was completely right about that.
And yeah, and I want, I mean, I think that the compromise solution that we have, we're
sort of the auto has to appear in the parameter list.
It's not like you can just have the concept name.
You have to have the concept name then followed by auto.
I think that was a good compromise because it still
gives you an easy way to identify that something's a template but uh i think even if we'd gone the
other route of just you know solely concept name makes it a template i think that probably would
have been fine just just based on how you use useful i've found it to be and how natural it is
yeah it's still i feel like people would have up, because how do you tell if something's
an explicit type or a concept if there's no way?
I feel like many code bases would end up like, you know.
We could have done that by convention.
Exactly, yeah.
But the committee made what I still believe is a big mistake in that we decided to give standard
library concepts snake case names instead of the camel case names that we had been using
informally in the community for a long time and that we'd been using in the standard spec to
denote name sets of type requirements pre-concepts. And I think that we should have used,
like I think if we had in the standard library
used camel case names to the concept names,
it would have established that as being the precedent
for other standard library-like things.
Code bases that use camel case for,
and not snake case for like all of their other things,
they wouldn't have had a good solution here. i i rolled some os violin for those code bases sorry i shouldn't
get all cub yeah yeah one of your two libraries not but that's not by my choice um uh but uh
i i shouldn't uh i shouldn't pretend that i don't have sympathy for a variety of coding styles.
I'm just being cute there.
I, of course, care about all coding styles.
My point is that we could have potentially done this by convention.
But I do think that the best convention is the one that we have, which is where the convention
is part of the language itself, that there has to be that auto keyword following it.
I think that was a really great, a great compromise.
Thanks for listening. We hope you enjoyed and have a great day.