[iterator] generator_iterator vs. function_input_iterator
Hi, There seems to be two nearly equivalent components in Boost.Iterator: generator_iterator (moved from Boost.Utility) and function_input_iterator. Both are input iterators wrapping a function object, which result is used as the dereferenced value. The difference is: - generator_iterator always creates an instance of the element type while function_input_iterator does that lazily; - function_input_iterator uses result_of while generator_iterator relies on C++03 T::result_type - equality comparison is different: generator_iterators compares equal if both refer to the same generator and cached element instances are equal while function_input_iterator uses an additional state (which can be viewed as an index) for comparison instead of the cached element. So basically, they are the same thing. generator_iterator looks a bit more dated and IMHO its comparison implementation is not as robust as that of function_input_iterator, so maybe we should deprecate it?
Andrey Semashev wrote:
There seems to be two nearly equivalent components in Boost.Iterator: generator_iterator (moved from Boost.Utility) and function_input_iterator.
`function_input_iterator`'s implementation looks better than that of `generator_iterator`. However, the name of the former is not appealing. "generate" is a standard word to Range enthusiasts -- it is used like `generate(non_pure_func) | take(10)`. Thus, I would like to deprecate `generator_iterator` first and then rename `function_input_iterator` to `generator_iterator`. Regards, Michel
On 08/31/17 19:16, Michel Morin via Boost wrote:
Andrey Semashev wrote:
There seems to be two nearly equivalent components in Boost.Iterator: generator_iterator (moved from Boost.Utility) and function_input_iterator.
`function_input_iterator`'s implementation looks better than that of `generator_iterator`. However, the name of the former is not appealing. "generate" is a standard word to Range enthusiasts -- it is used like `generate(non_pure_func) | take(10)`.
Thus, I would like to deprecate `generator_iterator` first and then rename `function_input_iterator` to `generator_iterator`.
Well, there is function_output_iterator also, I kind of like the duality. I guess we could make generator_iterator an alias in C++11, although I'm a bit worried if this could cause backward compatibility for users if they upgrade from a release with the old generator_iterator.
Andrey Semashev wrote:
Well, there is function_output_iterator also, I kind of like the duality.
Each name has supporters ;)
I'm a bit worried if this could cause backward compatibility for users if they upgrade from a release with the old generator_iterator.
Non-default constructors for function_input_iterator and generator_iterator are
incompatible; function_input_iterator has binary constructors and
generator_iterator has unary constructors. Even if we add unary
constructors that take only generator to function_input_iterator, they
are incompatible; function_input_iterator accepts lvalue objects or
function pointers and
generator_iterator accepts pointers to objects but not function pointers.
So, when upgrading from old generator_iterator to new one (i.e.
function_input_iterator), there should be compilation failures.
We can add the following constructor to help migration:
class new_generator_iterator {
new_generator_iterator(PointerToObject)
{
static_assert(false,
"The implementation of generator_iterator has changed. "
"Please consult the documentation to see how to update
the code.");
}
};
However, if users of old generator_iterator rely on behaviors of the eager
generation and of the equality operators, then the migration is hard to achieve.
OK... I drop this idea.
Range users may not care much about the name of underlying iterators;
it would be OK if range constructs have standard names. I'll submit a PR
that implements `generation` (the name `generate` is already used for
range algorithms, so I use the name `generation` which is used in the
Oven range library) to Boost.Range, which looks like
template
On 8/31/17 9:16 AM, Michel Morin via Boost wrote:
Andrey Semashev wrote:
There seems to be two nearly equivalent components in Boost.Iterator: generator_iterator (moved from Boost.Utility) and function_input_iterator.
`function_input_iterator`'s implementation looks better than that of `generator_iterator`. However, the name of the former is not appealing. "generate" is a standard word to Range enthusiasts -- it is used like `generate(non_pure_func) | take(10)`.
Thus, I would like to deprecate `generator_iterator` first and then rename `function_input_iterator` to `generator_iterator`.
Hmmmm - I'm thinking that silently changing the functionality of a component 12? years old to something "nearly" equivalent is a really bad idea. How can one know that this wouldn't break old code in a way that's just about impossible to track down. If you wanted to create a "better" naming scheme and map them to the original names with typedef or using, that would be much better and have no potential for inflicting damage on innocent bystanders, that would be OK. But then you'd have to update the documentation which is another task. Actually, I question the value in this kind of change anyway. There's nothing which would prevent users who are annoyed by this from just including a couple of typedefs/usings in their own code. This looks like cosmetic surgery where the quest for perfection is the enemy of getting the best result. Robert Ramey
Regards, Michel
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
On 31-08-17 20:18, Robert Ramey via Boost wrote:
Hmmmm - I'm thinking that silently changing the functionality of a component 12? years old to something "nearly" equivalent is a really bad idea. How can one know that this wouldn't break old code in a way that's just about impossible to track down.
+1
Robert Ramey wrote:
Hmmmm - I'm thinking that silently changing the functionality of a component 12? years old to something "nearly" equivalent is a really bad idea. How can one know that this wouldn't break old code in a way that's just about impossible to track down.
Thanks for the comment. I thought that if the following are all satisfied then it would be worth the change. But as described below, some of them are not satisfied. 1. `old_xxxx` is unanimously better name than `new_xxxx`. 2. `new_xxxx` has better implementation and new users should use the `new_xxxx`. 3. If there is any behavioral change, that should not be silent (that should result in compilation failures). 4. Easy to update old codes. - It seems that 1 is not true for other than range enthusiasts. - `generator_iterator` is easy to be misused. For example, this function void print_random_numbers(int n) { auto it = make_generator_iterator(std::random_device{}); for (int i = 0; i < n; ++i) { cout << *it << endl; } } consumes n+1 random numbers (the last random number is thrown away). `function_input_iterator` avoids such behaviors and consumes just n random numbers. So I think 2 is satisfied. - 3 is satisfied, but 4 is not satisfied unless we introduce `generator_iterator_v1` (that is, renamed old `generator_iterator`). Regards, Michel
participants (4)
-
Andrey Semashev
-
Michel Morin
-
Robert Ramey
-
Seth