♪ I'm with the big shot, yeah ♪
♪ Yeah, yeah ♪
- 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.
- Thank you very much.
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,
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.
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,
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,
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,
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
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.
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.
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.
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.
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.
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.
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.
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, 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.
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
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
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,
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.
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
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
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.
You can still do sum checking
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,
doesn't mean that there's no checking you can do
because, well, you can.
you can just see it there, this works.
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,
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
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
this has the point,
this has the advantage that if you write your code
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
John Backus was in this picture, so.
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,
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?
Do we have 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
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.
- [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,
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
- [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
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
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
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,
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
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.