Boost logo

Boost :

From: Ed Brey (brey_at_[hidden])
Date: 2000-02-22 09:55:43


From: "Jens Maurer" <jmaurer_at_[hidden]>
>
> I've implemented a generator_iterator decorator and extended
> random_demo.cpp to show the usage. However, the iterator
> interface isn't that useful anyway, because I haven't found
> an STL algorithm you could sensibly use with this kind of
> iterator: algorithms usually want some "past-the-end" iterator
> to say "STOP" to them, which we simply cannot provide for random
> numbers in the general case (that's why they're random, after all).

The potential to use random iterators exists. For example, to apply some
randomness to each element of a vector, one might use:

std::vector<SomeType> v;
std::transform(v.begin(), v.end(), rng, v.begin(), ApplyRand());

> Does anyone have convincing arguments why (3) fits more nicely
> in some existing framework such as STL?
>
> Is using the generator_iterator decorator too much a nuisance for
> the casual user? Personally, I'm still very happy with saying
> int tmp = rng(); if(tmp < 1 || tmp > 5) do_this(); else do_that();
> Using explicit function-call syntax (albeit on a function object)
> shows to the user that potentially voluminous things are going on
> behind the scenes. Consider random_device as an example. However,
> I recognize "++rng" as some lightweight operation, such as
> incrementing an integer or pointer or advancing an iterator,
> which are all just a few clock cycles. In short, providing an
> operator++ violates the principle of least surprise for me.

Whether the above example qualifies as "convincing" is a good question. It
all depends how common such use cases would be. I generally agree with your
above analisys and like the explicitness of using a temporary where one is
needed, partly because there need to worry about a call to another function
"incrementing" the random number as a side effect. Since rngs tend to be
shared between between multiple functions that may use them, I see this as a
real danger, and a point where bugs may easily slip in during maintenence.

On the other hand, I don't think of ++iterator as all that light weight,
since, although the amortized complexity of all iterator operations is O(1),
the actual complexity for a particular operation may be O(log(n)) (as in the
case of set::iterator) or even O(n) (for back_insert_iterator). And so I
like keeping operator++ to update and operator* to get (and reget) the
current value, so that algorithms can use it.

It would seem that the most accomidating solution would be to keep
operator++ and operator* for use by algorithms and rely on programmar
disciplin to use temporaries if there is (or may be) a danger or a side
effect from a function call updating a random number between references. To
encourage disciplin, I think that operator int() should not exist, so that
the interface looks like that of an iterator, which encourages the the
programmer to think of the rng as a global iterator, which should help make
it clear that side effects are a danger.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk