Date: Tue, 10 Nov 2020 16:38:07 +0200
The problem is there. No argument. And the paper presents it clearly and
brilliantly.
And it may bite our students.
But I would argue that the problem is with using temporaries, not
specifically with range-based-for.
Yes, there is a need to teach our students: beware of temporaries and
lifetime extension, it may bite you.
For example: don't return a const reference to a parameter that you got as
const ref. It might be a temporary (great example I send my students to is
here <http://www.youtube.com/watch?v=lkgszkPnV8g&t=13m0s>).
But fixing just the range-based-for may lead to even more confusion. That
would require additional thought of how to explain things, like:
class Person {
std::string name;
public:
Person(const std::string& name): name(name) {}
const std::string& getName() const {
return name;
}
~Person() {
name = "dead!";
}
};
int main() {
// [a]
auto&& name = Person("Mo").getName(); // UB
std::cout << name << std::endl; // UB, may print "dead!"
// [b]
for(char c: Person("Mo").getName()) { // UB
std::cout << c;
} // UB, may print "dead!", should it become a defined behavior and
print "Mo"? while leaving the above UB?
}
Having the desired fix for range-based-for only, when students would see
[b] and use it in cases like [a], we would have to teach them: "no, it is
allowed only in range-based-for, which has its own special rules".
If both [a] and [b] could have a defined behavior, that could be an
interesting choice, which would be of course less bug prone and easier to
teach.
But since we are not dealing here with the life-time extension rules in
general, I think there is no way to avoid teaching the fact the temporaries
have their "strange behavior" and then I'd say it's better to have the same
"strange behavior" for both [a] and [b] above, to eliminate any additional
confusion.
For the purpose of having less bug prone code - fixing just the
range-based-for, [b] above, and leaving the other cases, [a] above, stay UB
- is an option.
But if the motivation is teaching, I'd argue it would not make it any
easier to teach. Just yet another additional difference of behavior between
two quite similar expressions (no worries, we already go with the students
via initialization rules, they are used to strange things... ;-).
Of course that's only my subjective view.
By the way,
I do teach my students range-based-for and encourage them to use it.
And I do warn them about the tricky life-time extension rules for
temporaries, saying that if you are not sure, don't use a temporary, or
make yourself absolutely positively sure that you use it correctly.
Amir
On Tue, Nov 10, 2020 at 3:21 PM Detlef Vollmann via SG20 <
sg20_at_[hidden]> wrote:
> On 11/10/20 10:24 AM, Nicolai Josuttis via SG20 wrote:
> > May be SG20 can support the paper as a whole,
> > because IMO we really have to heal C++ to make it teachable again.
> You could ask SG12 as well.
>
> > Note: So far I was not a member of this email list;
> > so forgive me if this was discussed before.
> Maybe it was discussed in SG12.
>
> Detlef
> --
> SG20 mailing list
> SG20_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg20
>
brilliantly.
And it may bite our students.
But I would argue that the problem is with using temporaries, not
specifically with range-based-for.
Yes, there is a need to teach our students: beware of temporaries and
lifetime extension, it may bite you.
For example: don't return a const reference to a parameter that you got as
const ref. It might be a temporary (great example I send my students to is
here <http://www.youtube.com/watch?v=lkgszkPnV8g&t=13m0s>).
But fixing just the range-based-for may lead to even more confusion. That
would require additional thought of how to explain things, like:
class Person {
std::string name;
public:
Person(const std::string& name): name(name) {}
const std::string& getName() const {
return name;
}
~Person() {
name = "dead!";
}
};
int main() {
// [a]
auto&& name = Person("Mo").getName(); // UB
std::cout << name << std::endl; // UB, may print "dead!"
// [b]
for(char c: Person("Mo").getName()) { // UB
std::cout << c;
} // UB, may print "dead!", should it become a defined behavior and
print "Mo"? while leaving the above UB?
}
Having the desired fix for range-based-for only, when students would see
[b] and use it in cases like [a], we would have to teach them: "no, it is
allowed only in range-based-for, which has its own special rules".
If both [a] and [b] could have a defined behavior, that could be an
interesting choice, which would be of course less bug prone and easier to
teach.
But since we are not dealing here with the life-time extension rules in
general, I think there is no way to avoid teaching the fact the temporaries
have their "strange behavior" and then I'd say it's better to have the same
"strange behavior" for both [a] and [b] above, to eliminate any additional
confusion.
For the purpose of having less bug prone code - fixing just the
range-based-for, [b] above, and leaving the other cases, [a] above, stay UB
- is an option.
But if the motivation is teaching, I'd argue it would not make it any
easier to teach. Just yet another additional difference of behavior between
two quite similar expressions (no worries, we already go with the students
via initialization rules, they are used to strange things... ;-).
Of course that's only my subjective view.
By the way,
I do teach my students range-based-for and encourage them to use it.
And I do warn them about the tricky life-time extension rules for
temporaries, saying that if you are not sure, don't use a temporary, or
make yourself absolutely positively sure that you use it correctly.
Amir
On Tue, Nov 10, 2020 at 3:21 PM Detlef Vollmann via SG20 <
sg20_at_[hidden]> wrote:
> On 11/10/20 10:24 AM, Nicolai Josuttis via SG20 wrote:
> > May be SG20 can support the paper as a whole,
> > because IMO we really have to heal C++ to make it teachable again.
> You could ask SG12 as well.
>
> > Note: So far I was not a member of this email list;
> > so forgive me if this was discussed before.
> Maybe it was discussed in SG12.
>
> Detlef
> --
> SG20 mailing list
> SG20_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/sg20
>
Received on 2020-11-10 08:38:24