[STLInterfaces] only three operations?
Hi, While the formal review of STLInterfaces has not yet started, some early feedback may be of help. The idea to implement relational operators from binary operator- for random_access_iterator looks too clever for me. Maybe this deserves a mention in the documentation it is from operator- that the library will generate all relational ops. For non-contiguous random_access_iterators (like in deque) it might be suboptimal to do it this way: a directly provided operator== might be faster than the one synthesized from operator-. Of course, I can provide the 6 relops operators myself, but I could have only 2 if the facade were capable of generating operator!= from operator== (and similar). Could operator!= for random_access_iterator be generated from operator!= ? Regards, &rzej;
On Wed, Nov 27, 2019 at 8:38 AM Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
Hi, While the formal review of STLInterfaces has not yet started, some early feedback may be of help.
The idea to implement relational operators from binary operator- for random_access_iterator looks too clever for me.
I don't find that to be so. All those operations (the relops and op-) go together semantically. Could you elaborate on why you don't like the approach?
Maybe this deserves a mention in the documentation it is from operator- that the library will generate all relational ops.
Quite right. I'll add this if it's not already documented, or call it out if it's not obvious enough.
For non-contiguous random_access_iterators (like in deque) it might be suboptimal to do it this way: a directly provided operator== might be faster than the one synthesized from operator-. Of course, I can provide the 6 relops operators myself, but I could have only 2 if the facade were capable of generating operator!= from operator== (and similar). Could operator!= for random_access_iterator be generated from operator!= ?
It's true that the deque case will be suboptimal. Here are my considerations though: - The point of the library is to reduce the amount of code you must write to the bare minimum, and basing all the relops on op- and op== does not serve that goal. - Any generated operation (not just the relops) can be replaced by the user at will, just be having the user define that operation. In the deque case, that means defining op-, op==, and op!=. Deque is not the common case -- most random-access containers are also contiguous. I want to maintain the brevity of the common case. That means the solution is clear documentation, IMO. Zach
On 27. Nov 2019, at 15:55, Zach Laine via Boost
wrote: On Wed, Nov 27, 2019 at 8:38 AM Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
For non-contiguous random_access_iterators (like in deque) it might be suboptimal to do it this way: a directly provided operator== might be faster than the one synthesized from operator-. Of course, I can provide the 6 relops operators myself, but I could have only 2 if the facade were capable of generating operator!= from operator== (and similar). Could operator!= for random_access_iterator be generated from operator!= ?
It's true that the deque case will be suboptimal. Here are my considerations though:
- The point of the library is to reduce the amount of code you must write to the bare minimum, and basing all the relops on op- and op== does not serve that goal. - Any generated operation (not just the relops) can be replaced by the user at will, just be having the user define that operation. In the deque case, that means defining op-, op==, and op!=. Deque is not the common case -- most random-access containers are also contiguous. I want to maintain the brevity of the common case. That means the solution is clear documentation, IMO.
I think Andrzej made a good point, it should be possible to override automatically generated operators by adding a minimal number of extra operators, minimal demo: https://godbolt.org/z/zaFpBU
On Wed, Nov 27, 2019 at 9:45 AM Hans Dembinski
On 27. Nov 2019, at 15:55, Zach Laine via Boost
wrote: On Wed, Nov 27, 2019 at 8:38 AM Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
For non-contiguous random_access_iterators (like in deque) it might be suboptimal to do it this way: a directly provided operator== might be faster than the one synthesized from operator-. Of course, I can provide the 6 relops operators myself, but I could have only 2 if the facade were capable of generating operator!= from operator== (and similar). Could operator!= for random_access_iterator be generated from operator!= ?
It's true that the deque case will be suboptimal. Here are my considerations though:
- The point of the library is to reduce the amount of code you must write to the bare minimum, and basing all the relops on op- and op== does not serve that goal. - Any generated operation (not just the relops) can be replaced by the user at will, just be having the user define that operation. In the deque case, that means defining op-, op==, and op!=. Deque is not the common case -- most random-access containers are also contiguous. I want to maintain the brevity of the common case. That means the solution is clear documentation, IMO.
I think Andrzej made a good point, it should be possible to override automatically generated operators by adding a minimal number of extra operators, minimal demo:
Sure, that's easy. Modifying sequence_container to generate overloads based on op== and/or op- is not so easy. :) As I said, if you find the op==/op!= case to be less optimal when implemented in terms of op-, it's just a matter of adding your own op==, and a one-liner op!=. That's not a great deal of burden on the user. Zach
śr., 27 lis 2019 o 15:54 Zach Laine
On Wed, Nov 27, 2019 at 8:38 AM Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
Hi, While the formal review of STLInterfaces has not yet started, some early feedback may be of help.
The idea to implement relational operators from binary operator- for random_access_iterator looks too clever for me.
I don't find that to be so. All those operations (the relops and op-) go together semantically. Could you elaborate on why you don't like the approach?
I am sorry. I was writing that mail in a hurry an I failed to communicate my thoughts clearly. I do like your approach. In fact, I find it really illuminating. It is just that I find it so novel, that it could easily be taken for a mistake. I was staring at the docs for a long while, where it said the only operations I need for random access iterator was *, -, and +=, and I concluded that there must be some some error in the script that produces the documentation and the guy surely wanted to type operator== as well. Only after looking at the implementation did I realize that it was not a mistake. Hence my suggestion: make it very clear in the documentation that relops are generated from operator- for random access iterators.
Maybe this deserves a mention in the documentation it is from operator- that the library will generate all relational ops.
Quite right. I'll add this if it's not already documented, or call it out if it's not obvious enough.
For non-contiguous random_access_iterators (like in deque) it might be suboptimal to do it this way: a directly provided operator== might be faster than the one synthesized from operator-. Of course, I can provide the 6 relops operators myself, but I could have only 2 if the facade were capable of generating operator!= from operator== (and similar). Could operator!= for random_access_iterator be generated from operator!= ?
It's true that the deque case will be suboptimal. Here are my considerations though:
- The point of the library is to reduce the amount of code you must write to the bare minimum, and basing all the relops on op- and op== does not serve that goal. - Any generated operation (not just the relops) can be replaced by the user at will, just be having the user define that operation. In the deque case, that means defining op-, op==, and op!=. Deque is not the common case -- most random-access containers are also contiguous. I want to maintain the brevity of the common case. That means the solution is clear documentation, IMO.
I agree with aiming at the minimum boilerplate from the user, and I agree that non-contiguous random access iterators are so rare that they could be sacrificed. However, I believe that what I propose does not compromise your goals. As Hans pointed demonstrated, if you implement operator== using operator-, and then implement operator!= using operator== (rather than using operator-), then all your use cases work as before, but the additional gain is that if I additionally volunteer to provide my own operator== (because it is faster) you can give me operator!= for free. Does this make sense? Regards, &rzej;
Zach
On Wed, Nov 27, 2019 at 3:49 PM Andrzej Krzemienski
śr., 27 lis 2019 o 15:54 Zach Laine
napisał(a): On Wed, Nov 27, 2019 at 8:38 AM Andrzej Krzemienski via Boost < boost@lists.boost.org> wrote:
Hi, While the formal review of STLInterfaces has not yet started, some early feedback may be of help.
The idea to implement relational operators from binary operator- for random_access_iterator looks too clever for me.
I don't find that to be so. All those operations (the relops and op-) go together semantically. Could you elaborate on why you don't like the approach?
I am sorry. I was writing that mail in a hurry an I failed to communicate my thoughts clearly. I do like your approach. In fact, I find it really illuminating. It is just that I find it so novel, that it could easily be taken for a mistake. I was staring at the docs for a long while, where it said the only operations I need for random access iterator was *, -, and +=, and I concluded that there must be some some error in the script that produces the documentation and the guy surely wanted to type operator== as well. Only after looking at the implementation did I realize that it was not a mistake.
Hence my suggestion: make it very clear in the documentation that relops are generated from operator- for random access iterators.
Got it, thanks. Based on your original email, I've made this clear in the docs (though that change is not live on the website yet). [snip] It's true that the deque case will be suboptimal. Here are my
considerations though:
- The point of the library is to reduce the amount of code you must write to the bare minimum, and basing all the relops on op- and op== does not serve that goal. - Any generated operation (not just the relops) can be replaced by the user at will, just be having the user define that operation. In the deque case, that means defining op-, op==, and op!=. Deque is not the common case -- most random-access containers are also contiguous. I want to maintain the brevity of the common case. That means the solution is clear documentation, IMO.
I agree with aiming at the minimum boilerplate from the user, and I agree that non-contiguous random access iterators are so rare that they could be sacrificed. However, I believe that what I propose does not compromise your goals. As Hans pointed demonstrated, if you implement operator== using operator-, and then implement operator!= using operator== (rather than using operator-), then all your use cases work as before, but the additional gain is that if I additionally volunteer to provide my own operator== (because it is faster) you can give me operator!= for free.
Does this make sense?
Yes, it does. I'll try this, but I vaguely remember that I tried things this way and got an ambiguity. Hopefully I'm misremembering. Zach
participants (3)
-
Andrzej Krzemienski
-
Hans Dembinski
-
Zach Laine