Or just allow auto to infer different values for each variable.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/53a10b81-687a-40de-8420-b439d394af1a%40isocpp.org.
A simple example:
Here's a fairly common idiom, expressed in terms of a structured binding:
for(auto &[i, val] : std::counted_view(rng))
{...}
#include <iostream>#include <vector>#include <tuple>int main(){std::vector<int> v = { 6,5,4,3,2,1 };for( auto [i, first, last] = std::make_tuple(std::size_t(0), begin(v), end(v)); first != last; ++i, ++first){std::cout << "index: " << i << "\t" << *first << "\n";}}It seems sensible to me to group the loop's variables in a structured binding since
- it's succinct and,
- they remain firmly local to the loop's scope
- It's the only way to declare multiple dissimilar variables within the for statement.
However, this code is not DRY - the naming of the bound variables must correspond to the creation of the tuple. Maintenance confusion awaits.
It seems to me that a small, non-breaking syntax change could allow this:
for( auto [i = size_t(0), first = begin(v), last = end(v)]; first != last; ++i, ++first){// ...}which would:a) be 100% DRY,b) involve less typing
c) match the syntax for lambda capture (I could expand further on my thoughts on that, but perhaps another day)d) IMHO be easier to teach
On Wednesday, December 13, 2017 at 5:15:56 AM UTC-5, Richard Hodges wrote:A simple example:
Here's a fairly common idiom, expressed in terms of a structured binding:I'm sure some people do this, but an indexed range view would handle this much more easily and compactly:
for(auto &[i, val] : std::counted_view(rng))
{...}#include <iostream>#include <vector>#include <tuple>int main(){std::vector<int> v = { 6,5,4,3,2,1 };for( auto [i, first, last] = std::make_tuple(std::size_t(0), begin(v), end(v)); first != last; ++i, ++first){std::cout << "index: " << i << "\t" << *first << "\n";}}It seems sensible to me to group the loop's variables in a structured binding since
- it's succinct and,
- they remain firmly local to the loop's scope
- It's the only way to declare multiple dissimilar variables within the for statement.
However, this code is not DRY - the naming of the bound variables must correspond to the creation of the tuple. Maintenance confusion awaits.Perhaps you're mistaking DRY for some other principle. DRY is Don't Repeat Yourself. This code involves no repetition of typenames, variable names, objects, literals, or anything else. Nothing is being repeated; there is simply distance between the "variable" and its initializer.That has nothing to do with repetition.
It seems to me that a small, non-breaking syntax change could allow this:Structured binding should not be used as a quick-and-dirty way to create multiple variables of different types in a place where that wasn't possible previously. And we certainly should not add syntax to encourage this.
Remember: they could have made `auto` do this exact thing when we standardized it in 2011. But the committee expressly decided against it. All of the reasons for not allowing it then are still just as valid now.
for( auto [i = size_t(0), first = begin(v), last = end(v)]; first != last; ++i, ++first){// ...}which would:a) be 100% DRY,b) involve less typing59 characters vs. 79. That's not "much less", especially compared to the 45 characters in the range-based version.
c) match the syntax for lambda capture (I could expand further on my thoughts on that, but perhaps another day)d) IMHO be easier to teachThis isn't something people should be doing anyway. So why would we want it to be easy to teach?
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/be270d3b-d86d-4e6d-9e9c-483a9ea7eb98%40isocpp.org.
Perhaps you're mistaking DRY for some other principle. DRY is Don't Repeat Yourself. This code involves no repetition of typenames, variable names, objects, literals, or anything else. Nothing is being repeated; there is simply distance between the "variable" and its initializer.That has nothing to do with repetition.
...
59 characters vs. 79. That's not "much less"
auto i = size_t(0);
auto first = begin(v);
auto last = end(v);
Remember: they could have made `auto` do this exact thing when we standardized it in 2011. But the committee expressly decided against it. All of the reasons for not allowing it then are still just as valid now.I am not privy to the reasons. Are you able to elaborate please? I don't think structured bindings were on the table back in 2011.
auto x = 5.0f, y = 10, z = std::string("foo");
for( auto [i = size_t(0), first = begin(v), last = end(v)]; first != last; ++i, ++first){// ...}which would:a) be 100% DRY,b) involve less typing59 characters vs. 79. That's not "much less", especially compared to the 45 characters in the range-based version.No, it's not "much less". It's "less", as I originally wrote. However, perhaps we digress. The primary benefit (marked "a" and formatted in bold) is that it is DRY.
Which I think we would all agree is a good thing (even if we disagree on the method to achieve it).
Do we really need to add special syntax for something that only gets used in such limited scenarios? Even worse, if we add such syntax, aren't we encouraging people to declare a bunch of variables in one line, which is generally considered bad form?
No, it's best to just leave things as they are. In those circumstances where it is necessary to achieve what you want, you can still do it. But the poor syntax and copying behavior will encourage you to avoid it whenever possible.
Remember: they could have made `auto` do this exact thing when we standardized it in 2011. But the committee expressly decided against it. All of the reasons for not allowing it then are still just as valid now.I am not privy to the reasons. Are you able to elaborate please? I don't think structured bindings were on the table back in 2011.I didn't say structured bindings. I said `auto`.
Remember: what you want is not structured bindings. Structured binding is about unpacking objects that store data into multiple variable-like constructs. You don't have such a object, and you don't really want one. The only reason you created a tuple of values was because structured binding requires it.What you really want is the ability to declare multiple variables of different types in a single declaration statement. When `auto` was being standardized, there was discussion about allowing precisely that:
auto x = 5.0f, y = 10, z = std::string("foo");These would deduce 3 different types for the 3 variables. The committee specifically decided against doing this.
Through structured bindings, you can achieve a similar effect as that. But if we wanted that effect, we'd have allowed it to begin with.for( auto [i = size_t(0), first = begin(v), last = end(v)]; first != last; ++i, ++first){// ...}which would:a) be 100% DRY,b) involve less typing59 characters vs. 79. That's not "much less", especially compared to the 45 characters in the range-based version.No, it's not "much less". It's "less", as I originally wrote. However, perhaps we digress. The primary benefit (marked "a" and formatted in bold) is that it is DRY.But it isn't DRY; as we previously agreed, there's no repetition being eliminated. There is only distance.
Which I think we would all agree is a good thing (even if we disagree on the method to achieve it).No, not really. I don't want to see code like that, and I don't want to encourage people to have such long variable declaration sequences all in one statement like that.
If you're having to break a `for` loop or `if` statement or whatever into multiple lines just to make them legible, it suggests that there's a problem in your code. The longer such statements get, the harder it is to follow what's going on.
Indeed, reducing such verbosity is partially why we created range-based `for` in the first place. The idiom you're talking about is not an anti-pattern per-se, but it ought to be considered a code smell. When you use it, it should be because there is no better way to do what you're doing.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/0dbd4344-23a7-4578-ad5c-e7727dfecf27%40isocpp.org.
inline....
On 13 December 2017 at 18:05, Nicol Bolas <jmck...@gmail.com> wrote:
On Wednesday, December 13, 2017 at 10:58:11 AM UTC-5, Richard Hodges wrote:
answer inline
It seems to me that a small, non-breaking syntax change could allow this:Structured binding should not be used as a quick-and-dirty way to create multiple variables of different types in a place where that wasn't possible previously. And we certainly should not add syntax to encourage this.
This is sounding like unsubstansiated opinion. And I respectfully disagree - it seems useful to me to be able to create a tuple with named arguments in a local slope on the fly.
And you can do that already. What we shouldn't do is encourage it or hide the fact that this is what you're doing.Here's the thing. The only time you absolutely need this feature is when you're declaring variables in a place where you only get one declaration. Because if you can make multiple declarations, there's nothing stopping you from doing:
auto i = size_t(0);
auto first = begin(v);
auto last = end(v);I find these lines to be far more readable than the structured binding version or your alternative structured binding syntax. So the only time people should use your alternate syntax is when they're only allowed a single declaration. And that means in the initializer section of some statement.
In current c++, in order to declare these variables one per line while enclosing them strictly within the scope of the algorithm, once would need to enclose the entire algorithm in a pair of logically un-neccessary curly braces.
Do we really need to add special syntax for something that only gets used in such limited scenarios? Even worse, if we add such syntax, aren't we encouraging people to declare a bunch of variables in one line, which is generally considered bad form?It seems to me that tuples have become a special kind of problem, in that there is core language support for half of the construct, but library-only support for the rest.
Similarly initializer_list and typeinfo. I am of the view that this is an aberration.
Either support it in the core language or don't. The current half and half approach is an error. why shouldn't I be able to say:auto t = auto [x = int(1), y = std::string("foo"), 6]; // get<0>(t) == 1, get<1>(t) == "foo", get<2>(t) == 6such an expression is expressive, succinct and useful. I can manipulate the tuple either as a complete object or as individual objects. Great!
struct {int x = 1; std::string y{"foo"}; int z = 6;} t;
No, it's best to just leave things as they are. In those circumstances where it is necessary to achieve what you want, you can still do it. But the poor syntax and copying behavior will encourage you to avoid it whenever possible.An "it's best to leave things as they are" attitude would leave us with c+98 and prevent c++ ever becoming a mature fully-featured expressive language. I'm afraid to say that I cannot take this statement seriously.
Remember: they could have made `auto` do this exact thing when we standardized it in 2011. But the committee expressly decided against it. All of the reasons for not allowing it then are still just as valid now.I am not privy to the reasons. Are you able to elaborate please? I don't think structured bindings were on the table back in 2011.I didn't say structured bindings. I said `auto`.Mea culpa.Remember: what you want is not structured bindings. Structured binding is about unpacking objects that store data into multiple variable-like constructs. You don't have such a object, and you don't really want one. The only reason you created a tuple of values was because structured binding requires it.What you really want is the ability to declare multiple variables of different types in a single declaration statement. When `auto` was being standardized, there was discussion about allowing precisely that:
auto x = 5.0f, y = 10, z = std::string("foo");These would deduce 3 different types for the 3 variables. The committee specifically decided against doing this.Deciding against this seems to me to have been, in hindsight, the wrong decision. Perhaps this error can be corrected in a future standard?
I have yet to see a reasonable rationalisation (in the light of since-gathered experience) of this decision.
Oh sure, you can't leave a member unnamed, but why would you want to? If that member is important enough to be stored and accessed, it's important enough to have a name.`std::tuple` primarily exists for metaprogramming reasons (building structs, etc). If you're using it in static code like the declaration above, you're almost always using the wrong tool.No, it's best to just leave things as they are. In those circumstances where it is necessary to achieve what you want, you can still do it. But the poor syntax and copying behavior will encourage you to avoid it whenever possible.An "it's best to leave things as they are" attitude would leave us with c+98 and prevent c++ ever becoming a mature fully-featured expressive language. I'm afraid to say that I cannot take this statement seriously.I didn't say we should leave all of C++ as it is. I'm saying that we should leave this as it is.My problems with this really boil down to (in priority order):1) It abuses structured binding, forcing it to do something that structured binding isn't meant to do simply because it is convenient syntax.
2) The problems this solves are not encountered frequently enough to override #1.
3) In a lot of the practical cases where this might be useful, there are better solutions that don't need it (like my range adaptor example).
4) It encourages writing ugly code. The more variables you shove into a `for` initializer, the more testing and incrementing expressions you need and the harder it is to follow the logic. This is a big part of why the range adaptor is preferred where possible; it hides the ugly details.Remember: they could have made `auto` do this exact thing when we standardized it in 2011. But the committee expressly decided against it. All of the reasons for not allowing it then are still just as valid now.I am not privy to the reasons. Are you able to elaborate please? I don't think structured bindings were on the table back in 2011.I didn't say structured bindings. I said `auto`.Mea culpa.Remember: what you want is not structured bindings. Structured binding is about unpacking objects that store data into multiple variable-like constructs. You don't have such a object, and you don't really want one. The only reason you created a tuple of values was because structured binding requires it.What you really want is the ability to declare multiple variables of different types in a single declaration statement. When `auto` was being standardized, there was discussion about allowing precisely that:
auto x = 5.0f, y = 10, z = std::string("foo");These would deduce 3 different types for the 3 variables. The committee specifically decided against doing this.Deciding against this seems to me to have been, in hindsight, the wrong decision. Perhaps this error can be corrected in a future standard?Well, changing it is possible. At present, [dcl.spec.auto]/7 says:> The type of each declared variable is determined by placeholder type deduction (10.1.7.4.1), and if the type that replaces the placeholder type is not the same in each deduction, the program is ill-formed.This means that every declaration which would deduce different types is at present illegal. So removing this restriction would not break any currently legal code.And this change would be a lot more palatable than (ab)using structured binding for this purpose. It would also have semantics that are more immediately obvious than those for (ab)using structured binding in this way.Though personally, I still think it's a bad idea.
I have yet to see a reasonable rationalisation (in the light of since-gathered experience) of this decision.It's you who have to come up with a rationalization for the change, not the other way around. If "the light of since-gathered experience" really is on your side, you ought to be able to look at all of the old arguments against it and answer them one-by-one based on that experience.
Be sure to bring up the Range TS Iterator/Sentinel paradigm. That's always a slam-dunk when it comes to deducing the same type ;)
The `auto` proposals for C++11 are all still available from the committee's website. Feel free to download them and start working through the counter-arguments.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/c8d3dd9a-69c7-4586-b0d3-cec9122c8b6a%40isocpp.org.
What standard is that from? Couldn't find it when searching for std counted_view.
> I'm sure some people do this, but an indexed range view would handle this much more easily and compactly:
> for(auto &[i, val] : std::counted_view(rng))
> {...}
I've also never seen `auto &[i, val]` as a variable declaration consruct before. Is that c++17?
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/0a1c616b-b5cd-404c-b523-fe168f3ca878%40isocpp.org.
I won't dwell too much, just a couple of comments:On 14 December 2017 at 00:48, Nicol Bolas <jmck...@gmail.com> wrote:On Wednesday, December 13, 2017 at 5:22:11 PM UTC-5, Richard Hodges wrote:inline....On 13 December 2017 at 18:05, Nicol Bolas <jmck...@gmail.com> wrote:On Wednesday, December 13, 2017 at 10:58:11 AM UTC-5, Richard Hodges wrote:Either support it in the core language or don't. The current half and half approach is an error. why shouldn't I be able to say:auto t = auto [x = int(1), y = std::string("foo"), 6]; // get<0>(t) == 1, get<1>(t) == "foo", get<2>(t) == 6such an expression is expressive, succinct and useful. I can manipulate the tuple either as a complete object or as individual objects. Great!I fail to see how that is an improvement over using a tuple. And quite frankly, we already have ways of declaring a type:
struct {int x = 1; std::string y{"foo"}; int z = 6;} t;Declaring an object of on-the-fly struct would be a solution if a struct's members could be declared auto.
Unhappily they cannot, so this solution would only work where types are well known. Of course the argument for introducing auto hinged on convenience of type deduction, particularly in template expansions. This is a convenience I think we all enjoy. I would like to see this kind of convenience extended.
As a side note, there is exactly one core language feature in which the types of members is automatically deduced - the lambda with capture. The automatic deduction is useful in this case, it might well be in others.
No, it's best to just leave things as they are. In those circumstances where it is necessary to achieve what you want, you can still do it. But the poor syntax and copying behavior will encourage you to avoid it whenever possible.An "it's best to leave things as they are" attitude would leave us with c+98 and prevent c++ ever becoming a mature fully-featured expressive language. I'm afraid to say that I cannot take this statement seriously.I didn't say we should leave all of C++ as it is. I'm saying that we should leave this as it is.My problems with this really boil down to (in priority order):1) It abuses structured binding, forcing it to do something that structured binding isn't meant to do simply because it is convenient syntax.Tuples and structures are _logically_ two flavours of the same thing. We happen to talk about them as if they are different for historic reasons, not logical ones.
For me, the ability to spontaneously create an object of an arbitrary compound type, and inject the names of its members into local scope seems useful. It is this feature that gives python (for example) its wonderfully succinct list-comprehension syntax.
2) The problems this solves are not encountered frequently enough to override #1.Assertion. New tools create new opportunities.
3) In a lot of the practical cases where this might be useful, there are better solutions that don't need it (like my range adaptor example).Building a new iterator type for every logical scenario is inconvenient and difficult to teach. It hides logic details.
for(auto &[first, second] : zip_range(rng_first, rng_second))
{}
This is why range-based-for was invented. "keep simple things simple".'
Remember: what you want is not structured bindings. Structured binding is about unpacking objects that store data into multiple variable-like constructs. You don't have such a object, and you don't really want one. The only reason you created a tuple of values was because structured binding requires it.What you really want is the ability to declare multiple variables of different types in a single declaration statement. When `auto` was being standardized, there was discussion about allowing precisely that:
auto x = 5.0f, y = 10, z = std::string("foo");These would deduce 3 different types for the 3 variables. The committee specifically decided against doing this.Deciding against this seems to me to have been, in hindsight, the wrong decision. Perhaps this error can be corrected in a future standard?Well, changing it is possible. At present, [dcl.spec.auto]/7 says:> The type of each declared variable is determined by placeholder type deduction (10.1.7.4.1), and if the type that replaces the placeholder type is not the same in each deduction, the program is ill-formed.This means that every declaration which would deduce different types is at present illegal. So removing this restriction would not break any currently legal code.And this change would be a lot more palatable than (ab)using structured binding for this purpose. It would also have semantics that are more immediately obvious than those for (ab)using structured binding in this way.Though personally, I still think it's a bad idea.Do you mind explaining why? Because to me it seems like a splendid idea. To me, auto x = foo(), y = bar(); seems succinct and neat. Someone who didn't know the language would read this and naturally conclude that x and y may be of different types.
I have yet to see a reasonable rationalisation (in the light of since-gathered experience) of this decision.It's you who have to come up with a rationalization for the change, not the other way around. If "the light of since-gathered experience" really is on your side, you ought to be able to look at all of the old arguments against it and answer them one-by-one based on that experience.For one, it's more naturally logical to imagine that an auto variable will have the type of its initialiser.
Be sure to bring up the Range TS Iterator/Sentinel paradigm. That's always a slam-dunk when it comes to deducing the same type ;)I'm not sure what you mean here. In any range-based algorithm you will certainly want the ability for the iterator to be of a different type to the sentinel. multi-typed auto would help this.
auto beg = rng.begin(), end = rng.end();
Having pondered the responses, it turns out that I can express my algorithm in a tightly scoped, DRY and legal manner in current c++ like this:
{
std::size_t ix = 0;
auto first = begin(v);
auto last = end(v);
for(; first != last; ++first, ++ix)
//Actual loop body;
}
I really do think that there is a case for allowing:for(auto [i = std::size_t(0)] ; auto&& elem : v)f(elem, i++);or:for(auto [i = std::size_t(0), first = begin(v), last = end(v)] ; first != last ; ++first, ++i)f(*first, i);or:for(auto i = std::size_t(0), first = begin(v), last = end(v) ; first != last ; ++first, ++i)f(*first, i);since we already have this ability in the nasty lambda above, why not provide the ability in a way that's easy to reason about?
On Thursday, December 14, 2017 at 2:27:39 AM UTC-5, Richard Hodges wrote:I won't dwell too much, just a couple of comments:On 14 December 2017 at 00:48, Nicol Bolas <jmck...@gmail.com> wrote:On Wednesday, December 13, 2017 at 5:22:11 PM UTC-5, Richard Hodges wrote:inline....On 13 December 2017 at 18:05, Nicol Bolas <jmck...@gmail.com> wrote:On Wednesday, December 13, 2017 at 10:58:11 AM UTC-5, Richard Hodges wrote:Either support it in the core language or don't. The current half and half approach is an error. why shouldn't I be able to say:auto t = auto [x = int(1), y = std::string("foo"), 6]; // get<0>(t) == 1, get<1>(t) == "foo", get<2>(t) == 6such an expression is expressive, succinct and useful. I can manipulate the tuple either as a complete object or as individual objects. Great!I fail to see how that is an improvement over using a tuple. And quite frankly, we already have ways of declaring a type:
struct {int x = 1; std::string y{"foo"}; int z = 6;} t;Declaring an object of on-the-fly struct would be a solution if a struct's members could be declared auto.Seriously, what is it with people and `auto`? Why are you so allergic to typenames? That structure as it stands is far more readable than the "auto" version would be.
Thinking like this makes me rue the day the committee ever standardized `auto` variable deduction. People keep trying to take a useful tool for dealing with obvious code and long typenames, and turning it into the thing that must be used everywhere.
Let's not standardize the Almost-Always-Auto ideology.
Unhappily they cannot, so this solution would only work where types are well known. Of course the argument for introducing auto hinged on convenience of type deduction, particularly in template expansions. This is a convenience I think we all enjoy. I would like to see this kind of convenience extended."Convenience" of this sort often creates ambiguity and confusion. Having to use a typename is not some kind of onerous burden here.
As a side note, there is exactly one core language feature in which the types of members is automatically deduced - the lambda with capture. The automatic deduction is useful in this case, it might well be in others.That's because lambdas have to be short to be useful, particularly the capture list. The main point of a lambda is not what it captures but the actual function it encapsulates. The capture part is an unfortunate implementation detail that we try to minimize where possible.That is, the point of a lambda is the function part, not the functor part. The functor part is an implementation detail required by the way C++ works.
Making struct definitions shorter makes them harder to reason about and digest, and gives precious little back in return.No, it's best to just leave things as they are. In those circumstances where it is necessary to achieve what you want, you can still do it. But the poor syntax and copying behavior will encourage you to avoid it whenever possible.An "it's best to leave things as they are" attitude would leave us with c+98 and prevent c++ ever becoming a mature fully-featured expressive language. I'm afraid to say that I cannot take this statement seriously.I didn't say we should leave all of C++ as it is. I'm saying that we should leave this as it is.My problems with this really boil down to (in priority order):1) It abuses structured binding, forcing it to do something that structured binding isn't meant to do simply because it is convenient syntax.Tuples and structures are _logically_ two flavours of the same thing. We happen to talk about them as if they are different for historic reasons, not logical ones.... I don't know what that has to do with what I said. Your statement only makes sense if you think of structured binding as a feature invented for tuples. It's not. It works just fine with decomposeable structs, and you can write machinery to make them decomposeable when they're not automatically decomposeable.For me, the ability to spontaneously create an object of an arbitrary compound type, and inject the names of its members into local scope seems useful. It is this feature that gives python (for example) its wonderfully succinct list-comprehension syntax.That doesn't justify abusing structured binding to do that. If you really believe that the ability to create a type and make local variables of its members is useful (and I've yet to see how), then you should create a feature that is specifically about that.
Structured binding is about unpacking an existing object, not about creating types. Don't abuse a syntax for an unrelated feature just because it's convenient.2) The problems this solves are not encountered frequently enough to override #1.Assertion. New tools create new opportunities.Also an assertion. What "new opportunities" does this create?
I have yet to see a reasonable rationalisation (in the light of since-gathered experience) of this decision.It's you who have to come up with a rationalization for the change, not the other way around. If "the light of since-gathered experience" really is on your side, you ought to be able to look at all of the old arguments against it and answer them one-by-one based on that experience.For one, it's more naturally logical to imagine that an auto variable will have the type of its initialiser.That's not an answer to those arguments. Indeed, you didn't even state what those arguments are.Be sure to bring up the Range TS Iterator/Sentinel paradigm. That's always a slam-dunk when it comes to deducing the same type ;)I'm not sure what you mean here. In any range-based algorithm you will certainly want the ability for the iterator to be of a different type to the sentinel. multi-typed auto would help this.... right. Which is why I said you should bring it up. I wasn't being sarcastic.Consider what I just said about having two "independent operations" on the same line. If you're extracting begin/end from a range, then those aren't "two independent operations". They're a single logical thought:
auto beg = rng.begin(), end = rng.end();When you have something that is conceptually atomic that, by reason of implementation, requires two distinct actions, that is when it is appropriate to stick them in one line.
Of course, you'll naturally try to say that getting iterators for two separate ranges is also a single logical thought to your algorithm. But I contest this because they're not atomic actions. Getting the beginning of a range is useless without getting its end (in most cases). That's what makes the pair of actions "atomic"; you can't do anything with them until both are complete.
However, getting one iterator range can be useful without getting some other iterator range. It may not be useful to your algorithm, but it is still useful in the general sense.
That's my personal dividing line.
On Thursday, December 14, 2017 at 7:37:22 AM UTC-5, Richard Hodges wrote:Having pondered the responses, it turns out that I can express my algorithm in a tightly scoped, DRY and legal manner in current c++ like this:I'm not really sure what that proves. You can accomplish the same thing by using curly braces:
{
std::size_t ix = 0;
auto first = begin(v);
auto last = end(v);
for(; first != last; ++first, ++ix)
//Actual loop body;
}You can even remove the `begin` line by adding it to the `for` statement. So what's the downside of this? Do you really need to write these multi-variable things that often that we need a language change? You've not answered that question.
I really do think that there is a case for allowing:for(auto [i = std::size_t(0)] ; auto&& elem : v)f(elem, i++);or:for(auto [i = std::size_t(0), first = begin(v), last = end(v)] ; first != last ; ++first, ++i)f(*first, i);or:for(auto i = std::size_t(0), first = begin(v), last = end(v) ; first != last ; ++first, ++i)f(*first, i);since we already have this ability in the nasty lambda above, why not provide the ability in a way that's easy to reason about?You can already do the first one; just get rid of the structured binding bit. And the second and third ones have nothing to do with one another. They have completely different semantics.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/79fdf8b2-08e8-4889-a1b6-50f0f05eb0d0%40isocpp.org.
> I'm sure some people do this, but an indexed range view would handle this much more easily and compactly:
>
> for(auto &[i, val] : std::counted_view(rng))
> {...}
There is currently no such thing as a std::counted_view but I take your point. The problems with this approach are:
- You have to think of a meaningful name for every trivial range adapter you ever want to write. This is a bigger problem in a large organisation or distributed team that it might at first seem.
- Range adapters involve abstracting out one's algorithm into a verbose class. Precisely the opposite of the intent of range-based for (keep simple things simple, keep logic in the loop body)
- You have to document and publish what is essentially a line or 2 of trivial self-documenting code.
- You have to wait for at least 3 years of squabbling in the isocpp committee before it'll be in the std namespace*
* ok, fair enough, you could submit it to boost and get it out in 3 months if you're happy with boost::counted_view.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/7928cfe2-5779-4f69-a1e4-1d329631c6d8%40isocpp.org.
From: Patrice Roy Sent: Friday, January 5, 2018 9:27 PM Reply To: std-pr...@isocpp.org Subject: Re: [std-proposals] Re: Structured Bindings - revisited |
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAKiZDp32jD8kxFL%2B3-gFePMRt7Xds8HO6NoWS_T%3DofaO3E539g%40mail.gmail.com.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/20180106030305.5115986.4133.44006%40gmail.com.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAKiZDp32jD8kxFL%2B3-gFePMRt7Xds8HO6NoWS_T%3DofaO3E539g%40mail.gmail.com.
FWIW, Richard, I think your idea has merits. I have often found it a bit annoying not to be able to declare variables of different types in the init section of a for statement, and inspiration from lambda capture syntax / structured bindings seems harmonious to me.
for(auto [a = 0, b = ""s]; a != N; ++a)
for(auto a = 0, b = ""s; a != N; ++a)
On 14 December 2017 at 18:19, Nicol Bolas <jmck...@gmail.com> wrote:... right. Which is why I said you should bring it up. I wasn't being sarcastic.Consider what I just said about having two "independent operations" on the same line. If you're extracting begin/end from a range, then those aren't "two independent operations". They're a single logical thought:
auto beg = rng.begin(), end = rng.end();When you have something that is conceptually atomic that, by reason of implementation, requires two distinct actions, that is when it is appropriate to stick them in one line.I think we agree here. Acquiring an index counter and the limits of a range seem to me to be part of the same logical atomic operation.Of course, you'll naturally try to say that getting iterators for two separate ranges is also a single logical thought to your algorithm. But I contest this because they're not atomic actions. Getting the beginning of a range is useless without getting its end (in most cases). That's what makes the pair of actions "atomic"; you can't do anything with them until both are complete.I wholeheartedly disagree. The c++ memory model mandates that getting the two pairs of iterators is indeed atomic. Everything between two memory fences is logically atomic. This is the foundation of the as-if rule. This is unarguable.
On Thursday, December 14, 2017 at 7:37:22 AM UTC-5, Richard Hodges wrote:Having pondered the responses, it turns out that I can express my algorithm in a tightly scoped, DRY and legal manner in current c++ like this:I'm not really sure what that proves. You can accomplish the same thing by using curly braces:
{
std::size_t ix = 0;
auto first = begin(v);
auto last = end(v);
for(; first != last; ++first, ++ix)
//Actual loop body;
}You can even remove the `begin` line by adding it to the `for` statement. So what's the downside of this? Do you really need to write these multi-variable things that often that we need a language change? You've not answered that question.That's a fair question. My initial response is that the extra curly braces are not beautiful. And to me elegance and beauty of code presentation is a factor in my enjoyment of writing it. To me, that's enough of a reason for a change (if not the one I originally proposed). I appreciate that you may not take aesthetics to heart as much as me.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CANu6V4VJt1ma9SE_wD_X%3DtismPcAMiArHzh9%3DSq2ERMKO7yZQw%40mail.gmail.com.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUZh9rG5Zn2UdSFEAJk3Zuu8q2O0EdcnogdUaEjM58vUeA%40mail.gmail.com.
Yes, that's an alternative syntax I think would work too. Changing the way auto works as Nicol suggests seems like a bigger change to me,
and I would prefer avoiding that until there's a sound rationale and a paper exploring its impact throughout the language (particularly with respect to concepts; it's already quite complicated there).
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/dd97066a-6f90-46b0-bb92-c2a6119954ab%40isocpp.org.
Now it seems the best time to investigate the possibility for auto to being able to declare multiple, comma separated, variables.With the new init if, and the new init range-for - we should be able to do as much work as possible in a single statement!
It looks to me the disallow is just legacy "compatibility" mode - to let auto be optional.
I also can't imagine how this can break existing code, as there is no conversion/promotion right now - the types must be exactly the same - but as said, this must be investigated.Can someone write a paper, if one is not already written, to get the ball rolling? Nicol Bolas? Giovanni Piero Deretta?
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/dd97066a-6f90-46b0-bb92-c2a6119954ab%40isocpp.org.
On Sunday, January 7, 2018 at 7:48:37 AM UTC-5, mihailn...@gmail.com wrote:Now it seems the best time to investigate the possibility for auto to being able to declare multiple, comma separated, variables.With the new init if, and the new init range-for - we should be able to do as much work as possible in a single statement!Long statements are not clear statements. The more a statement does, the less easy it is to figure out what it's doing.We didn't add initializers to `if`, `switch`, and range `for` to make them "do as much work as possible". It was done to make code less brittle ("solving" the temporary range issue) or to deal with cases where you need to compute a value, test if its valid, and then use it in an `if` statement.
This is the principle downside to me of allowing variables of different types in `auto`: that it will encourage people to declare every variable in a block in one statement, even when it isn't necessary.
It looks to me the disallow is just legacy "compatibility" mode - to let auto be optional.`auto` is optional; adding this will not make it any less optional. I don't know what you mean by this.
auto x = "hello"s, y = 3.14159; // distinct types, quite new; impact on the way people write C++? Requires thought, at the very leastI don't think it's a matter of sentence length in the standard text. It's more a matter of :int a = 2, b = 3; // same type
If you see single-auto, multiple types as the way to go, I think it's a position that deserves a paper. It does not jump as being to path to follow in a self-evident manner;auto x = "hello"s, y = 3.14159; // distinct types, quite new; impact on the way people write C++? Requires thought, at the very leastI don't think it's a matter of sentence length in the standard text. It's more a matter of :int a = 2, b = 3; // same type
// ...template <Regular T> void f(T, T); // same typevoid g(Regular, Regular); // if short syntax eventually gets in : same type? different types?void h(auto a, auto b); // same rules as Regular,Regular or not? Papers have been written debating both options
auto [i = std::size_t(0), first = begin(v), last = end(v)];
auto i = std::size_t(0), first = begin(v), last = end(v);
maybe you'll find a convincing angle, and I for one will happily read it once it's written. The alternatives seem less contentious to me, given prior art,
On Sunday, January 7, 2018 at 5:12:29 PM UTC+2, Nicol Bolas wrote:On Sunday, January 7, 2018 at 7:48:37 AM UTC-5, mihailn...@gmail.com wrote:Now it seems the best time to investigate the possibility for auto to being able to declare multiple, comma separated, variables.With the new init if, and the new init range-for - we should be able to do as much work as possible in a single statement!Long statements are not clear statements. The more a statement does, the less easy it is to figure out what it's doing.We didn't add initializers to `if`, `switch`, and range `for` to make them "do as much work as possible". It was done to make code less brittle ("solving" the temporary range issue) or to deal with cases where you need to compute a value, test if its valid, and then use it in an `if` statement.This is the principle downside to me of allowing variables of different types in `auto`: that it will encourage people to declare every variable in a block in one statement, even when it isn't necessary.I will rephrase - with init-if and init-range-for, this feature will have even more uses. And by uses, I mean legitimate ones.If a variable is used in scope only and it must be created before the if/for/switch statement, then the init section is its best place.I also don't consider comma separated list of variables declarations worse then line by line ones.And one more thing - people are already doing it the ugly way!auto i = std::size_t(0), first = begin(v), last = end(v)will prevent writing thisauto [i, first, last] = std::make_tuple(std::size_t(0), begin(v), end(v))which we both agree is worse!
for( auto [i, first, last] = std::make_tuple(std::size_t(0), begin(v), end(v));
first != last;
++i, ++first)
{
std::cout << "index: " << i << "\t" << *first << "\n";
}
for( auto i = std::size_t(0), first = begin(v), last = end(v);
first != last;
++i, ++first)
{
std::cout << "index: " << i << "\t" << *first << "\n";
}
for(auto &[i, val] : std::counted_view(rng))
{
std::cout << "index: " << i << "\t" << val << "\n";
}
It looks to me the disallow is just legacy "compatibility" mode - to let auto be optional.`auto` is optional; adding this will not make it any less optional. I don't know what you mean by this.Humm, you mean that we simply allow comma separated list to evaluate to different variable types?
Because otherwise, if this is added, auto is no longer optional, like it is today.auto i=2, j=3; //< 'auto' is optional, can be replaced with intauto s="hi"s, i=1; //< auto is not optional, code will break if changed to anything else
On Sunday, January 7, 2018 at 6:19:21 PM UTC+2, Patrice Roy wrote:...
If you see single-auto, multiple types as the way to go, I think it's a position that deserves a paper. It does not jump as being to path to follow in a self-evident manner; maybe you'll find a convincing angle, and I for one will happily read it once it's written. The alternatives seem less contentious to me, given prior art, but I'm open to examining what you have in mind once it's been put in proposal form.
Prior art here is actually C and predates the new funky stuff (which has it own place).It is worth noting we already can declare variables of different types:int i, *pi;these two are radically different types.And it gets "better"int i, *p, a[12], f(), (*pf)(double), C::*mf;It is painfully obvious here, it is allowed to be declared anything on a single line as long as it can be
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUYp9mEboC9KM_RG4xhKZ5VESw7dxqLYf-PnMT4_P8-K-g%40mail.gmail.com.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/20e52a58-1947-4cb9-8ab0-d6a46a064e88%40isocpp.org.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUbbWbvKY_z%2BDQa4dh6FbU4n%3DCic%2Bd5WnaqVu4_dnn%3D0xg%40mail.gmail.com.
...
And one more thing - people are already doing it the ugly way!auto i = std::size_t(0), first = begin(v), last = end(v)will prevent writing thisauto [i, first, last] = std::make_tuple(std::size_t(0), begin(v), end(v))which we both agree is worse!If people are writing that, then they deserve to write it. That's my feeling on the matter. Let's make ugly code as ugly as possible, so that people will switch to the better code.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/f39d0998-040a-498f-b9c8-1a36c0ad3d96%40isocpp.org.
Small addition : the mention that something likeint a = 3, *p = &a, &r = a;... stands as prior art is interesting, and I think it should be part of an eventual proposal.
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/5786bf3b-3bf9-449a-a0bd-f6caecdb375e%40isocpp.org.
On Sunday, January 7, 2018 at 7:39:07 PM UTC+2, Nicol Bolas wrote:...And one more thing - people are already doing it the ugly way!auto i = std::size_t(0), first = begin(v), last = end(v)will prevent writing thisauto [i, first, last] = std::make_tuple(std::size_t(0), begin(v), end(v))which we both agree is worse!If people are writing that, then they deserve to write it. That's my feeling on the matter. Let's make ugly code as ugly as possible, so that people will switch to the better code.You are assuming all multiple declarations, written in one line, are bad.
But that is subjective, considering the trade offs, and they are trade offs - either dummy scopes or some new special classes and functions to fit in the current model.
Consider a real-world, looping over two images pixels:for(auto* dst_p = dst_start, *src_p = src_start; //< only works if the data is the same typedst_p < dst_end;dst_p += Bpp, src_p += Bpp)
{// use}How is this bad or unclear code?
And we only got for loop so far. Now even more needs will arise (with the range-for, if and switch), uses, which make sense, and make sense iff the variables are needed before the test and are excusive for the scope
if(auto big = bag, of = initializer, expression = that, run = on, fore = ver;
big == of)
{ ... }
{
auto big = bag;
auto of = initializer;
auto expression = that;
auto fore = ver;
if(big == of)
{ ... }
}
for(auto foo1 = get_range1(), foo2 = get_range2(), foo3 = get_range3();
auto &[f1, f2, f3] : zip_range(foo1, foo2, foo3))
{ auto foo1 = get_range1(); auto foo2 = get_range2(); auto foo3 = get_range3();
for(auto &[f1, f2, f3] : zip_range(foo1, foo2, foo3))
}
I was just following the suggestion of another contributor to this thread. I maintain you should write a proposal, and I think this deserves attention. You write well, I'm sure it will be a good proposal.
As you said, defining multiple variables in a single line is not very pretty, and in fact, the CppCoreGuidelines discourage it too:
https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Res-name-one
--
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+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/43d789dc-8409-48e4-99e4-c41907365597%40isocpp.org.
3) It introduces variables that aren't actually used. After all, the `// use` part doesn't care about `src_p` and `dst_p`. It will never modify those variables; it only uses what they point to.
for (auto& [range, dest] : zip(range_window(source, N), destination))
{
dest.some_op(range.begin(), range.end());
}
--
You received this message because you are subscribed to a topic in the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this topic, visit https://groups.google.com/a/isocpp.org/d/topic/std-proposals/lk5oLy6qM7Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAC%2B0CCPSw-HJewUbR9Py_2qmU2xgq-3vCU9pciiPTNQucomWEw%40mail.gmail.com.
On Monday, January 8, 2018 at 4:21:07 PM UTC+2, Marcin Jaczewski wrote:
On Monday, January 8, 2018 at 10:01:53 AM UTC+1, Jake Arkinstall wrote:3) It introduces variables that aren't actually used. After all, the `// use` part doesn't care about `src_p` and `dst_p`. It will never modify those variables; it only uses what they point to.That's an assumption. For the specific 2d image iteration it very well might be the case but there are situations in data processing in which it is not. For example, operations/observations on local windows of data. This is not uncommon.For me, any "solution" which removes my access to a range of N elements before the one explicitly pointed to by the loop iterator is useless.for(auto s_first = cbegin(source),s_last = s_first + N,dest = begin(destination);s_last != cend(source);++s_first, ++s_last, ++dest){dest->some_op(s_first, s_last);}I would prefer it to look like:
for (auto& [range, dest] : zip(range_window(source, N), destination))
{
dest.some_op(range.begin(), range.end());
}
Ironically examples like this only prove the need for multiple variables declaration - range and dest are two variables, both of different type.
Sure it is better written that way, but can it be *always* written like that? Nicol Bolas will say Yes, but I doubt.
Sometimes there might be a need for more control over the variables (or the iteration), sometimes it might cumbersome to wrap everything in pretty range interfaces.
Manual variable initialization will always have its place.
And as I said, it is not just for. Other use case are bound to come:if(auto lock = std::lock_guard(mtx)
, queue = getQueue();
!queue.empty())
{
// use queue}if(auto a = weakA.lock()
, b = weakB.lock();
a && b)
{
// use a and b
}These are pretty reasonable.Sooner or later the one variable or multiple with the same type limitations will become too limiting, simply because they don't have any semantic sense.At that point people will just start using hacks (like the tuple one).
{
auto a = weakA.lock();
auto b = weakB.lock();
if(a && b)
{
// use a and b
}
}
You are right that view are not silver bullet that will fix all possible problems and in the and we will need use old `for` for some cases. Question is how many times you have case that using some standard view or writing new one (even if it will be use only one time) will be inappropriate? Exactly where line is in many times depend on taste but overall we could agree on order of magnitude.How often you need have to write this loops that can not be replaces by view? If it will happens very often then indeed this change could improve overall langue but if is not? Then I will leave this as is.