class image
{
...
public:
...
pixel & operator[](size_t x, size_t y)
{
return internal_data[x+y*width];
}
};
/// used like:
image my_image = ...;
...
pixel px = my_image[5, 3];
[{...}]
output[{x,y}] = value;
int f(const std::vector<int>& v) { return v[5, 3];}
struct two_indices { std::size_t x; std::size_t y; };
pixel & operator[](two_indices ixs)
{
return internal_data[ixs.x + ixs.y * width];
}
template<int index_count>
using index_list = std::array<std::size_t, index_count>;
pixel & operator[](index_list<2> ixs)
{
auto [x, y] = ixs;
return internal_data[x + y * width];
}
matrix[1]; //Accesses column.
matrix[1_row]; //Accesses row.
matrix[{1, 2}]; //Accesses scalar.
My suggestion is to allow overloading operator [] with multiple arguments
(?<!\[)\[([^[\](){}]*(?<!\[)\[(?1)\][^[\](){}]*|[^[\](){}]*\((?1)\)[^[\](){}]*|[^[\](){}]*\{(?1)\}[^[\](){}]*|[^[\](){}]*)+,(?1)+\]
(?:\n|^)(?:\/(?!\/|\*)|[^\/\n])*[a-zA-Z_)\]}>$]\s*(?<!\[)\[((?<!\[)\[(?1)*\]|\((?1)*\)|\{(?1)*\}|[^[\](){}])*,(?1)*\]
foo[ bar<4,5>::value ]
/**
\code
placeholder<int> _i;
placeholder<double> _d;
sregex rex = ( some >> regex >> here )
[ ++_i, _d *= _d ];
\endcode
*/
I understand, that this breaks existing code. But the question is rather: How much?
//old code
a[b, c];
// new code
a[(b, c)]
Actually, here's a way to make the change 100% backwards compatible.When foo[a, b, ...] is detected, the compiler must check for operator[](...) in the dereferenced type foo. If any overload of operator[] has multiple arguments, then it must call operator[](a, b, c). Otherwise, the call is operator[]((a, b, c)) etc. instead.This check would be done during semantic analysis anyway, so I don't think it'd be very difficult to do.
So, vector[a, b] would use operator,(...), whereas image[a, b] would use operator[](size_t x, size_t y). So there you go, no backwards compatibility breaks.
class Meow
{
...
int &operator[](size_t x, size_t y);
};
Meow meow;
meow[1][2] = 3; // same as meow.operator[](1, 2) = 3;
On Saturday, November 25, 2017 at 2:08:25 PM UTC-5, Ryan Nicholl wrote:
My suggestion is to allow overloading operator [] with multiple arguments, e.g.:
class image
{
...
public:
...
pixel & operator[](size_t x, size_t y)
{
return internal_data[x+y*width];
}
};
/// used like:
image my_image = ...;
...
pixel px = my_image[5, 3];
Would be most useful where I see
[{...}]
currently. E.g.:when processing images.
output[{x,y}] = value;
You've essentially undermined your proposal by highlighting a problem with most multi-argument `[]` proposals.
As it currently stands `output[x, y]` already has a meaning. Namely, it's equivalent to `output[y]`; the entire text between the `[]` is taken as a single expression, rather than a list of arguments.
So you have to invent a new syntax to make what you want possible. Namely, `output[{x, y}]`.
On Saturday, November 25, 2017 at 4:11:21 PM UTC-5, Nicol Bolas wrote:On Saturday, November 25, 2017 at 2:08:25 PM UTC-5, Ryan Nicholl wrote:
My suggestion is to allow overloading operator [] with multiple arguments, e.g.:
class image
{
...
public:
...
pixel & operator[](size_t x, size_t y)
{
return internal_data[x+y*width];
}
};
/// used like:
image my_image = ...;
...
pixel px = my_image[5, 3];
Would be most useful where I see
[{...}]
currently. E.g.:when processing images.
output[{x,y}] = value;
You've essentially undermined your proposal by highlighting a problem with most multi-argument `[]` proposals.
As it currently stands `output[x, y]` already has a meaning. Namely, it's equivalent to `output[y]`; the entire text between the `[]` is taken as a single expression, rather than a list of arguments.
So you have to invent a new syntax to make what you want possible. Namely, `output[{x, y}]`.Why would anyone currently want to use a comma separated list inside of a `[]` is beyond me.
This conflicts with already valid syntax:
int f(const std::vector<int>& v) {return v[5, 3];}Does that work as a 2D ref? Looks like it would be interpreted as two comma separated expressions, returning the 4th element of v. 5 would be ignored.
On Saturday, December 16, 2017 at 11:40:42 AM UTC-5, adrian....@gmail.com wrote:
On Saturday, November 25, 2017 at 4:11:21 PM UTC-5, Nicol Bolas wrote:
Since we're talking about a feature of such minor consequence, I would say that even minor breaking changes means that it's not worth the risk.
It is legal code today, so changing its meaning is a breaking change.
On 16 Dec 2017 16:45, "Nicol Bolas" <jmck...@gmail.com> wrote:It is legal code today, so changing its meaning is a breaking change.Not necessarily though. If the array access operator accepts N arguments and M > N arguments are provided, the comma operator can apply. If it accepts N arguments and N arguments are provided, it handles them accordingly.
If we follow that rule, then this is not a breaking change - simply because we have no multi-dimensional array access operator.
matrix[{1,2}];matrix(1,2);matrix[1][2];
they will need to remember "use bracket for array indexing, and add braces for array multi-indexing".
Worse, a new user might even try to see if it compiles without the braces, or simply forget them. And compile it will.
Perhaps with a warning from the compiler about an unused statement, but note that there is no possibility for a library solution to warn about this error.
The second does not look like an array indexing operation, but like a function call or a constructor. This is the solution that most libraries nowadays adopt (see references below). It is not dangerous as the above, but it is irritating because it does not convey the correct intent. Syntax highlighters need to parse the definition of "matrix" to know whether "matrix(1,2)" is a function call or not. As a result, most highlighters I have seen treat "matrix(1,2)" as a function call, which is incorrect.
Then you have "matrix[1]" for sequential element access (i.e., as laid out in memory), and "matrix(1,2)" for structured element access, why the need for two separate notations when the concept is the same? It's another cognitive burden placed on the user.
The third fixes the issues of the above two, but it also has several drawbacks of its own. First, it is not possible to disentangle cases where one wants sequential access (go through the array as it is laid out in memory) and structured access (follow the array's multi-dimensional shape). "matrix[1]" represents the second row (or column), not a scalar value. This can still be done by going through a proxy class/function, e.g., "matrix.sequential[1]", so I would say it is not such a big deal. Second, "matrix[1][2]" requires splitting the indexing between two function calls, and creating a temporary for "matrix[1]". This may or may not imply runtime overheads, but certainly will increase compile time and library complexity. In case of >2D arrays, it also makes it impossible to spot cases where the user forgot to specify the last index (i.e., "matrix[1][2]" instead of "matrix[1][2][3]") at the location of the indexing; the error (if any) will happen latter when the user tries to use "matrix[1][2]" as a scalar.
Lastly, all above solutions still do not fix the issue that "matrix[1,2]" is currently well defined and most certainly does not do what anyone would want it to.
So yes, allowing "matrix[1,2]" as an operator[] overload is a breaking change, but it is my opinion one case where benefits greatly outweigh the costs. And this is not a niche case. Data science is becoming an increasingly important discipline nowadays, and I think C++ is lagging behind other languages like python, R, etc, (even though C++ outperforms them all) in part because it lacks such simple things.
Are you seriously telling me that people would use C++ for these applications, but are warded off just because they can't use `[]` and would have to resort to `()`? I find myself doubtful that any person is picking languages based on trivial syntax like that.I think you're exaggerating the importance of this syntax.
My overall point is this.We can all agree that `[1, 2]` would be ideal. But because this already has meaning in C++, we can't change it without going through a round of deprecation. So you'd be looking at 6-9 years before we could even add the language feature that lets us give `[1, 2]` the meaning we want.Is this feature worth that wait? Is it worth the effort of deprecating comma expressions in brackets? Or should we just encourage the use of alternatives?I say it'd be easier to add a language feature to allow `[{1, 2}]` to work on language arrays than to make `[1, 2]` work. Let's canonize that idiom by adding it to the language. That's something that could (in theory) happen in the C++20 time frame, since it doesn't break backwards compatibility.So you can either wait 6-9 years for perfection, or get something right now that is almost as good.
On Saturday, January 6, 2018 at 5:33:08 PM UTC+1, Nicol Bolas wrote:My overall point is this.We can all agree that `[1, 2]` would be ideal. But because this already has meaning in C++, we can't change it without going through a round of deprecation. So you'd be looking at 6-9 years before we could even add the language feature that lets us give `[1, 2]` the meaning we want.Is this feature worth that wait? Is it worth the effort of deprecating comma expressions in brackets? Or should we just encourage the use of alternatives?I say it'd be easier to add a language feature to allow `[{1, 2}]` to work on language arrays than to make `[1, 2]` work. Let's canonize that idiom by adding it to the language. That's something that could (in theory) happen in the C++20 time frame, since it doesn't break backwards compatibility.So you can either wait 6-9 years for perfection, or get something right now that is almost as good.To reply to your previous message, yes I think people get turned off C++ because of small awkwardness like these. Of course it's not one such little detail that tips the balance, but the whole package of it. We're slowly making things simpler with each iteration of the language (range-based loops, auto, etc), and I think we should continue down that road to make C++ as intuitive to use as possible, if it is to compete with cute newborn languages.As for your proposal. Consider someone new to the language seeing the "[{1,2}]" construct, and wondering why it is spelled like this.
Can you imagine what they will think when they are told "yeah, it is because [1,2] is a valid syntax that throws away 1 and uses 2 as an index"?
My bet is on "why on earth would someone want that? and why is it given a simpler, more accessible syntax?". It does not inspire trust in how the language was designed.
So I'm willing to wait for perfect. If I know anything about C++ standardization, is that 6-9 years of wait is as good as it gets ;)
--
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/CAC%2B0CCNhTj2iP-LHbKsVyf%3Dgm-iwnCe7j3aMQBwJ1t6tdpu40Q%40mail.gmail.com.
On Saturday, January 6, 2018 at 12:07:22 PM UTC-5, schreiber...@gmail.com wrote:On Saturday, January 6, 2018 at 5:33:08 PM UTC+1, Nicol Bolas wrote:My overall point is this.We can all agree that `[1, 2]` would be ideal. But because this already has meaning in C++, we can't change it without going through a round of deprecation. So you'd be looking at 6-9 years before we could even add the language feature that lets us give `[1, 2]` the meaning we want.Is this feature worth that wait? Is it worth the effort of deprecating comma expressions in brackets? Or should we just encourage the use of alternatives?I say it'd be easier to add a language feature to allow `[{1, 2}]` to work on language arrays than to make `[1, 2]` work. Let's canonize that idiom by adding it to the language. That's something that could (in theory) happen in the C++20 time frame, since it doesn't break backwards compatibility.So you can either wait 6-9 years for perfection, or get something right now that is almost as good.To reply to your previous message, yes I think people get turned off C++ because of small awkwardness like these. Of course it's not one such little detail that tips the balance, but the whole package of it. We're slowly making things simpler with each iteration of the language (range-based loops, auto, etc), and I think we should continue down that road to make C++ as intuitive to use as possible, if it is to compete with cute newborn languages.As for your proposal. Consider someone new to the language seeing the "[{1,2}]" construct, and wondering why it is spelled like this.Why do they care? A new user needs to learn that things are spelled as they're spelled."Why" is not an important matter for their learning at this point. Syntax is whatever it is.
Can you imagine what they will think when they are told "yeah, it is because [1,2] is a valid syntax that throws away 1 and uses 2 as an index"?But that's not why. They should be told "The expression `1, 2` is a valid expression that throws away 1 and uses 2. So we wrap it up in an initializer list so that it will be treated as a sequence of values and not an expression." That `[]` is involved is not really the point.
My bet is on "why on earth would someone want that? and why is it given a simpler, more accessible syntax?". It does not inspire trust in how the language was designed.This one wart will not be noticed among the thousands of other warts C++ has. And however much you may think things in C++ are becoming simpler, the number of warts increases with each revision.
It's not just about the wait time. It's also about the pain of it. Getting such a change standardized will not be easy, nor will people changing their code be easy. Those facts, coupled with the relative unimportance of the eventual goal, makes it highly unlikely that this would get standardized. The committee has better things to spend time on, and C++ users have better things to do than add `()` to perfectly functional code.It isn't worth the wait, and it isn't worth the code changes. The perfect syntax isn't worth the effort needed to get there.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
How about this (admittedly offbeat) syntax:x[1; 2; 3] // use semicolons to separate multidimensional indexes