♪ I'm with the big shot, yeah ♪ ♪ Yeah, yeah ♪ (lively music) (attendees applauding) - Bjarne Stroustrup has
been a guiding force for this community and has done a lot of work to promote C++ and to
build a community out of that and so I wanna, I'm looking forward to his talk today where he's gonna tell us a
little bit about concepts and what that means. Thank you very much, Bjarne. (attendees applauding) - Thank you very much. Okay, wow. If I could see all of
you, I'll be intimidated but fortunately, thanks to the lights, I can see about two lines here. So I'm going to tell you a
little bit about concepts and in some ways, that's a very old topic and others thinks it's new. You can start using it. Some of us has been using it for years. It's getting into production in places. So I'm going to talk a little
bit about generic programming then I'm going to say what do we actually get out of concepts and what are concepts and
how do you build useful ones. So, basically, you can
go back to the early aims of David Musser and Alex Stepanov. Basically, wanting to get
generic programming in as a discipline, providing
more flexible, better code with a focus on, on algorithms as opposed to data types. And my aim is sort of
fairly simply stated, making generic code as
simple as non-generic code. This is one of these
modest and ambitious aims that can drive development,
so I'm going to do that. Obviously, when you have generic code, not all code can be as simple
as if you're just writing code based on knowing that
everything is a double C. So, more advanced generic code should be not unnecessarily complicated but it can't quite be as
simple as non-generic code. And one thing I would like to emphasize and I feel I probably
won't be able to do it as much as I would like
to is it's not just for foundation libraries. There's a lot of application
code that is generic and you shouldn't just think about it as something, oh, a
standard library that you don't really need to think about. I was talking to a bunch
of theoretical physicists a couple of weeks ago. It's there in their stuff that's certainly not foundation library. I talk to generic, embedded systems
programmers that use it for certain aspects of device controls. This stuff, concepts
is not just a hysteric, it's not academic at all and it is not just for
foundation libraries. Basically, the whole game
is to write a better code and better code has all the
usual requirements here. Nothing has much to do
with generic programming but the point is that if
you write generic program in good generic code, it helps
with all of those things. And it's basically a significant help. I really don't like talking much about individual language features. A language feature and
isolation is usually boring and you can talk about
where you put your commas and semicolons and some
people like that, I don't. I tend to fall asleep over that. It's necessary at some level but I'm trying to get the big picture. So this is not a talk about
language technical details. if you want to know the latest about the debates in the Standards Committee, well, go to one of the other talks to the other committee panel
or something like that. This is not what I'm trying to talk about and there are at least four
talks at this conference that goes into details about generic programming and concepts so that's another good reason for me not to go into those details. So the concepts have been moving through the standards process, too
slowly, in my opinion of course but I'm known to be impatient. And basically, the TS was
approved two years ago and we have the explicit requires clauses in the working paper now. Barring utter disaster,
it will be in C++20. We have the shorthand
notation so that you can instead of just saying I want the type N, I can say I want here a
random-access iterator and we have requires expressions
to express things directly in the language. Not quite yet. We hope to get ranges into the
working paper in San Diego. That's less than two
months away and again, that seems to ready to work which means that you are algorithms and containers and stuff like that. I can start using concepts
and you get the benefits right out of the box with C++20. There's work going on the
function declaration like syntax. That's not settled yet and my guess is you won't get the concept type name introduces. If you don't know what
that is, well tough, you can find out and anyway, you probably won't be able
to use it in production for another couple of years. It's all available in the
GCC implementation now. So my main sort of thesis here is that genetic program
is just programming and my aim is to make this more true than it is now. And this implies that we need to improve some of our type checking
to make type checking for generic code much more like
checking for ordinary code. Eventually, the generic
code will be ordinary code. We need to improve the syntax. The template syntax is clunky. It has been clunky since the simplest syntax didn't fly in the 80s. And we have to organize
our code for generic and non-generic code in the same way. Not all of this header stuff
or templates and .cbp for code, that's the modules stuff so I'm not going to talk about that. So basically there's a history to this. In the '80s, most of the '90s, if you wanted generic code in C++, you ended up using macros and I have a paper from '81 that says we need generic programming and macros will just do it for us. I was right about the first part and I was very wrong
about the second part. Macros just poisons
everything including your IDE and your editor and scrambled your brain so we have to do better than that. In '87 and on so now, I have some fairly specific
aims for templates. I want them to be flexible. At the time, I said I
don't want a language that can only do what I can imagine. I mean maybe my imagination
is good but sure, it isn't as good as the union
of people in a room like this and I want a zero-overhead, otherwise, people are right
this sort of ugly pointers and array kind of code that they then think is more efficient, it often isn't and it's
certainly less maintainable, than a good generic code. So it had to have zero-overhead, this is C++ has to be
used for really critical embedded system stuff, it has to be used for
high-performance stuff and it is today. And then of course, I
wanted good interfaces because good interfaces is
essential for large software. That's how we partition our code. We only have two ways of simplifying code. It's abstraction and divide and conquer. Divide and conquer means putting a barrier between two parts of the
code and we get there. And as I used to say, two
out of three ain't bad but it isn't good either. So I've been trying to
figure out how to get away from the basic templates,
unconstraint templates, header-only organization because it's fundamentally not right. It may be good enough. We've done superb things as
a community in this period but we can do better. Okay, so let's take the time
machine, go back to '78. And that's how we wrote code. This is K&R code. Say that square root returns a double. We give it a two and it crashes, of course because two happens not to be a double. Well, so what? Well, we didn't say it was a double. All we can say is we can
go over to the source code and look at it and say
that square root takes an X and it treats it as a double. It does not say you must give it a double or you get an error, get a runtime error. No, you get a crash. And I had sort of one look
and another look at this, couldn't quite believe what I was seeing and made some changes in the last, in the first two months
of the C++ project. See the classes that was caught, so now we can write double
square root of double. I mean I want my square root and I want the declaration to
say that it expects a double so that if we get square root or two, I get the right answer. It converts to two to 2.0. Similarly, if I give it
some rubbish like a string, I get an error right there. This made a huge difference and
I also cleaned up the syntax so that the definition now
looks like declaration. And if you've been writing C++, you probably never seen anything else. If you've been writing C in
the last sort of 30 years, you've been seeing
things roughly like that and it's an operation like that I think we're trying to do with
concepts relative to checking. Go back to '88 and we're saying
that there must be a type which we will use as an iterator. And since we don't know too
much about the interface, it just says there must be a
type and we'll use two of them. It has to be in the header file so that we can do some compilation and I can say a vector
of integers, that's fine, list of integer's fine, vector of S, fine. Everything works fine
so we start using it. And then sorting vectors happens to work. Sorting lists doesn't work. From deep down in the
implementation of sort, we will be told that there is an absence of a subscript
or a plus or something to some type that we
probably haven't heard of because it's an implementation detail. And if you want to sort the vector of S, well, because we couldn't
get the definitions of equality in less than four types, it'll just tell you that you
can't compare two structs. And the error messages
are spectacularly bad. This is because we have duck typing. If it looks like a duck, if it waddles and it quacks, it's a duck. Unfortunately, of course,
it could be a rubber ducky or something like that and
we get these strange errors. We really want to be able to say that we want something
better than just a type. And on the other hand,
templates was a massive success. It's one of the things that kept C++ going and at the edge of things, we
have flexibility, type safety, specialization for irregular types and the basis of template, lot much, template metaprogramming and a lot of type based optimizations. The result is great
flexibility, great performance. And has huge flaws, as I
pointed out, the syntax, I mean, even its mother
couldn't appreciate it. Duck typing, error messages. The overloading with templates
is really quite complicated. Code organization gets messy
and the compilers get slow, very slow. We have to do something about it and I would like to address
all of these aspects, not just fiddle with the corners of it. So let's see what I want
and what we are getting. I would like to say that
sort takes a sortable. Concept is a specification
of what is sortable. And you can look it up in the standard. It says that you have to
have a beginning and end. Being a sequence. It has to have random
access and a value type. The element type has to be
something you can compare. Fine, unfortunately, in
the previous 20 years, compilers and users don't read the manual, however, now, we can write
this so that it works. I am using the concept
TS notation just now because then, I can test my code. This is not likely to become C++20 but it's in the TS. So, if I sort a vector, it
matches the requirements of a vector of integers. It matches the requirements of sortable. List doesn't because it
doesn't have a subscript, doesn't have random
access and sort of the Ss doesn't because value type doesn't have the comparison operator. So I get an error right there
and it should be readable. They will become even more
readable over the years when things get tuned
to use concepts well. And now, I can now sort
anything that's sortable and the implementation of sortable could simply be to call the old sortable. And if you want to be
more flexible, I can say I actually would like to
sort lists even though they are not sortable. They don't have random access and so we just define
the notion of something that lists like which has the
properties of being a sequence with elements that you can compare and I can implement them by putting them into a vector sorting them
and putting them back again. That's simple and quite often, a reasonably performing
regulation and if we do this, once it sees the list, it
will say oh, I can't do the simplest sortable but
because of lack of property but I have enough
properties to call the list so we'll do it. So we're getting the
overloading like we got the overloading for ordinary
types in the standard language, well, almost 40 years ago. And the rules for overloading,
you can look at them up, a much simpler than four basic types. And by the way, as ranges are
now coming, we can simplify. See, why do I have to say
begin and end all the time? I mean one of the principles that we're trying to work towards is to make simple things simple and the simplest case
of sorting a sequence is to sort all the
elements of a container, anything, we just give it the whole range and it'll figure out what the details are. So things are improving. Notice also, I didn't
say what the element type of the vector is. I can now deduce it. We are moving ahead and
it's getting simpler to write good code. So, if we look at it, when I want to make ordinary
code and generic code the same, I have to think about types and I have to think
about how concepts fits into a type system. And a type basically
specifies what operations I can use on an object
implicitly or explicitly and it relies on function
declarations and language rules to make sure this works and in addition, a type
specifies how an object is laid out in memory. So it says, what can you do to an object and how can you make the object. A concept on the other
hand, basically specifies how you can use an object. How implicitly or explicitly
what operations you can use and that is specified in terms of something called use patterns, basically expressions and it reflects the rules of the language. And it says absolutely
nothing about the layout of the object. And ideally, that would
be the only difference between types and concepts. We are close to that. So you can think about
simple objects of concepts, concepts that only take one argument as basically something that
is how to use an object as opposed to how to make it. Okay, so here's an example. Types and concepts. I have here a concept which is same which is that a capitalized
Int is really an int. And I can now start writing
code with that concept. So x1, it will take
anything that is an int and seven is an int so it'll do it, or I could use the integer directly. I can do operations and again, I can say, for the capitalized Int,
I'm saying the result must be something that isn't int and the other one it says it is an int. And I can pass arguments
and I can overload on it. This looks very, very
similar and it is deliberate. I even thought of using a
font that'll make it easier to tell the difference
between the capitalized Int and the lowercase int and decided no, actually, the point is they're similar. The syntax here made immovable objections in the Standards
Committee so it's unlikely you will be able to say sort a sortable. You will probably being
able to say sort a sortable or throw stuff. People seem to like that better. It's a compromise proposed
by Ville Voutilainen. So you can get very close
to what I'm saying here. One of the main reasons
this is a discussion is sortable of ref ref. if that was a concept
then would be a template and the ref ref would be
a forwarding reference. If not, it will be an r-value reference. I have taught concepts about five years. So, many dozens of people talk
to many hundreds of people, I've never seen this kind
of stuff in real life but that's a fact to
the Standards Committee and I think I can live with
what we are likely to get. So, that's sort of as
much as I'm going say about what the technicalities
about concepts. I'm going to talk about what benefits we might get out of it. By the way, my section breaks has people who contributed to this. Andrew Sutton there is
the initial implementer of the stuff you can get to see now. And he's worked very hard on specification and implementation. So basically, concept supports good design and they are doing to
design using templates roughly what classes did
to ordinary programming. It allows us to structure our code better, it allows us to think about code better. If I'm going call something
with a couple of points like draw a line, you
can do it the old way, int, comma, int, comma,
int, comma, int, comma, int and start wondering what the ints mean or you could have a point
comma point or point comma box and be more specific
about what your sign is. That kind of way of
changing the way you think is what we're after. It gives better reliability
and better maintainability. I have some practical
experience with that. And again, for overloading,
that's important because overloading is the
basis of generic programming. If things aren't called the same when they're doing the same thing semantically to different types, you can't write generic code. We have to go there. So, let's see some example here. Here's the classical example. The slightly simplified version of advance from the Standard Library. We can say that if we are
given a forward iterator, we have to do things the slow way. Dum-ti-dum-ti-dum-ti-dum-ti-
dum, go forward. If I get a random access iterator, I can just go or there in one hop. This is a very important difference and we have it in the Standard Library. Now, we can write it as simply as this. Basically, give it a vector and advance is a very simple operation, or one. If we give it a list, it will be relatively slow operation, OM, and basically getting this kind of stuff simplifies our code relative
to what we have to write today and makes it much more similar
to other kinds of code. And note that we are not actually saying you have to write a concept hierarchy and make your code rigid
and only do the things that has been pre-declared to work. Concepts are predicates, we just figure out which
predicate matches the best and get on with it. The code is simpler. So yeah, as I pointed out,
overloading is fundamental to generic programming
the way we do it in C++. We have been using a lot of traits which can be quite complicated. If you looked at code using enable_if, you know it can be headache-inducing and also, the workarounds using
these programming techniques on basically on type code, the fully generic stuff,
it gets quite complicated and slow to compile. Type checking happens at the end at the very last moment and that's, at least it's type safe
for some definition, it's type safety but it
doesn't give the errors upfront and it gives the compiler a hard time. So let's see an example. Conditional properties. They're very widespread these days. Basically, we want to say
that something like a class offers a property if
and only if another type behaves in a certain way. So here is the classic pointer type. Smart pointer. It could be a unique point, it could be a shared point or something. All of them does the equivalent
to what you see there. You have an operator dereference if and only if the thing with the
element type is a class. Otherwise, you have to dereference. So that's expressed very directly. You get a dereference. It requires that T is a class. Take a more complicated
example, I have a class pair. Still borrowing examples
from the Standard Library and still capitalizing my type so that you know it isn't
really in Standard Library. So I want to be able to make
a pair out of two values and I want to make the
pair out of two values if and only if each of the two values can be converted into the
appropriate type of the pair. And so I write this. There are two element types. if their types are convertible to the appropriate, da-da-da-da-da. In other words, the code
reflects very directly the way I expressed what I wanted. This is nice. To compare, for those of you
who haven't seen too much enable_if code, here's
the simplest version of the pointer version
written the old way. It says that there's a, there's an arrow operator,
dereference operator if, well, you can see the stuff there. This is sort of painful and
particular, it's not universal, you can't use the same
technique everywhere. I was thinking of showing
the pair constructor and I decided not to because I had trouble fitting it on a slide. For starters, there's no
place in a constructor to use an enable_if. Secondly, you have to deal
with the variety situations. It gets very messy. Concept maps the way we
think about our problems, the workarounds do not. So we simply cut out a part
of the thought process. That's good. Some people who has tried to use auto and fully generic stuff has find that it leads to some problems. Every new feature get
misused and overused. That's fine, I love auto and
so does a lot of other people so it gets you all used. and one thing we found was
that people call a function and they put the result into auto. That's reasonable if there's generic code. You don't know the exact type
or you don't want to bind it to a particular type just yet so you just bring the generic code forward and you get things like foobar x or y, you put it to some value or some type. Fine, except we find that
the programmers keep looking into the header files and
flipping forwards and backwards in the code and readability
is seriously decreased. This becomes a bug source. So, the response for now
has been put a comment in. Every time you assign something
that's not obvious, really, it's alpha type, put a comment on it. Sure, make_shared, you
don't have to have a comment because you know make_shared
makes a shared pointer but a lot of cases, if
it goes beyond that, you have to put comments in
and your code gets uglier, larger and comments are not always right. The concept, you can say
well I'll take anything as long as it's an input channel. And you can do that in any context. That clears our code a
lot eliminates programmers flicking back and forth between
different parts of the code which is very distracting
and breaking concentration and you just get much better code. Readability is one of
the benefits of concepts. And then, I don't know. Familiarity is a strong force but you look at that template there, it's really quite clunky. And for new things, there are scary people want prefix keywords and
that's how we got to here. Names become very important because there's not really a
type system here in play that says what the type name really means. I mean type name input iterator means I hope that the input
iterator is an input iterator. It's just a matter of hope. And this was what we got out
of some historical process where people were a bit
panicked or templates, they were very new at the time. When we can be specific? Things get far more readable. The version up there is slightly longer but it says much more. It says I'm going to
get an input iterator, now, take any, I'll compare and I'll take any other type as long as it's in equality
comparable with the value type. Let's see, I don't have a
definition of value type there but that's the one that looks in and finds what the value type is, the element type. And with auto on type name,
we have to sort to read the implementation again. We are back to the sort of the
K&R style of C declarations. There's simply not information enough. And here, there's people
who look at the top and says ooh, that's complicated. It isn't really. It's just unfamiliar for a day or two. I know from students that on day two, they wouldn't go back. And so, oops, I'm going the wrong way here. Sequences are expressed
as pairs of iterators. We are going to move forward. We're going to get the
range TS so we can stay instead of saying there's
a pair of iterators, we can say I want a range
however I expressed. and you get to the lower version there. It's important that we are now moving from the sort of language experimentation to the supported use of things with, with Standard Library support and such. And by the way, don't
expect optimal readability from older code that has been
bug compatibly moved forward to use concepts. And don't expect the most readability to come from the deep foundation libraries that has to have the ultimate flexibility. I have observed that the most benefits from readability actually
comes from relatively simple and relatively new libraries written by people who understand concepts as opposed to people who
understood the old techniques very well and replicates
them using concepts. So, we still have a ways to go to overcome the ways of old thinking that leaves the complexity in place expressed with the new facilities. So again, back to this notion
that auto and type name is the weakest form of typing, simply says, it's a type. In theory, we could actually do without having auto in the language. Look at that concept there, capital Auto. That's the way we could do it. If we started designing
C++ today, quite likely, the building feature
auto could be eliminated. And my aim is that you would accept the, you can accept the concept
wherever auto is now. That's backwards, I
really would like to use the fully generic concept
auto if and only if there isn't a more precise way of stating what I'm trying to state, and that's not so good. And again, this has
been around for a while. I proposed auto if auto in the
Standards Committee in 2003 and the screams of
horror were rather loud. Basically, in C++, we
tend to rely on types and find things like void star and sort of suspect, it's a code smell. And I think we will get to the point where we think the type
name and auto will be, well, a code smell. If they're there, somebody
hasn't thought it through that at least, if you have
an auto or type name T, there will be required clause coming later to see what it means but what
we really need to get away from this fairly primitive thinking that we take a type and
we do something with it and we try and write
code that doesn't work if you get something
that is slightly wrong and anyway, it gets complicated. So concept will change
the way we think about it. It's not just a hope. It's what I have observed again and again with people who have
learnt this kind of stuff. And this is not just support
for business as usual. This is major, it
changes the way we think. As I think I've said, I'm
not keen on individual language feature talks and details talk. This is not a detail. This changes the foundation. And the community as a whole
is going to be slow as usual. It takes a long, long time
to get millions of people to change their mind about anything. And there are people who
will never change their mind but individuals can do much better. So, even if we can't
get everything we want in all the code now,
maybe you can do better in your local code and maybe
you can start experimenting even if you can't deploy it yet. That's what I and others
started doing a few years ago. It works. First experiment, figure out
what works in your context, move on and it can get
to the production level. GCC has pretty good support for concepts. Clang is coming. I believe Microsoft is
thinking hard about it and it's not really that hard to implement once you get going and the
Standard Library has it so come C++20, we should all be there, so, it's time to get ready. Concepts weren't born yesterday. There's a lot of people says oh, it's new. It's dangerous, or as opposed to oh, it's new, it's great or it's new, it's really should
have been something else. No, it shouldn't have been something else. We have spent a lot of time
figuring out what fits with C++ and how to work it in,
how to work the details. Alex started in '81 called algebraic structures and then he's been calling them concepts since somewhere in the
'90s, early 90s, I think. No, no, no, no, late '80s. And I tried to find a way of
constraining templates in '88, it failed and either I know anybody else knew how to get all three
properties I wanted but we have. The STL was specified in terms of concepts even though there's no
language support for it, it's a fundament way of
thinking and therefore, it makes sense to talk about concepts even if there's no language support for it and then there's a lot of history here, I'm not going to go into it. That's a different talk but don't think it's something new or
something totally malleable. Good people have worked hard
on this stuff especially him. Okay, I haven't actually said that much about what is the concept
and now, I should. And Alex said concepts
are all about semantics. This might surprise you because
there's no semantic part to the language support, however, it says what kind of
properties a type must have, how can you use it and
you have to think about what that means, what makes sense. So basically, technically, concepts are compile-time predicates. ForwardIterator<T>, it's true. If T is a forward iterator
and it is false otherwise. And that can be used in the
language and the language rules, that's the idea. What a forward iterator is,
we can define somewhere else. We know what it is, we can
look it up in the standard. And concepts are fundamental. They tend to represent fundamental
concepts of our domains. So, if you're mathematically inclined, you have concepts like
monoid, group, field and ring. In C++, we have input
iterator, forward iterator, by directional iterator,
random access operators. These are there. Today, we just have to represent them with language support. And so, we've always had concepts. I mean, you read K&R C, the first definition
says an integral type is, an integer type is, these are concepts. Now, today, we can actually
represent that in C++ but we've been using that
for some definition of we for more than 40 years. And we, yeah. We have direct language support. So this is philosophy, you have Plato. This is the engineering. Archimedes, he's an engineer. And we must learn to
use the techniques well, not just philosophy, but
actually practical use and practical support. And the concept is good if it represents well-thought out concepts. It is not the minimum requirement
for an implementation. We've been spending
some time doing lifting and trying to find the
absolute minimal requirements of an algorithm. That's not it. The ability to add things
is not a fundamental thing for a large group of things. The ability to use ++ is not. You need something more well-thought out and there's no semantics
to an individual operation but there is a semantics to
a combination of operations like plus, minus, multiply and divide and good concept should
support interoperability, so. Hmm, okay. A lot of people think about
concepts as types of types and that's not it. You don't do too much harm thinking about a concept that
takes a single argument as a type of a type,
however, most concepts take more than one argument. If you have a template that
takes two type arguments, almost by definition, there
will be some relationship between those two type arguments. Why else are these type
arguments to the same function? To same algorithm? There has to be a relation. You're using them in combination. The second you have two arguments of different types, you need a concept with two arguments and you're out of the type of type world. The other thing is that, like templates, concept
can take value arguments. It's not that common just
now but since we now have value arguments of different
types in C++17, 20, it'll become more common. So, some of the concepts
takes things like type and, and the value. This is not type of type kind of stuff and if you look at it, that means that concepts
are not type classes and they were not meant
to be type classes. It supposed to give you
implicit conversions, mixed type operations which
people have insisted on since Fortran and that type
theorists have disliked since about the same time but this C++, we have to serve the C++
styles of uses and C++ users, they are not expressed in terms
of sets of functions either. We tried that, it didn't scale. So one thing to remember,
when you define concept, when you think about concepts is describe the concept for clusters of operations. I mean, plus, minus, multiply, divide and then you also probably
need plus equals, minus equals, plus plus and such. For stacks you have push and pop and very rarely, does a concept characterize a single operation. HasPlus and HasMinus, a very
suspect when you see them as concepts because
they don't actually work in lots of places and they're
used for ad hoc combinations of features and you
get a set of operations that doesn't actually interoperate. So, you have to think about that. Here's a plug and play example. I wrote a simple implementation of a sum. Could have been accumulate or something but I wrote it in terms of plus equals. If I did the minimal dependency on that, I would have a dependency
on a plus equals, plus equal about, something like that. The way of the dreaded ables. If your types have an able at the end, think a little bit harder. There are useful concepts
that is named like that but most of them aren't. So, basically, when I
want assistant constraint for that algorithm there, I have to think how else
might I have expressed that algorithm. Should I just take plus equal
or should I take plus equals and plus an equals? Basically, some kind of
number is a better answer because you actually also want
to have copyable unmovable, things you didn't think about
just when you were doing it so you want to express the concept, you have to raise the level of discourse to something that makes
sense basically in isolation. What is it that I'm really relying on? What is the fundamental
concept we're doing with here? It's at least an additive
monoid but I would say a number. And it's not just for algorithms. Here's a piece of code which
happens to be a very minor simplification of some real code. It is an input channel,
it takes some transport in a message decoder, what's an input transport? Well, as concept that says what it is and what's a message decoder? It's a concept that says what it is, basically saying what you can do to them and then you build up some context and then you have a variadic, variadic template here
that is used to initialize the representation of the transport. This kind of stuff is really quite hard to write and understand and
it's really hard to explain to new developers unless you have the conceptual framework provided by the concepts
that also gives you the error handling if people misunderstand this kind of stuff. So you can build it, use
it for large frameworks. Let's see, how do we define
concepts as Gabby Dos Reis who work with me and
others for many, many years for building up this kind of stuff. If you are going to use some concepts, obviously, the first choice
is to find some concepts that somebody else has built. I have a slide of some
sources but basically, the range library and the
working, (audio cutting off) standard has examples. But if you have to build your own one, the best thing to say is
that you can build it out of existing things. So, I talked about sortable. A type T is sortable if it is a sequence meaning it has begin an int, has random access means
you can subscript an end and this value type is comparable, it has the operations there. This is not brain surgery,
this is not rocket science though I'm sure we're going to use this in stuff for brain surgery and rockets. But this really is just a notation for the way we talk about these things. We have hit some fundamental concepts and it becomes easy to talk about them, easy to write them down. If you go down and want
to define some of the simpler concepts directly instead of using things done by others
like in every other area, you get to more complication
and more trickery. It's easy to say square root of two but if you're going to
write a square root, you have to know a little bit more. Are you going to use Newton-Rapson
and how do you express it and is it a better algorithm? The minute you go down
one level of abstraction, things gets more complicated, sometimes, very much more
complicated but in here, it's fairly simple. I want a type to be equality comparable, comparable to equals. So there is a support in
a language core requires which is that it can
specify what the properties of expressions are. So it says that if I have two Ts, they have to be able to be
compared to equals and non-equals and both cases, they
have to return a bool. It's, again, not brain surgery but it's more complicated than that and you can get to slightly
more complicated things. The way you get closer
to the core language, you have to represent the facilities of the core language a bit better. So, a sequence requires,
it has to be a value type. There has to be an iterator type and those are things I've
just defined up there and the must be a begin
that gives an iterator. There it is. There has to be an end
that gives an iterator and the input iterator. Sorry, the iterator of T
has to be an input iterator. I mean it's not just returning
a type called an iterator. We can actually say that
it is an iterator or else, we're in trouble. And by the way the value
type of the iterator must be the value type of the type T for comparable. So that's one way of doing it, now, we're getting down to the level. We don't usually get much deeper than this but if you look at the
definition of the range library, you can see that as we go
down closer to the hardware, to the trickier bits in the language, they get more complicated. If we can stay there at
the top slide, it's better and if we can stay out of
this, it's even better. Like our fundamental functions
like square root or sort, we get them out of the library. So do we get our concepts, there are in the working
paper, a concept session which has concepts so you
will never actually have to do equality comparable and such because they already understand it. Ranges, just about anything
to do with algorithms and iterators and there's
more places to find them. One thing to remember is
I emphasize the importance of complete concepts with semantics make sense,
they are fundamental. How do we get there? Well, there are two things. During development, we are
almost going to get it wrong the first time. So we need to get there somehow. Secondly, sometimes, we
need building blocks. So take an example here. Here, is sort of an ad hoc thing. It says that I requires
something that you can add. That's usually a mistake. I consider requires requires a code smell. If you see that in your code, you probably haven't thought hard enough because usually when we want plus, we also want these other properties like you can get a+b but
you can also increment and you can copy the thing. And quite often, you want
to construct it from a zero, things like that. So if you write some in terms of a concept, you can improve it as you go along. This kind of requires requires which I've seen in far too much code done by people who are
just coming to concepts. They think, well, I know the syntax, I can write these things. Just show me the syntax and I'll write. You get this kind of stuff
and these requirements starts growing, growing, growing and they don't lead to interoperability because each operation is done by itself. What you need to do is to
think about what can you do, what can you build up. Now, addable is one of
these dangerous addables. So you think is it really what I want? Don't I want a number? Don't know what minus also? If I don't want minus, why why don't I? The minute you generalize
sum to accumulate, you are up into the next
level of abstraction where you need a proper
concept to constrain what you can do. There's been people complaining about you can get accidental matches. If we are calculating what use of a concept matches various concepts, you can get things that could accidentally match. Now, I picked here an
example from the old days of object-oriented programming
where people were worried, sometimes, reasonably. Drawable, I define something drawable. It's something that you can draw. Be suspicious, it's
only got one operation. It's unlikely to be a good concept. It may be something we
did just at the beginning of a development before we
knew exactly what it was but be careful. It's got a single
operation, it's called able. Be careful. Anyway, so, we make a shape. It draws, we make a cowboy
because in the game industry, we're drawers, and so
now, we can do a draw_all and it draws all. Now, this is all right if draw really is the shape that draws. It's not so all right if it pulls a gun. So, that's an example from the early days of object-oriented
programming just translated into modern terminology. Accidental matches can happen but really, that's a bad concept. It doesn't represent anything fundamental. If you have done this properly, there would have been draw
operations than just draw and it's unlikely the cowboy
would have had them more. Similarly, for a cowboy,
there would be operations that probably didn't fit with
a shape like get on the horse. So the accidental match can
happen, it definitely can. Classic examples, input
iterator and forward iterator, they only change in their semantics, not in the set of operations. And if they do, you can add
disambiguation operator. I mean there's things
that forward iterator can do that input iterator is cut and I go back to the beginning operation or something like that, it's not that hard or you can use a trait class,
they still have their uses. But beware of the single
constraint concepts. Here's a thing that I found. I started like a lot of people
with concept like a number that had the four operations
and then I realize that I needed that one then
I realized I needed that one but notice one thing. My initial concept, the
incomplete concept were useful. It caught a lot of the errors
and allowed me to think and I could just improve
it as we went along. What's missing here? The fact that numbers
can be copied and moved. So I haven't quite gotten there yet but you develop these once at a time. Refinement of concepts in our
minds is a gradual process as we learn and we improve our concepts. They have names so we can do it. One thing that concept do
not do concepts as designed for C++, it does not catch all type errors and template definitions. This was a bit of a surprise to some of us if you read the early papers. It was one of the things we
wanted and we didn't get it for a variety of reasons. Here, do we really want
to catch this early? So forward iterator and it does an add. Yeah, it would be good if we could do it but as a matter of fact,
doing that puts constraints on the performance, puts
constraints on the compilation feature and it actually constrains things rather dramatically. And this kind of error
will eventually be caught but only at an instantiation time. We're falling back to
the bad old techniques for catching the errors. On the other hand, it allows us to write simple concepts simply and
so to have fast compilers and be very, very flexible and I was, look, I have a set of rules
that I'm following from the D&E, expressed in the D&E book. It's more important to
allow a useful feature than to prevent every misuse. So, why not? Basically, we decided when
we started redesigning concepts after the C++0x debugger that 90% of the benefit
came from use checking and we figured out how to do use checking with the current notion of syntax. Gabby did some experiments. We know how to do it, it's just
we got more and more worried that we were wrong to
close the system like that. How do I build these concepts up slowly before I know all the constraints? How about debug aids? How about telemetry, logging? If the concept has to be complete so that you can check and catch everything that you use in the implementation that you didn't mention in the interface, then you have a closed system and you sort of have to
reach a level of perfection before you can use it. And since you don't because perfection doesn't come early, you keep changing the interface. You want a debugger, you
have to add debug ability in the interface. You want statistics
added to an old concept, you have to add that to the interface. Now, all the user code might break. So we were beginning to get
very worried about how you, how you do a transition
from existing type of code to new code, how do you
use old code from new code, how do you use new code from old code, we decided we are not going to touch definition checking for now. This actually requires
serious syncing, not just, the fact that we know how
to do it is not sufficient. Just because you can do something
doesn't mean you have to. Okay. You can still do sum checking like static_assert. I want to know if my type
matches the range concept, there it is. And for testing of my algorithms, I can just build what's called archetypes, sort of a class called, sort of X that has all the properties
that I'm expecting and you feed that into a
static_assert with my algorithm and you see if it works. The only snag is that
you are likely to make the same mistakes when you are
defining the architect type as you did when you defined the concepts. This can be, of course, mitigated by having different
people borrow from such but just because there's no default, definition shaking doesn't mean that there's
no checking you can do because, well, you can. you can just see it there, this works. Let's see. We would like to use
high-level concepts more often. And so here's sort of a first cut on constraining merge. Merge is standard, standard algorithm and it's one of the more complicated ones. And so the first cut looks like this. I need three types. The first one is a forward iterator, the second one is a forward iterator and the third one is an output iterator. And you have to be able
to compare and assign to all of these things. This is somewhat tedious and
that's what the standard says but we are doing the
equivalent of sort of doing primitive operations. In real world, we've learned
we have to aggregate operations into functions, classes and such. And so this is a sort of, it's easy to make a mistake
when you write so much and it's hard to read. One of my favorite
phrases, headache inducing an accumulate is much worse. And by the way, this
particular pattern appears, I think, four times in the standard. So what we do is we design mergeable which is the concept
that requires three types and then does or the checking. So we need to get away from
the most simple-minded things often starting out with
single type concepts and then going into the
relationship between those concepts and simply saying I want three types and they have the proper
relationships among themselves for being mergeable. There's a more elegant
way for doing that thing. I want to introduce three type names and they should be mergeable
but that's not going to make it into C++20 though that is my favorite for expressing this idea and basically, then you just
have to define mergeable and merger boy is the one that
has the properties we require and obviously, this has the point, this has the advantage
that if you write your code like this, you can improve that
concept as you go along because the first time, you're
not going to get it right. So, having it named is helpful, having it in one place
to fix it is helpful. It is just like when
you're defining functions. You are defining functions. So the principles of
concept design is basically think harder about the semantics, think harder about the
fundamental concepts. This is why concepts are
core concepts, by the way and you have to think
about what is universal and what can be used in many
places as opposed to ad hoc. If you find you write a
lot of similar concepts and a lot of long complicated concepts like if you see something like that, it's like seeing a whole lot of statements and a large function. You should eventually
get used to thinking, oh, that's a code smell. Really, are there something
that you can abstract from it and build something manageable like that. And you can actually predict that you're going to find in this case so it's better to introduce
the name concept earlier even if you can't do all the details yet. Consistent set of properties, you make them concrete by using concepts. And basically, it's much
easier to think about your code in terms of concepts. Again and again, I have said, met people says, well, I couldn't even think of this
solution without concepts just like I've met people I can't even think about this
solution without classes. It's a fundamental thing. It helps thinking. The major inspiration for a lot of this is elements of programming by Stepanov and McJones. John Backus was in this picture, so. It's interesting. He was the one that did
Fortran, by the way. So there's a certain continuity
in the programming world. And so concrete suggestions. Make sure that you can
think about the semantics. When you see a concept, it's expressed in terms of syntax part. You should be able to think
about it as having semantics. Eventually, we may get
support for doing that. That will be called actions
but we are not there yet. Incomplete concepts are
far better than no concepts and basically, you tend to start thinking then you have simple concepts
and let them grow later. Use named concept. Requires requires is code smell. You can use static_asserts
to get upfront testing of your types and your concepts. To find the algorithms in
terms of general types, the ideal is plug-and-play,
not absolute minimization. And variables should be
constrained with concepts so that you don't have to write
in a fully functional style and you don't have to
fix the type too early to be able to get readability. This improves readability. And basically, for those of you who haven't already been using
concepts for months or years, try them. I have not personally met anybody who tried them and
went back to on typed templates because they wanted to. It's quite often that you have to go back because the implementations
are not universal yet and code bases cannot always be updated to the latest compiler
on all of this stuff but I think it's much
better if you try concepts, and so for withdrawal symptoms, for years after till they
upgrade the compilers and the code bases then you
don't think in terms of concept because you will not go back. Once you have used concept,
you think in terms of them and it improves your code even if you don't have
the language support. This is the underlying argument for that why this is fundamental and part of the basic
structure of the language. And basically, good interfaces
is key to good code. You can do it now. You simplify the code. There's a lot of complicated
template metaprogramming using enable_ifs that
gets radically simplified by using concepts. So if you're saying no, no, I'm not doing generic programming, I'm doing template metaprogramming. There's two things wrong with this. One is the word template. Metaprogramming doesn't have
to be templates anymore. A lot of constexpr
functions will help you. Secondly, concepts help with
template metaprogramming because not all of template
metaprogramming is on typed. And basically, the thing
that people always say, well, you want concepts because it gives better error messages. No, you want concepts because
of all of these other things and as a side-effect, you
get better error messages because you have expressed
your ideas more clearly so that even a compiler
can understand you. Okay, and of course, fewer errors. That's what I have to say so questions? (attendees applauding) Do we have microphones? No microphones? You can probably yell loud
enough for me to hear it. Yeah, so the question is that
he'd gotten the impression that concepts were there
to express algebras and my examples doesn't
seem to reflect that idea and I don't think that idea is correct. It's not just for math,
it's not just for things you have an underlying theory about. I showed mergeable which is
part of the standard library. That's for an algorithm and I, I showed the input channel example where we're using concepts
to constrain and specify actually the types that
take part of a composition of things. So this was why I said it's not just for foundation libraries which a slightly stronger statement. I think it becomes very, very important in application programming and I've seen that again and again. I've seen it in industrial code and I've seen it very
often in student code. - [Attendee] Bjarne, hi. - Yeah. - [Attendee] Can you go
back to slide 51 and just. - That one? - [Attendee] Yeah, can
you help me understand what the error was that
didn't get caught and-- - Oh, an input iterator
does not support plus, it only supports ++. So, this is the kind of mistake that you can actually see in real life. Somebody had in their head the notion that plus one and ++ was the
same thing but it so happens that's not the way it's
defined because plus one is to the type system, basically the same as plus 20 and you don't want to be able
to go 20 steps into a list because that is an ON operation. And so we can't distinguish
plus one from plus 10 or plus 10,000 and so the
library is defined like that and so this is the kind of mistake that we would sort of like
to catch but the side effects of catching that kind of thing is to close the interface
around algorithms so that you can't debug,
you can't have telemetry, you can't have gradual evolution and you can't have stable interfaces so we decided that this one, yeah, we'd like to do it but
we don't quite know how yet. This takes more work. I think now, if you want to say something, please, find a microphone. - Yeah, to go back to
the point about algebra is I think in a more general sense, you do have some examples
here like advanced where you're using concepts to constrain and to create an overload set. You got advanced for forward iterators, for max iterators but then
you have other examples like sort which sort
takes something sortable, merge takes something mergeable and the standard swap
takes something swappable and it's a little bit circular, right? In that case where we become unclear, well, is it sortable because I can pass it to the standard sort or is
that a customization point where someone with advanced, you're using it as customization for it. Someone could add their own advanced that was less constrained
or more constrained and it would pop into the
overload set at the right point which sounds horrible but
like that's the functionality you're enabling by like that as opposed to if constexpr
or something like that inside the implementation. With sort, are we using it
as a customization point? Is that the reason for
creating an overload set? - Yeah, I'm supposed to repeat questions. This one is a little bit hard to repeat so I'll take it in chunks and repeat if I don't get to the real point. First of all, of course,
we can do it with algebras. We've done the monoid,
ring, vector space stuff. On the other hand, we
want the open the overload that we get from C++
from the earliest days. I want to say if I want to specify the algorithms
in the standard library with concepts and once you
have done them with concept, you actually will be able to
add your own versions to it just like you can add your own
versions through overloading or if you're doing uptr and hierarchies, you can add your own versions by, by derivation. Now, some people call that ad hoc and definitely meant to support that also. - In that case, with sort, you're saying someone could
add a more constrained sort that required sortable, add also something else
and that sorta get picked. - [Bjarne] Sure. - Then you've got-- - I can use it both to get
a more constrained version. So if you wanted a, a sortable that also could do foobar, whatever it is, you would simply take
sort sortable and foobar so you can so you can
get a narrower version, a more constrained version as
opposed to what I was doing was I was opening up. How do you sort when you
don't have all the properties? You can do both. I'm going for flexibility here, not for any particular theory. And in some sense, any
concept in any algorithm can be more or less constrained. - Hi, so I've seen, in the examples I've seen so far, mostly just checks for
existence of operations on types which is kind of something that we haven't been able to do before with enable_if itself. Why does it stop there and I'll go further and also check between
relations of operations. For example, for the
concept equality comparable. It's not just enough to check that there is the
operation equal and unequal but also they should return
the opposing value, right? - I think there are two questions here. The second one is why can't we check, see semantic connections between
the functions of a concept. We had a design for that for C++0x called actions which I
actually think is very good and could do exactly that. It expresses relationship
between two operations and we just didn't think
we could get that done now and we didn't want to
complicate the process through acceptance in
the Standards Committee by throwing in more features. - [Attendee] Is that is that
where contracts could come in? I mean it's-- - No, no, contracts work on values. Concept works on types and it
is still the type relations between the operations that we
would be able to handle with, with concepts and with actions. There was a first part of your question that I don't think I answered. - [Attendee] I think I'm answered. - Okay, thank you. - I'm thinking about the
operators which like plus unsigned integers which are not defined for the whole range of the thing or less than for floats, right? And you have the concepts which would cover these types like sortable of floats, right? Would you include float
to sortable or not? I would definitely consider
floating point numbers sortable and I would just ignore another number. There's been long, long debates about this and it relates to the
issue of whether concept is a type of type. It is not, it's a requirement
of what you get in and as I pointed out repeatedly,
it may not be the complete constraint of the implementation. It is still the implementation's job to know what is coming in case, in case of a floating point number. It might get an end and it is the algorithm's job to decide whether I'd wants to do anything about it. - [Attendee] Right, but then, you wouldn't have the same
semantics for example plus, plus, it has not the same semantics between instant loads, right? So if you have a number, that
is not actually a number. - Do you want me to also check, sorry. Do you want me to also
check overflow and underflow and everything? - [Attendee] That is actually hard. - It is very hard. Checking for another number is very hard. Checking for another number only when you've got a floating point type is very hard. If I was going to work things
out for a small example, I might consider it but I
think it's a wrong approach for real-world scalable code. - Yeah, but that would
result in incorrect code. - Yeah, I mean it's a
great help for thinking but I think trying to constrain the concept used to the
things like that is wrong. I have another argument
which I can't put my mind to just now. Another end number was discussed again and again and again, I suggest you go to Andrew
Sutton's talk about concepts. He's really good at that point. And isn't two hours into a presentation, a little bit bool. - Hi, a bit concerned about the kind of coarse graining of concepts. So you kind of address this preemptively. You talked about how plusable
was not a good concept and instead okay, we have numeric, right? I think one of the
issues with this is that in general, when you're designing
classes and especially for application developers, usually, it's better to error on the side of a constrained interface. So, if you don't need multiply
then you don't write it. You can add it later if you need it. If you think it's confusing or
misleading, you don't have it so we're in the situation now where if we start using this numeric constrain in many, many algorithms even though let's say
multiplications not used like, I know accumulate probably isn't actually done this way
but imagine if accumulate was done using numeric then suddenly, any type that I write that
doesn't have multiply, we can't use with accumulate. So it's actually kind of
encouraging people to like slot themselves into these concepts which it can be a good thing in some cases but I think sometimes,
it's actually pretty bad if you're basically saying to people, if you wanna reuse this
high-quality generic code, you better add like all
these other operations you don't really need and
the algorithm doesn't need. - This is a very old debate. Should you have absolute minimal? Yeah, I'm repeating the question. Do you have absolute minimal requirements or do you encourage people
to build more complete types? And I don't think encouraging people to think about where their
types fit semantically and put some extra work in
is encouraging sloppiness on the contrary. You need to look at
experience and my experience and other people's experience has been that encouraging plug-and-play, encouraging high level concepts
is useful and important. Furthermore, I'm not
being rigid about that. Notice I've said you evolve concepts and furthermore, you can have
various levels of concepts. It would be quite
reasonable to have concept for things that could
be added and subtracted but not having multiply. So you have that flexibility. When you see a new feature,
especially a major new feature, I find the programmers are amazingly good at imagining problems and they are actually quite
often dramatically lousy in imagining benefits. And my view is that any language feature, any concept if I've used upon has benefits and potential errors and I consider software development fundamentally an engineering discipline as opposed to a branch of mathematics or type theory. And you have to evaluate the benefits and the disadvantages and then you have to observe
what happens in real life and I have come to the conclusion after watching this kind of
stuff and people using it for a decade plus that aiming for more general
and more complete concepts actually improve code. - Thank you. - With introduction of templates, we had to change syntax to allow things to be constructed to move
syntaxes intended for classes. So now we can use it for building types. So we made changes to the
language to allow you to use it more uniformly. Now, with concept, I see similar danger. The concept will be
easier to use obviously, but it could be realized in multiple ways. Do you see ways to change
the language to help us realize the same concept in
multiple implementations? - [Bjarne] I'm not sure I
understand the question. - Imagine that we talk about sortability. In future you might be able to use it and do it using the
spaceship operator, always, in the past, you'd collect
some other operators, you'd still get the
same thing semantically but it's really different implementation. - So the point is that
you can implement things in different ways and you
need some freedom to do this and that relates to the previous question. Do you define your
concepts really tightly? Sortable is defined in terms
of begin end and less than, that's what the standard says and that's what the concepts is. As a user, you then use
the name of the concept. When the standard changes, say to, say that sort uses the
spaceship operator directly, your code will not change. Your requirement on your users may change and you may have to fix that
because the standard changed. But there's this interaction
through the specification of the concept that
gives you some freedom. And that your argument is an argument for the more general concepts as opposed to the minimal constraints. - I have a question about
the relevance of constexpr in some of this. I know within a function, for example, if constexpr inside a template expansion has different properties in some ways than it does outside that, how would the constexpr interact with say function definitions
and concepts it requires? - How would constexpr functions relate to the way it's used in concepts. There are currently not in concepts a way of requiring constexpr
functions, for instance. That is something we've
discussed over there. - I was thinking more of trying
to express test properties using constexpr instead of
forcing people to use enable_if. Inside a function, that's very simple but I was wondering if
there is a way to do that with concepts as well.
- I would like to see most users of enable_if disappear. They are more error
prone, more complicated. You sometimes have to have both the enable_if of a condition, the enable_if on the
opposite of the condition. If you have two predicates, you can end up with four
versions of the code. This is horrid. That's eliminated by concepts, that helps. Constexpr functions fit with concepts because they both ways
of expressing a predicate if they return a bool. So, it works together. There's a few rough edges, you cannot write a concept this is require constexpr function. By the way, code using concepts compile faster than code using workarounds. Eric Niebler reported two weeks ago that the range is TS that
exists in two versions, and enable_if and the concepts compile 25% faster with concepts. Expressing things directly is better than representing
things directly and we are winning on all
accounts with concepts or the previous work around. - [Attendee] Thank you. - [Attendee] Regarding the idea of SFINAE and default template arguments, template deduction. What is the opportunity that exists between concepts as it exists right now and the ability for those to participate in template template arguments
in deduction in SFINAE style sort of errors that you may argue-- - As far, okay, the question is how does
template template arguments fit into it? I think it they simply fit into it. That is you can express concepts that involve
template template argument. Again, this is a level of
detail I don't want to go into for the fundamental things but I think you take the fundamental ideas,
the fundamental techniques in the standard, you pull the crank and out comes the right solution. - [Attendee] Secondly, as well, with the ever widening gap between C and C++ for this matter, there have been many features
that have been introduced into the language over the
years that have allowed me to do certain things that
I could still accomplish and compile with the previous
generation of our language. How do concepts and their forward slash backwards
compatibility for that matter restrict me from porting code or using development environments that exist in both C and C++? - Can you use concepts
both with over compilers and C and C++. Well, concepts are not actually meant to be backwards compatible, obviously. And I think C is totally lost in this game because it doesn't have proper generics. You can't have concepts
as a language feature supporting macros and in practical terms,
if you need to work on a variety of environment, some are old, you can use things like if you restrict yourself to
explicit requires clauses, you can have requires macro
that turns into nothing for old environments and so what you can do is
you can develop your stuff on a modern compiler, get
the checking in place, do the testing on a modern compiler then throw the switch so that
the concept becomes nothing and if you have not used overloading, it'll then run correctly on old compilers. A slightly more subtle version of that is to define your actual concepts as sort of capital concept macros that either turn into the
concept for the modern compiler or to type name on the old one. Again, you lose overloading but
you can compile with GCC 4.2 if you're unhappy enough. It's pretty horrid but there are ways of using older code, older compilers but you have to do nasty things. - [Attendee] And will there
be the ability to default or specialize on concepts
within template programming? - Will be thing for
default and specializing? Specializing, yes, defaulting,
I don't quite understand what it means in particular, so probably-- - [Attendee] Some other time, I suppose. - Some other time. - [Attendee] Hello, I'm coming actually from a theoretical physics background and I'm very excited
about these developments that you've just talked about. I have a question much of or some of what can be achieved very
elegantly with concepts has previously been
achieved by inheritance through abstract classes and I wonder what is this take that you have on the position of abstract
classes in the future with concepts being present? - So, abstract classes versus concepts. One thing I failed to emphasize because I've become so used to it, concepts is a zero overhead feature. There is no runtime cost. And that's important and I
should have said so and I, once you get used to things, you forget. So for abstract classes, if you want a binary compatible
upgradable interface, abstract classes are unbeatable. Just a set of functions. On the other hand, it causes
indirect function call that can be expensive. Concepts are the opposite. There's no overhead, they're just compile time predicates. On the other hand, since
concepts are independent of the layout of the
objects they manipulate, they don't actually address the issue of binary compatibility at all. So I think they're sort of neutral. You have to orthogonal chores. - [Attendee] Okay, thank you. - [Moderator] So we do have
12 minutes till the next talk. If you would like to ask Bjarne question, maybe come to the stage
and talk to him over there. We'll get to the next talk here. - Okay, thank you. - [Attendee] Thank you. (attendees applauding)
Oh god.... The cppcon binge watching begins....
Already up the next day.. awesome!
Worth pointing out, because this will surely be a common mistake with CTAD. At 18:02:
Gives you a
vector
holding two iterators toc
, it does not call the iterator pair constructor. What you need to do is:Also
vector{c}
is not a thing. There is no constructor forvector
that takes an arbitrary range.Wow, that was fast! I wasn't expecting to be able to watch these for a couple of weeks.
I'm still skeptical about the lack of definition checking, but I guess time will tell.
On slide 26 (~29:32) he uses input_channel as type.
Is input_channel a concept? is it a "narrow" auto?
anyone know where the clang implementation of concepts is right now?
I saw a post a while ago about there being an experimental branch on godbolt, but haven't seen much about it since - and clang 7 just shipped without it, from what I can tell.
Presentation Slides, PDFs, Source Code and other presenter materials are available at:
https://github.com/CppCon/CppCon2018
Edit:
They are not uploaded yet, but I assume they will be uploaded under this repository. Copied the link from the youtube description.
I would appreciate if someone who found the slides could post a link here. I can't watch the video at work
Is the (Concept auto val) syntax really the way we’re heading? It’s awfully redundant.