"The problem in this community is: the more scary a proposal is, the more people like it". Such a legendary quote! Great summary of the C++ standard: lots of compromises and nobody is 100% happy or even 80% happy.
"Ask application developers". Hope there are still application developers using Cpp. I feel very lonely because almost all of my colleagues are now using java, javascript, python ...
A nice talk by Nicolai. I believe we must all be masochists using such a language.Anyway - it is not that bad. Just use uniform initialisation and we can still love C++.One thing I noted was that Nicolai did not make the constructor for Customer explicit. This is a bug, perhaps because he wanted to simplify the example.
I agree with abseil, this is what I generally use anyway. '=' is more intuitive and easier to read, and it's better to work to fix all possible issues with '=', rather than switching everything to '{}'.
One way to init is missing: ¨int i = int(42);¨ It sort of works because it init i to 42, but this is in effect a call to a C style cast so ¨int i = int(42.3);¨ would compile without any warnings about the precision loss.
Yes, but that is because you doing the conversion explicit. One common pattern with construction is that implicit construction has no loss of data, but an explicit one might. So int i = 42.3 means initialize i to 42.3 with no loss of data, where int i = int(42.3) means initialize i to 42.3 and I don't care about data loss.
From what I'm reading, you shouldn't move your return value because the optimizer will either do NRVO or move it anyway. If you move it explicitly, you effectively remove any possibility of NRVO.
Mike Prikhodko yes but there is an rvalue qualifier on the member function. Doesn’t this mean the value will be implicitly moved or is NRVO improperly designed for rvalue quailified member functions?
@@N00byEdge No, this doesn't mean the value will be implicitly moved. It will not. Local variables do that. But member fields -- alas. And NRVO is not possible for them either. So omitting std::move() here is a pessimization. The rvalue qualifier on the member function means that the member function has been called for an rvalue *this. But! Inside that member function, *this is still an lvalue (unless you std::move() it again). This is the same situation as with rvalue function arguments, which are lvalues inside the function until std::move'd. You can check the following example on godbolt. It calls Name's copy ctor instead of move ctor in case that field is returned without applying std::move to it. #include struct Name { Name(); Name(const Name&); Name(Name&&); Name& operator=(const Name&); Name& operator=(Name&&); }; struct Foo { Name name; const Name& getName() const& { return name; } Name getName() && { //return std::move(name); return name; } }; void bar(Name& dest, Foo& src) { dest = std::move(src).getName(); }
It is funny how 90% of problems presented here are impossible to do in Rust programming language. The lifetime issues are a great example of this: thanks to the compiler support for tracking of the lifetimes and a powerful type system (allowing for, let's say having a type with a runtime lifetime tracking). Many problems presented here, are that the drawbacks and side-effects of many syntaxes (which have to be perfectly memorized) are implicit.
The question is how much you have to pay for those features, e.g. Rust compiler tracking objects' lifetimes. How long does it take to compile 1 MLOC Rust codebase? Oh wait, you probably can't answer that, because there is no such codebase, because no one is using Rust seriously.
All programming languages are perfect until they are used by a large enough number of people, have been around for a long enough time, and care about backwards compatibility. Recently Rust is all the rage in the gamedev community - a community who is notorious for entitlement and nonstop complaining by the way - but I assure you IF Rust ends up being popular enough so as to have large bodies of code written in it over many years, the very same people will start bashing it for various as of yet unforseen reasons. Which reminded me of Bjarne's saying that there are only two types of programming languages: the kind people complain about and the kind nobody actually uses. We have heard how awesome the many functional programming languages out there are, yet I have yet to come by one single program written in a functional language on any of the computing devices I have used over the past 25 years.
btw Nicolai miss one important fact, meaning of `std::string&&` and `T&&` is same in both cases, both mean "rvalue reference to sth", problem become this "sth". This change overall effects of it. `T&&` use automatic type deduction and reference collapsing (set `T` to `const std::string&`), this both combined give you forward reference.
@@MeetingCPP I do not said "generic", I said "rvalue reference to sth" and there is BIG difference. `T` is some type, and this type can be reference too. My whole point was that this can be rvalue reference to some lvalue reference `(std::string&)&&`. And now we have rule of collapsing them, `& &&` is change to `&`. And effective type of `T&&` is `std::string&`.
@@MeetingCPP From the message, it is clear that von nobody knows that. He is in fact explaining how it works, that it is an emergent property and idiom, not an actual language thing itself. Thus, some mention of T&& as a Universal Reference may be incorrect, if the context is not that of the application of the idiom. E.g. the grammar itself, primitive language features, and specifically when understanding the formal rules of the standard.
On slide 2, the biggest issue I see on a quick reading is the non-const version of getName. It is exactly the same as the const version, so why bother? And it lets the caller modify name in-place without doing the validation of a setter. (and it returns a reference whose lifetime is dependent on another object).
If you write code that needs compile across multiple compilers and platforms especially if you need it to work on Apple clang and Visual studio, and not just linux gcc and clang. I would recommend against curly bracket initalization as it behaves slightly different in how it resolves on the buggy macOS and windows compilers, and even in some cases different between C++ versions in the good gcc and clang versions. I have had to make recent Chromium code cross compiler portable (google now only use a single clang version across all platforms), and the 90% of the issues I need to solve, are caused by overly enthusiastic use of curly bracket initialization (and a mess of constructors and types).
@@vladimiro3059 In my experience gcc is the closests to the standard. Clang accepts too much illegal code. It gets all the features in, but accepts wrong code it _really_ shouldn't accept, often even without warnings (especially constexpr and noexcept stuff). Also if you count Apple clang as clang, that one is pretty bad standardwise, since it is forked from a rather old clang version at this point, though that it is hardly the clang project's fault, it is still a clang compiler you need to work with (or fight) as a developer. Fortunately it is not a competition. Gcc has improved in compile speed immensive after having to compete with clang, and clang has cought up in optimizations. Lets hope both stay strong and push eachother forward.
int i; well ok, nothing to say here. i = 42; // OK nothing to say here either. 'i' is not a pointer. The computer *may* use it *as* a pointer, but there is no guarantee that 'i' will *ever* reside in memory (which is a requirement for it to have an address... it shouldn't be like this, but it is how it is so ok) 42 = i; // ERROR because of the previous one, i have to agree. int* q = &42; // ERROR now this just pisses me the fuck off. No matter what, the integer value '42' EXISTS IN MEMORY at the moment of execution of this statement. I SHOULD be able to get the address of it.
You have very wrong assumptions. What you want to do is broken at least on two levels. 1) No, 42 does not have to be in memory and is very unlikely to be found there. Have you ever heard about an immediate operand in a machine instruction? 2) What exactly you expect to happen when you write a new value through your pointer 'q'? E. g. *q = 45?
by asking me whether i know what an immediate operand is, you answered your own question. The location of that operand is the address of that value. i expect the obvious to happen an error if code is readonly, the operand to change if not.
People do not seem to understand.. It is EASY to code in C++. The difference is it gives you the option to make it better where as most of the stuff he is talking about is stuff things like Python or whatever would do by default and leave you zero control over. Your options are, take the easy way out, don't give a shit and let it do what it does but your performance will suffer, something I might add is relative as your basic or even worst C++ code will likely outperform Java and no doubt out perform Python. When you need that extra bit... then you get to the nitty gritty and start to rip into the language and abuse its full potential. These things are done after decades of debate by extremely intelligent people and have decided it will make the language better.... if it confuses us, perhaps we are just not on their level.
Watching this talk made my blood boil. C++ was a mistake. Forget "how do I teach this to beginners?". The fact that you're considering teaching any of this to anyone in the first place is the problem.
@Vineel Reddy probably you are a novice and frustrated by the difficulty of C++. I agree with you, C++ is a tough language to master (it requires couple of years of daily learning). But, once you master C++, you will never look back because the sky is your limit.
it is impossible to master it, because by the time you learn the current standard well enough to call yourself a master, the next standard will have arrived and you now need to play catch up: you need to keep using the previous standard, because that's what you're best at, but you need to also use the new standard, because you want to master it. And the cycle repeats. You are chasing a moving target.
"The problem in this community is: the more scary a proposal is, the more people like it". Such a legendary quote! Great summary of the C++ standard: lots of compromises and nobody is 100% happy or even 80% happy.
"Might be nightmare for application programmers...but who cares"... the hard truth... Really nicely put!
"Ask application developers". Hope there are still application developers using Cpp. I feel very lonely because almost all of my colleagues are now using java, javascript, python ...
vb, c#...
this is madness
it gets increasingly easier to code in asm -_-
@Vineel Reddy, maybe if you were a bit smarter...
@Vineel Reddy Lmao. Go cry somewhere else. Let me guess, you're one of those people who keep hyping pure Functional Programming, right?
Amazing talk! Definitely Nicolai's best talk and definitely most entertaining!
A nice talk by Nicolai. I believe we must all be masochists using such a language.Anyway - it is not that bad. Just use uniform initialisation and we can still love C++.One thing I noted was that Nicolai did not make the constructor for Customer explicit. This is a bug, perhaps because he wanted to simplify the example.
even his book is really good.
Bruh I'm so curious, are you Indonesian?
@@BossGxngOfficial how could you are anywhere
I agree with abseil, this is what I generally use anyway. '=' is more intuitive and easier to read, and it's better to work to fix all possible issues with '=', rather than switching everything to '{}'.
One way to init is missing: ¨int i = int(42);¨ It sort of works because it init i to 42, but this is in effect a call to a C style cast so ¨int i = int(42.3);¨ would compile without any warnings about the precision loss.
Yes, but that is because you doing the conversion explicit. One common pattern with construction is that implicit construction has no loss of data, but an explicit one might. So
int i = 42.3 means initialize i to 42.3 with no loss of data, where int i = int(42.3) means initialize i to 42.3 and I don't care about data loss.
On the slide 24, I think you can also move name out of a temporary object to avoid string copy.
From what I'm reading, you shouldn't move your return value because the optimizer will either do NRVO or move it anyway. If you move it explicitly, you effectively remove any possibility of NRVO.
@@Tyranisaur NRVO only applies to local variables. Here "name" is a member of the "this" object.
Mike Prikhodko yes but there is an rvalue qualifier on the member function. Doesn’t this mean the value will be implicitly moved or is NRVO improperly designed for rvalue quailified member functions?
@@N00byEdge No, this doesn't mean the value will be implicitly moved. It will not. Local variables do that. But member fields -- alas. And NRVO is not possible for them either. So omitting std::move() here is a pessimization.
The rvalue qualifier on the member function means that the member function has been called for an rvalue *this.
But!
Inside that member function, *this is still an lvalue (unless you std::move() it again).
This is the same situation as with rvalue function arguments, which are lvalues inside the function until std::move'd.
You can check the following example on godbolt.
It calls Name's copy ctor instead of move ctor in case that field is returned without applying std::move to it.
#include
struct Name
{
Name();
Name(const Name&);
Name(Name&&);
Name& operator=(const Name&);
Name& operator=(Name&&);
};
struct Foo
{
Name name;
const Name& getName() const&
{
return name;
}
Name getName() &&
{
//return std::move(name);
return name;
}
};
void bar(Name& dest, Foo& src)
{
dest = std::move(src).getName();
}
What should I teach?
Pascal.
It is funny how 90% of problems presented here are impossible to do in Rust programming language. The lifetime issues are a great example of this: thanks to the compiler support for tracking of the lifetimes and a powerful type system (allowing for, let's say having a type with a runtime lifetime tracking).
Many problems presented here, are that the drawbacks and side-effects of many syntaxes (which have to be perfectly memorized) are implicit.
The question is how much you have to pay for those features, e.g. Rust compiler tracking objects' lifetimes. How long does it take to compile 1 MLOC Rust codebase? Oh wait, you probably can't answer that, because there is no such codebase, because no one is using Rust seriously.
All programming languages are perfect until they are used by a large enough number of people, have been around for a long enough time, and care about backwards compatibility.
Recently Rust is all the rage in the gamedev community - a community who is notorious for entitlement and nonstop complaining by the way - but I assure you IF Rust ends up being popular enough so as to have large bodies of code written in it over many years, the very same people will start bashing it for various as of yet unforseen reasons.
Which reminded me of Bjarne's saying that there are only two types of programming languages: the kind people complain about and the kind nobody actually uses. We have heard how awesome the many functional programming languages out there are, yet I have yet to come by one single program written in a functional language on any of the computing devices I have used over the past 25 years.
btw Nicolai miss one important fact, meaning of `std::string&&` and `T&&` is same in both cases, both mean "rvalue reference to sth", problem become this "sth". This change overall effects of it. `T&&` use automatic type deduction and reference collapsing (set `T` to `const std::string&`), this both combined give you forward reference.
No. T&& is not a generic rvalue reference, it is a universal reference:
isocpp.org/blog/2012/11/universal-references-in-c11-scott-meyers
@@MeetingCPP I do not said "generic", I said "rvalue reference to sth" and there is BIG difference. `T` is some type, and this type can be reference too. My whole point was that this can be rvalue reference to some lvalue reference `(std::string&)&&`. And now we have rule of collapsing them, `& &&` is change to `&`. And effective type of `T&&` is `std::string&`.
@@MeetingCPP From the message, it is clear that von nobody knows that. He is in fact explaining how it works, that it is an emergent property and idiom, not an actual language thing itself. Thus, some mention of T&& as a Universal Reference may be incorrect, if the context is not that of the application of the idiom. E.g. the grammar itself, primitive language features, and specifically when understanding the formal rules of the standard.
Complexity breeds complexity? (Don't remember where I've heard this)
On slide 2, the biggest issue I see on a quick reading is the non-const version of getName. It is exactly the same as the const version, so why bother? And it lets the caller modify name in-place without doing the validation of a setter. (and it returns a reference whose lifetime is dependent on another object).
Its there for making a later point, see slides 20++.
If you write code that needs compile across multiple compilers and platforms especially if you need it to work on Apple clang and Visual studio, and not just linux gcc and clang. I would recommend against curly bracket initalization as it behaves slightly different in how it resolves on the buggy macOS and windows compilers, and even in some cases different between C++ versions in the good gcc and clang versions.
I have had to make recent Chromium code cross compiler portable (google now only use a single clang version across all platforms), and the 90% of the issues I need to solve, are caused by overly enthusiastic use of curly bracket initialization (and a mess of constructors and types).
Problem is with msvc and g++ compilers. Clang is the most close to standard.
Our recommendation is pointless.
@@vladimiro3059 In my experience gcc is the closests to the standard. Clang accepts too much illegal code. It gets all the features in, but accepts wrong code it _really_ shouldn't accept, often even without warnings (especially constexpr and noexcept stuff). Also if you count Apple clang as clang, that one is pretty bad standardwise, since it is forked from a rather old clang version at this point, though that it is hardly the clang project's fault, it is still a clang compiler you need to work with (or fight) as a developer.
Fortunately it is not a competition. Gcc has improved in compile speed immensive after having to compete with clang, and clang has cought up in optimizations. Lets hope both stay strong and push eachother forward.
What happened to KISS?
MIIC conquered KISS.
Make It Increasingly Confusing.
What about
std::string getName() && {return std::move(this->name);}
I use C++ daily and like it. That said, would Turing kill himself again after seeing this talk?
int i;
well ok, nothing to say here.
i = 42; // OK
nothing to say here either. 'i' is not a pointer. The computer *may* use it *as* a pointer, but there is no guarantee that 'i' will *ever* reside in memory (which is a requirement for it to have an address... it shouldn't be like this, but it is how it is so ok)
42 = i; // ERROR
because of the previous one, i have to agree.
int* q = &42; // ERROR
now this just pisses me the fuck off. No matter what, the integer value '42' EXISTS IN MEMORY at the moment of execution of this statement. I SHOULD be able to get the address of it.
You have very wrong assumptions. What you want to do is broken at least on two levels.
1) No, 42 does not have to be in memory and is very unlikely to be found there. Have you ever heard about an immediate operand in a machine instruction?
2) What exactly you expect to happen when you write a new value through your pointer 'q'? E. g. *q = 45?
by asking me whether i know what an immediate operand is, you answered your own question. The location of that operand is the address of that value.
i expect the obvious to happen
an error if code is readonly, the operand to change if not.
People do not seem to understand.. It is EASY to code in C++. The difference is it gives you the option to make it better where as most of the stuff he is talking about is stuff things like Python or whatever would do by default and leave you zero control over. Your options are, take the easy way out, don't give a shit and let it do what it does but your performance will suffer, something I might add is relative as your basic or even worst C++ code will likely outperform Java and no doubt out perform Python. When you need that extra bit... then you get to the nitty gritty and start to rip into the language and abuse its full potential. These things are done after decades of debate by extremely intelligent people and have decided it will make the language better.... if it confuses us, perhaps we are just not on their level.
As I a russian, I feel offended by C++
I think C++ offends everyone man don't feel bad
Just to confuse Russians
Watching this talk made my blood boil. C++ was a mistake.
Forget "how do I teach this to beginners?". The fact that you're considering teaching any of this to anyone in the first place is the problem.
@Vineel Reddy probably you are a novice and frustrated by the difficulty of C++. I agree with you, C++ is a tough language to master (it requires couple of years of daily learning). But, once you master C++, you will never look back because the sky is your limit.
it is impossible to master it, because by the time you learn the current standard well enough to call yourself a master, the next standard will have arrived and you now need to play catch up: you need to keep using the previous standard, because that's what you're best at, but you need to also use the new standard, because you want to master it. And the cycle repeats. You are chasing a moving target.