Discussion:
[std-proposals] auto and expression templates using attributes
Till Heinzel
2018-10-16 08:44:22 UTC
Permalink
I have previously worked a lot with expression templates, and using them
together with auto is a pain - errors crop up all the time, and I ended up
wrapping most of the functionality away.
I have been looking at P0672R0
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0672r0.pdf> and I
think that sounds like a pretty good idea, but it also seems to be a quite
invasive solution. I also looked at this discussion: a C++17 library
solution to N4035, expression templates, auto and class template argument
deduction
<https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/%22expression$20template%22%7Csort:date/std-proposals/ErPSC92ERDU/cUHPa_bgAgAJ>,
which does not seem to address the problem, as it is still up to the user
to see when to use the proposed type.

So instead, I would propose adding a new attribute [[temporary_type]] that
tells the compiler to emit a warning when an object of the type is used in
a non-temporary context. I am not too certain on value categories, but I
think it would work well if this would just mean a warning when the object
is an lvalue. The user then knows to call some function, or to use a cast
or an explicit type for the assignment, whatever works in the context of
the library.
An accompanying attribute could be [[allowed_temporary_lvalue]], to
suppress the warning at the call site. This would allow using the type
warning-free within the library where it is created, and clearly express
that this is a special case, not the primary use case for this type.

While I find P0672R0 interesting, I also think it may be overkill for a
relatively niche problem. I ran into it using armadillo (linear algebra),
the Wikipedia site specifies mostly linear algebra as a use case, and a
quick google search ends up with the same thing. So on a value-effort
graph, I think P0672R0 has to much effort for too little value. Attributes
do not change the core language significantly, do not introduce new syntax
or complexities, they simply tell compilers to emit warnings under certain
conditions. That seems like a much cheaper way of getting some safety into
the use of expression templates. It does not allow the drop-in replacement
of expression templates, but I consider that a somewhat minor problem
compared to the bugs that crop up when using them in an auto-riddled,
modern-C++ world.

I am not an expert on the standard, so I would love some comments on this.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/2f62daa1-aeb8-4a56-af97-d622a8b9030a%40isocpp.org.
Arthur O'Dwyer
2018-10-17 15:08:35 UTC
Permalink
Post by Till Heinzel
I have previously worked a lot with expression templates, and using them
together with auto is a pain - errors crop up all the time, and I ended up
wrapping most of the functionality away.
I have been looking at P0672R0
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0672r0.pdf> and
I think that sounds like a pretty good idea, but it also seems to be a
quite invasive solution. I also looked at this discussion: a C++17
library solution to N4035, expression templates, auto and class template
argument deduction
<https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/%22expression$20template%22%7Csort:date/std-proposals/ErPSC92ERDU/cUHPa_bgAgAJ>,
which does not seem to address the problem, as it is still up to the user
to see when to use the proposed type.
So instead, I would propose adding a new attribute [[temporary_type]] that
tells the compiler to emit a warning when an object of the type is used in
a non-temporary context. I am not too certain on value categories, but I
think it would work well if this would just mean a warning when the object
is an lvalue. The user then knows to call some function, or to use a cast
or an explicit type for the assignment, whatever works in the context of
the library.
An accompanying attribute could be [[allowed_temporary_lvalue]], to
suppress the warning at the call site. This would allow using the type
warning-free within the library where it is created, and clearly express
that this is a special case, not the primary use case for this type.
While I find P0672R0 interesting, I also think it may be overkill for a
relatively niche problem. I ran into it using armadillo (linear algebra),
the Wikipedia site specifies mostly linear algebra as a use case, and a
quick google search ends up with the same thing. So on a value-effort
graph, I think P0672R0 has to much effort for too little value. Attributes
do not change the core language significantly, do not introduce new syntax
or complexities, they simply tell compilers to emit warnings under certain
conditions. That seems like a much cheaper way of getting some safety into
the use of expression templates. It does not allow the drop-in replacement
of expression templates, but I consider that a somewhat minor problem
compared to the bugs that crop up when using them in an auto-riddled,
modern-C++ world.
I am not an expert on the standard, so I would love some comments on this.
(FWIW: A blog post
<https://quuxplusone.github.io/blog/2018/07/12/operator-auto/> I wrote back
in July on the subject.)
I am surprised that P0672R0
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0672r0.pdf> does
not have any R1 in the San Diego mailing.

(1) I like P0672's approach with `using auto = Matrix;`.

(2) I *dislike* P0672's cavalier suggestion that

*auto* x = A*B;

should behave fundamentally differently from

auto f = [](*auto* x){ ... }
f(A*B);

in this respect. That kind of arbitrary subtlety is the bane of C++ and we
don't need more of it.

(3) I am skeptical that either P0672 or Till's suggestion would solve the
problem of

std::vector<bool> vec(100);
for (auto& elt : vec) {
elt = true;
}

which has been presented recently as a classic example of proxy types
ruining everything for everybody.
But perhaps we don't need to solve that problem; we just need to teach
everyone to use the correct

std::vector<bool> vec(100);
for (auto&& elt : vec) {
elt = true;
}

which Just Works for every type in the world, including proxy types and
const vectors and even ranges that return rvalues from their iterators.

(4) Till, I think your idea is possibly fruitful, but you'd have to work
out the corner cases — ideally by making a compiler implementation of the
attribute (e.g. in Clang). What counts as an "lvalue"? What happens in the
"auto&& elt : vec" example above? What happens if I just say "const auto&
T = A*B;", even if I never use `T` as an lvalue? What happens if I do that
and then use `Matrix C = std::move(T);` — does that count as an lvalue use
of `T`? And so on. If you can get a Clang attribute with unit tests that
look good, then it might help programmers even if P0672 never makes any
more progress.

my $.02,
–Arthur
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/2bf1f2eb-04c6-4985-a86a-123b25662eff%40isocpp.org.
h***@gmail.com
2018-10-19 03:12:43 UTC
Permalink
Post by Till Heinzel
I have previously worked a lot with expression templates, and using them
together with auto is a pain - errors crop up all the time, and I ended up
wrapping most of the functionality away.
I have been looking at P0672R0
<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0672r0.pdf> and
I think that sounds like a pretty good idea, but it also seems to be a
quite invasive solution. I also looked at this discussion: a C++17
library solution to N4035, expression templates, auto and class template
argument deduction
<https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/%22expression$20template%22%7Csort:date/std-proposals/ErPSC92ERDU/cUHPa_bgAgAJ>,
which does not seem to address the problem, as it is still up to the user
to see when to use the proposed type.
So instead, I would propose adding a new attribute [[temporary_type]] that
tells the compiler to emit a warning when an object of the type is used in
a non-temporary context. I am not too certain on value categories, but I
think it would work well if this would just mean a warning when the object
is an lvalue. The user then knows to call some function, or to use a cast
or an explicit type for the assignment, whatever works in the context of
the library.
An accompanying attribute could be [[allowed_temporary_lvalue]], to
suppress the warning at the call site. This would allow using the type
warning-free within the library where it is created, and clearly express
that this is a special case, not the primary use case for this type.
While I find P0672R0 interesting, I also think it may be overkill for a
relatively niche problem. I ran into it using armadillo (linear algebra),
the Wikipedia site specifies mostly linear algebra as a use case, and a
quick google search ends up with the same thing. So on a value-effort
graph, I think P0672R0 has to much effort for too little value. Attributes
do not change the core language significantly, do not introduce new syntax
or complexities, they simply tell compilers to emit warnings under certain
conditions. That seems like a much cheaper way of getting some safety into
the use of expression templates. It does not allow the drop-in replacement
of expression templates, but I consider that a somewhat minor problem
compared to the bugs that crop up when using them in an auto-riddled,
modern-C++ world.
I think there are a few operations that may be indicative of problem with
delayed evaluation/proxy types:
copy/move
discard (I'll vaguely throw non-dependent operator void() out there)
reference binding

A temporary bound to a reference such that the reference extends the
lifetime of the temporary is a potentially problematic case that you may
want to consider with regards to the attributes you are proposing.
Post by Till Heinzel
I am not an expert on the standard, so I would love some comments on this.
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+***@isocpp.org.
To post to this group, send email to std-***@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/55c9a427-37c7-4a22-8e8a-8c5f00059852%40isocpp.org.
Loading...