Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.
The main motivation for this proposal is consistency.
It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.
On Friday, June 23, 2017 at 1:03:38 PM UTC-4, jmo...@aldebaran.com wrote:Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.
OK, first question: what's the syntax for preventing people from overriding these things on my types?
The main motivation for this proposal is consistency. It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.
But `operator()` can take anything; you can inject entire interfaces into a type through clever use of tag types. Overloading `operator()` from outside a type is functionally equivalent to allowing you to add (non-friend) member functions to a type.
On Fri, Jun 23, 2017 at 5:17 PM, Nicol Bolas <jmck...@gmail.com> wrote:So the damage you can cause
What makes it "damage"?
But `operator()` can take anything; you can inject entire interfaces into a type through clever use of tag types. Overloading `operator()` from outside a type is functionally equivalent to allowing you to add (non-friend) member functions to a type.
And that could lead to dancing? What exactly is the problem here? It makes that much of a difference to deny saying Object(a, b, c) and forcing people to say Apply(Object, a, b, c)?
As is, a type that has a member function template makes even its private members accessible to everyone, so privacy is dead anyway:
Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.The main motivation for this proposal is consistency. It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.
Thank you in advance for your reviews and comments.
This email and any attachment thereto are confidential and intended solely for the use of the individual or entity to whom they are addressed.
If you are not the intended recipient, please be advised that disclosing, copying, distributing or taking any action in reliance on the contents of this email is strictly prohibited. In such case, please immediately advise the sender, and delete all copies and attachment from your system.
This email shall not be construed and is not tantamount to an offer, an acceptance of offer, or an agreement by SoftBank Robotics Europe on any discussion or contractual document whatsoever. No employee or agent is authorized to represent or bind SoftBank Robotics Europe to third parties by email, or act on behalf of SoftBank Robotics Europe by email, without express written confirmation by SoftBank Robotics Europe’ duly authorized representatives.Ce message électronique et éventuelles pièces jointes sont confidentiels, et exclusivement destinés à la personne ou l'entité à qui ils sont adressés.
Si vous n'êtes pas le destinataire visé, vous êtes prié de ne pas divulguer, copier, distribuer ou prendre toute décision sur la foi de ce message électronique. Merci d'en aviser immédiatement l'expéditeur et de supprimer toutes les copies et éventuelles pièces jointes de votre système.
Ce message électronique n'équivaut pas à une offre, à une acceptation d’offre, ou à un accord de SoftBank Robotics Europe sur toute discussion ou document contractuel quel qu’il soit, et ne peut être interprété comme tel. Aucun employé ou agent de SoftBank Robotics Europe n'est autorisé à représenter ou à engager la société par email, ou à agir au nom et pour le compte de la société par email, sans qu’une confirmation écrite soit donnée par le représentant légal de SoftBank Robotics Europe ou par toute autre personne ayant reçu délégation de pouvoir appropriée.--
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/8bd2a86c-2b01-491b-8ee9-30d78aa4b35e%40isocpp.org.
On Friday, June 23, 2017 at 12:03:38 PM UTC-5, jmo...@aldebaran.com wrote:The main motivation for this proposal is consistency. It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.The examples for non-member operator[] and operator() seem pretty uncompelling. The first one seems like a bad algorithm (why not just pass in a predicate instead of enforcing indexing? It'd probably be less typing overall), the second one doesn't even directly use your operator() anywhere - it's buried... somewhere. I think these could use much stronger examples of cases where the best solution would be to add the overload, but we can't, so we're left with some subpar solution. And provide before/after examples demonstrating the improvement. Otherwise, right now it's kind of... meh.
For operator->(), that one is fundamentally different. Either the class is designed to be a proxy pointer/iterator... or not. What would it mean to add operator->() to some other class? Do you have an example for wanting to do this?
On 23 June 2017 at 10:03, <jmo...@aldebaran.com> wrote:Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.The main motivation for this proposal is consistency. It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.Overloading operator-> would mean that there can be a set of possible operator-> functions for a single type, with different return types. What do you expect to happen there? Should the selected operator-> depend on whether the type contains the named member? (You might like to look at the 'operator.' wording to get some idea of how complicated this can become.)
Overloading operator() sounds like it would potentially lead to a much more expensive overload resolution process for potentially every function call in the program, unless it's handled very carefully. For instance, someone is going to write something like this:template<typename R, typename ...T, typename ...U,enable_if<each_U_is_either_T_or_optional_T<list<T...>, list<U...>>::value, int> = 0>optional<R> operator()(R(*f)(T...), U &&...u) {/* if any u's are nullopt, return nullopt, otherwise return f(unwrap(forward<U>(u))) */}... in order to allow:optional<int> a, b;int f(int x, int y);optional<int> c = f(a, b); // implicitly use ::operator() here, only call 'f' if neither 'a' nor 'b' is nullopt... and likewise for a bunch of other templates that are functors in the category theory sense.And now we potentially have a large number of operator() overloads to consider for every single function call, and considering each of them requires some nontrivial template instantiation work.
Overloading operator[] seems fine, though. It's just a normal binary operator with slightly funny syntax, after all.
Thank you in advance for your reviews and comments.
This email and any attachment thereto are confidential and intended solely for the use of the individual or entity to whom they are addressed.
If you are not the intended recipient, please be advised that disclosing, copying, distributing or taking any action in reliance on the contents of this email is strictly prohibited. In such case, please immediately advise the sender, and delete all copies and attachment from your system.
This email shall not be construed and is not tantamount to an offer, an acceptance of offer, or an agreement by SoftBank Robotics Europe on any discussion or contractual document whatsoever. No employee or agent is authorized to represent or bind SoftBank Robotics Europe to third parties by email, or act on behalf of SoftBank Robotics Europe by email, without express written confirmation by SoftBank Robotics Europe’ duly authorized representatives.Ce message électronique et éventuelles pièces jointes sont confidentiels, et exclusivement destinés à la personne ou l'entité à qui ils sont adressés.
Si vous n'êtes pas le destinataire visé, vous êtes prié de ne pas divulguer, copier, distribuer ou prendre toute décision sur la foi de ce message électronique. Merci d'en aviser immédiatement l'expéditeur et de supprimer toutes les copies et éventuelles pièces jointes de votre système.
Ce message électronique n'équivaut pas à une offre, à une acceptation d’offre, ou à un accord de SoftBank Robotics Europe sur toute discussion ou document contractuel quel qu’il soit, et ne peut être interprété comme tel. Aucun employé ou agent de SoftBank Robotics Europe n'est autorisé à représenter ou à engager la société par email, ou à agir au nom et pour le compte de la société par email, sans qu’une confirmation écrite soit donnée par le représentant légal de SoftBank Robotics Europe ou par toute autre personne ayant reçu délégation de pouvoir appropriée.
--
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-proposal...@isocpp.org.
Le vendredi 23 juin 2017 21:59:24 UTC+2, Barry Revzin a écrit :
On Friday, June 23, 2017 at 12:03:38 PM UTC-5, jmo...@aldebaran.com wrote:The main motivation for this proposal is consistency. It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.The examples for non-member operator[] and operator() seem pretty uncompelling. The first one seems like a bad algorithm (why not just pass in a predicate instead of enforcing indexing? It'd probably be less typing overall), the second one doesn't even directly use your operator() anywhere - it's buried... somewhere. I think these could use much stronger examples of cases where the best solution would be to add the overload, but we can't, so we're left with some subpar solution. And provide before/after examples demonstrating the improvement. Otherwise, right now it's kind of... meh.
About the first example, you could also use operator[] to modify / create an element à la std::map. In this case, a predicate would not be enough. `[]` could be used as a "standard" way to access an element.
But in the current state of the language, while designing a concept it is best to avoid relying on [] and (), if you want your concepts to be as easy to model as possible: if operator() and operator[] were not defined by the creator of a type,
modeling the concept implies to duplicate the type (and its interface) and to add the operators. This is too much work compared to be able to define these operators as non-members.
So when designing concepts, an alternative is to use free functions (at() and call() for example), which is less natural, less concise and not compatible with builtin types.
The second example relies on function composition. If you don't have function objects, your function composition tools are unusable... Having to duplicate types instead of slightly adapting them is too bad, especially when you can do so with other operators.
For operator->(), that one is fundamentally different. Either the class is designed to be a proxy pointer/iterator... or not. What would it mean to add operator->() to some other class? Do you have an example for wanting to do this?
Currently, it is possible to implement operator* as a non-member but not operator->, which seems strange.
You often have types with methods get(), load(), value(), etc. An interesting syntax unification is to provide operator* for these types, that just forward to get() / load() / value().
Then, if you have operator* that returns an l-value, why not having operator-> ? It would allow to have the syntax (*my_object).method() equivalent to my_object->method(), as expected.
Here is another example of adapting an existing type with non-member operators. This one is currently possible, since it uses arithmetical operators:
The creator of a type is responsible for the interface she provides.
But the user can decide that in her context some operators not provided by the creator of the type are meaningful.
For example, std::array forms a mathematical vector space with most arithmetical types. Roughly speaking, this means that an std::array can represent a mathematical vector and we just have to choose an appropriate scalar type.
std::array has already the right behavior (value semantics, etc.), except for the absence of arithmetical operators (+, *, etc.).
The user can't modify std::array definition, but she can add these operators as non-members.
For example:
<snip>
The user can also add @= versions (+=, *=, etc.) for efficiency reasons.
Now the user can use std::array as a vector space in her generic algorithms.
The amount of work is minimal because of the possibility to define
non-member operators.
Le samedi 24 juin 2017 02:23:10 UTC+2, Richard Smith a écrit :On 23 June 2017 at 10:03, <jmo...@aldebaran.com> wrote:Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.The main motivation for this proposal is consistency. It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.Overloading operator-> would mean that there can be a set of possible operator-> functions for a single type, with different return types. What do you expect to happen there? Should the selected operator-> depend on whether the type contains the named member? (You might like to look at the 'operator.' wording to get some idea of how complicated this can become.)
Currently, operator-> must be defined as a non-static member function taking no parameters (16.5.6) . The non-member form would take a single argument evaluating to a class object, so there would be only one version by type, if I understand correctly.
Overloading operator() sounds like it would potentially lead to a much more expensive overload resolution process for potentially every function call in the program, unless it's handled very carefully. For instance, someone is going to write something like this:template<typename R, typename ...T, typename ...U,enable_if<each_U_is_either_T_or_optional_T<list<T...>, list<U...>>::value, int> = 0>optional<R> operator()(R(*f)(T...), U &&...u) {/* if any u's are nullopt, return nullopt, otherwise return f(unwrap(forward<U>(u))) */}... in order to allow:optional<int> a, b;int f(int x, int y);optional<int> c = f(a, b); // implicitly use ::operator() here, only call 'f' if neither 'a' nor 'b' is nullopt... and likewise for a bunch of other templates that are functors in the category theory sense.And now we potentially have a large number of operator() overloads to consider for every single function call, and considering each of them requires some nontrivial template instantiation work.I'm not sure if this example work (f is not a member function for example).
Anyway, it would be the user responsibility to add or not such an overload. And it is already possible to seriously slow down compilation by providing a bunch of template "enabled-if" operators (+, -, <<, and the others).
Overloading operator[] seems fine, though. It's just a normal binary operator with slightly funny syntax, after all.Thank you in advance for your reviews and comments.
This email and any attachment thereto are confidential and intended solely for the use of the individual or entity to whom they are addressed.
If you are not the intended recipient, please be advised that disclosing, copying, distributing or taking any action in reliance on the contents of this email is strictly prohibited. In such case, please immediately advise the sender, and delete all copies and attachment from your system.
This email shall not be construed and is not tantamount to an offer, an acceptance of offer, or an agreement by SoftBank Robotics Europe on any discussion or contractual document whatsoever. No employee or agent is authorized to represent or bind SoftBank Robotics Europe to third parties by email, or act on behalf of SoftBank Robotics Europe by email, without express written confirmation by SoftBank Robotics Europe’ duly authorized representatives.Ce message électronique et éventuelles pièces jointes sont confidentiels, et exclusivement destinés à la personne ou l'entité à qui ils sont adressés.
Si vous n'êtes pas le destinataire visé, vous êtes prié de ne pas divulguer, copier, distribuer ou prendre toute décision sur la foi de ce message électronique. Merci d'en aviser immédiatement l'expéditeur et de supprimer toutes les copies et éventuelles pièces jointes de votre système.
Ce message électronique n'équivaut pas à une offre, à une acceptation d’offre, ou à un accord de SoftBank Robotics Europe sur toute discussion ou document contractuel quel qu’il soit, et ne peut être interprété comme tel. Aucun employé ou agent de SoftBank Robotics Europe n'est autorisé à représenter ou à engager la société par email, ou à agir au nom et pour le compte de la société par email, sans qu’une confirmation écrite soit donnée par le représentant légal de SoftBank Robotics Europe ou par toute autre personne ayant reçu délégation de pouvoir appropriée.--
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-proposal...@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/8bd2a86c-2b01-491b-8ee9-30d78aa4b35e%40isocpp.org.
This email and any attachment thereto are confidential and intended solely for the use of the individual or entity to whom they are addressed.
If you are not the intended recipient, please be advised that disclosing, copying, distributing or taking any action in reliance on the contents of this email is strictly prohibited. In such case, please immediately advise the sender, and delete all copies and attachment from your system.
This email shall not be construed and is not tantamount to an offer, an acceptance of offer, or an agreement by SoftBank Robotics Europe on any discussion or contractual document whatsoever. No employee or agent is authorized to represent or bind SoftBank Robotics Europe to third parties by email, or act on behalf of SoftBank Robotics Europe by email, without express written confirmation by SoftBank Robotics Europe’ duly authorized representatives.Ce message électronique et éventuelles pièces jointes sont confidentiels, et exclusivement destinés à la personne ou l'entité à qui ils sont adressés.
Si vous n'êtes pas le destinataire visé, vous êtes prié de ne pas divulguer, copier, distribuer ou prendre toute décision sur la foi de ce message électronique. Merci d'en aviser immédiatement l'expéditeur et de supprimer toutes les copies et éventuelles pièces jointes de votre système.
Ce message électronique n'équivaut pas à une offre, à une acceptation d’offre, ou à un accord de SoftBank Robotics Europe sur toute discussion ou document contractuel quel qu’il soit, et ne peut être interprété comme tel. Aucun employé ou agent de SoftBank Robotics Europe n'est autorisé à représenter ou à engager la société par email, ou à agir au nom et pour le compte de la société par email, sans qu’une confirmation écrite soit donnée par le représentant légal de SoftBank Robotics Europe ou par toute autre personne ayant reçu délégation de pouvoir appropriée.--
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/1ff81804-737c-4999-a27b-8e10608de2cb%40isocpp.org.
On 24 June 2017 at 09:47, <jmo...@aldebaran.com> wrote:Le samedi 24 juin 2017 02:23:10 UTC+2, Richard Smith a écrit :On 23 June 2017 at 10:03, <jmo...@aldebaran.com> wrote:Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.The main motivation for this proposal is consistency. It makes also easier to externally adapt existing types for use with generic algorithms, as show examples.Overloading operator-> would mean that there can be a set of possible operator-> functions for a single type, with different return types. What do you expect to happen there? Should the selected operator-> depend on whether the type contains the named member? (You might like to look at the 'operator.' wording to get some idea of how complicated this can become.)
Currently, operator-> must be defined as a non-static member function taking no parameters (16.5.6) . The non-member form would take a single argument evaluating to a class object, so there would be only one version by type, if I understand correctly.So in cases where multiple viable operator-> functions exist, the result would be ambiguity, independent of the identifier after the -> ? That would avoid this problem, but is notably a different choice than that made during the design of 'operator.'. Your paper at least would need to describe and explain this decision.
Overloading operator() sounds like it would potentially lead to a much more expensive overload resolution process for potentially every function call in the program, unless it's handled very carefully. For instance, someone is going to write something like this:template<typename R, typename ...T, typename ...U,enable_if<each_U_is_either_T_or_optional_T<list<T...>, list<U...>>::value, int> = 0>optional<R> operator()(R(*f)(T...), U &&...u) {/* if any u's are nullopt, return nullopt, otherwise return f(unwrap(forward<U>(u))) */}... in order to allow:optional<int> a, b;int f(int x, int y);optional<int> c = f(a, b); // implicitly use ::operator() here, only call 'f' if neither 'a' nor 'b' is nullopt... and likewise for a bunch of other templates that are functors in the category theory sense.And now we potentially have a large number of operator() overloads to consider for every single function call, and considering each of them requires some nontrivial template instantiation work.I'm not sure if this example work (f is not a member function for example).I think I'm missing something -- why would it make a difference if 'f' is a member function?
Anyway, it would be the user responsibility to add or not such an overload. And it is already possible to seriously slow down compilation by providing a bunch of template "enabled-if" operators (+, -, <<, and the others).The large number of operator<< overloads are already a very significant component of compile time for many programs. This has the potential to apply the same problem to all function calls. I have not seen any evidence that programmers take this into account when adding their neat new operator overload. You're right that it's not the language's job to nanny the programmer, but the principle that you don't pay for what you don't use should apply to compilation performance as well as runtime.
I think there's also a question of whether you'd apply operator() recursively: if we can rewrite f(a, b, c) as operator()(f, a, b, c), do we then need to check whether we need to rewrite *that* as operator()(operator(), f, a, b, c) and so on? Likewise, can a + b be interpreted as operator()(operator+, a, b)?
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/1ff81804-737c-4999-a27b-8e10608de2cb%40isocpp.org.
OK, first question: what's the syntax for preventing people from overriding these things on my types?
On Friday, June 23, 2017 at 3:10:38 PM UTC-4, Hyman Rosen wrote:On Fri, Jun 23, 2017 at 1:50 PM, Nicol Bolas <jmck...@gmail.com> wrote:On Friday, June 23, 2017 at 1:03:38 PM UTC-4, jmo...@aldebaran.com wrote:Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.
OK, first question: what's the syntax for preventing people from overriding these things on my types?
Wanting to prevent people from doing things is a bad idea, because the people who want to do things are living in the future of the people who want to prevent them from doing things, and the people in the future have better information about what they need than people in the past.
In any case, having those functions defined as non-members is no different from having any other functions or operators that take such objects as parameters. I don't see why operator[] should be treated differently than operator+.
First, I contest the idea that `operator()` is no different from the others. You might argue that with `->` and `[]`, but not function call. The reason being that `operator()` has no parameter restrictions associated with it; you can overload it with any number of parameters of any type. `operator->` takes no parameters, and `operator[]` takes exactly one parameter. So the damage you can cause by external overloads is minimal.
But `operator()` can take anything; you can inject entire interfaces into a type through clever use of tag types. Overloading `operator()` from outside a type is functionally equivalent to allowing you to add (non-friend) member functions to a type.
Second, my principle objection is that these operations are fundamentally part of the type. If a type is not a pointer-like type, then it has absolutely no business overloading `operator->`. If a type is not an array-like type, then it has no business overloading `operator[]`. And if a type is not a function-like type, then it has no business overloading `operator()`. And these are fundamental properties of the type; they're not something you can just graft onto any old type you like.
在 2017年6月24日星期六 UTC+8上午5:17:59,Nicol Bolas写道:On Friday, June 23, 2017 at 3:10:38 PM UTC-4, Hyman Rosen wrote:On Fri, Jun 23, 2017 at 1:50 PM, Nicol Bolas <jmck...@gmail.com> wrote:On Friday, June 23, 2017 at 1:03:38 PM UTC-4, jmo...@aldebaran.com wrote:Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.
OK, first question: what's the syntax for preventing people from overriding these things on my types?
Wanting to prevent people from doing things is a bad idea, because the people who want to do things are living in the future of the people who want to prevent them from doing things, and the people in the future have better information about what they need than people in the past.
In any case, having those functions defined as non-members is no different from having any other functions or operators that take such objects as parameters. I don't see why operator[] should be treated differently than operator+.
First, I contest the idea that `operator()` is no different from the others. You might argue that with `->` and `[]`, but not function call. The reason being that `operator()` has no parameter restrictions associated with it; you can overload it with any number of parameters of any type. `operator->` takes no parameters, and `operator[]` takes exactly one parameter. So the damage you can cause by external overloads is minimal.
But `operator()` can take anything; you can inject entire interfaces into a type through clever use of tag types. Overloading `operator()` from outside a type is functionally equivalent to allowing you to add (non-friend) member functions to a type.
Second, my principle objection is that these operations are fundamentally part of the type. If a type is not a pointer-like type, then it has absolutely no business overloading `operator->`. If a type is not an array-like type, then it has no business overloading `operator[]`. And if a type is not a function-like type, then it has no business overloading `operator()`. And these are fundamental properties of the type; they're not something you can just graft onto any old type you like.I don't think so. Overloading as construction of EDSL (e.g. in boost.spirit) relies on violating your principles quite heavily.
And you even do not have ways to ensure least astonishment to well-educated newbies. Arguably, what is, say, an array-like type? How to make sure a type is like an array enough? No doubtfully `std::array` is like an array enough, but what like `std::map`? Why no `const` on its `operator[]`?
On Friday, June 23, 2017 at 6:51:43 PM UTC-4, Hyman Rosen wrote:On Fri, Jun 23, 2017 at 5:17 PM, Nicol Bolas <jmck...@gmail.com> wrote:So the damage you can cause
What makes it "damage"?
You have taken a type which was not a functor and made it a functor. You have taken a type that was not array-like or pointer-like and made it array/pointer-like.
If those are not the purpose of those types, then you have damaged that type's interface by violating the single responsibility principle.
On Sunday, July 2, 2017 at 9:40:50 PM UTC-4, FrankHB1989 wrote:在 2017年6月24日星期六 UTC+8上午5:17:59,Nicol Bolas写道:On Friday, June 23, 2017 at 3:10:38 PM UTC-4, Hyman Rosen wrote:On Fri, Jun 23, 2017 at 1:50 PM, Nicol Bolas <jmck...@gmail.com> wrote:On Friday, June 23, 2017 at 1:03:38 PM UTC-4, jmo...@aldebaran.com wrote:Hello,This is a proposal to allow operator(), operator[] and operator-> to be defined as non-member functions.I do not know if this has already been proposed and potential arguments against it, so please let me know.
OK, first question: what's the syntax for preventing people from overriding these things on my types?
Wanting to prevent people from doing things is a bad idea, because the people who want to do things are living in the future of the people who want to prevent them from doing things, and the people in the future have better information about what they need than people in the past.
In any case, having those functions defined as non-members is no different from having any other functions or operators that take such objects as parameters. I don't see why operator[] should be treated differently than operator+.
First, I contest the idea that `operator()` is no different from the others. You might argue that with `->` and `[]`, but not function call. The reason being that `operator()` has no parameter restrictions associated with it; you can overload it with any number of parameters of any type. `operator->` takes no parameters, and `operator[]` takes exactly one parameter. So the damage you can cause by external overloads is minimal.
But `operator()` can take anything; you can inject entire interfaces into a type through clever use of tag types. Overloading `operator()` from outside a type is functionally equivalent to allowing you to add (non-friend) member functions to a type.
Second, my principle objection is that these operations are fundamentally part of the type. If a type is not a pointer-like type, then it has absolutely no business overloading `operator->`. If a type is not an array-like type, then it has no business overloading `operator[]`. And if a type is not a function-like type, then it has no business overloading `operator()`. And these are fundamental properties of the type; they're not something you can just graft onto any old type you like.I don't think so. Overloading as construction of EDSL (e.g. in boost.spirit) relies on violating your principles quite heavily.
My argument is not that you shouldn't be able to overload any operator from outside the type. My argument is that you shouldn't be able to overload those operators from outside of the type. If the maker of a type didn't give it an `operator[]` overload, you don't have the right to impose one upon it.
We've been able to make EDSLs despite being unable to overload those operators from outside the type.
And you even do not have ways to ensure least astonishment to well-educated newbies. Arguably, what is, say, an array-like type? How to make sure a type is like an array enough? No doubtfully `std::array` is like an array enough, but what like `std::map`? Why no `const` on its `operator[]`?
It's interesting that you bring up `map`'s `operator[]`, because that was on my mind back when I posted that. If we had it to do over again, I rather suspect that `map` would not have an `operator[]` overload. We've had to patch `map`'s design just to address deficiencies in `operator[]`, with `try_emplace` and `insert_or_assign` effectively doing much the job of `operator[]` much better than that function ever could.
If we still had to keep it around, it'd probably be a `const` function.