Re: [boost] Determining interest in combining_iterator
[EMAIL PROTECTED] wrote: FWIW, I've extended my pair iterator to be a tuple iterator for input/forward/bidirectional/random-access iterator categories, which was relatively painless. I will boostify it, add output iterator support back in, and test it with VC7.1 as well as g++ 3.2.2, if you (or anyone else) are interested. Well, this combining iterator thing is the first time I'm ever submitting anything to boost, so I don't know if I should give advice, but what I did was to click on Submissions at www.boost.org and it said that Step 1 was to post a description of the proposed submission to the boost mailing list to determine interest. So that's what I did, and I suppose that's what you should do too. In my case, the response was not overwhelming, but it wasn't devastating either, and I got a positive from David Abrahams. So what I'll do next is to check out their new iterator adaptor stuff in the sandbox and see how my stuff fits in there or can be made to fit in. Since my combining iterator would have to be part of the iterator adaptor library, it will then ultimately be David's, Jeremy's and Thomas' decision whether they want it in there or not. Thanks a bunch for yall's feedback so far. It has certainly helped me sort things out. Finally, Anthony: As I look at the new iterator adaptor in the sandbox, I will of course keep an eye on whether their changes have any bearing on the relationship between what you have and what I have. Under the current boost iterator adaptor, I think it is clear that yours and mine are at least as different from each other as the transform iterator is different from the projection iterator, and hence they are two separate things. It may be a while until I get around to working on all this again, so let me know if you have any new insights in this regard. Thomas Becker Zephyr Associates, Inc. Zephyr Cove, NV [EMAIL PROTECTED] __ Do you Yahoo!? Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop! http://platinum.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Determining interest in combining_iterator
[EMAIL PROTECTED] wrote: Thomas Becker [EMAIL PROTECTED] writes: Unless I'm missing something, I believe that my original rough intuition was ok. Given my combining iterator, it seems very easy to write your tuple iterator by providing a simple generic reference-tuple-making functional. [...] The returned tuple of references is not copyable though --- the copies will still refer to the originals. I went through all this with my pair iterator; try using std::sort on your pair of vectors, especially with vectors of a non-POD UDT with no swap specialization, just to avoid any optimizations in your standard library. A plain tuple-of-references will screw up the vectors, you need something more complex. Also, you can't use a tuple-of-references with input iterators, since they return values not references when dereferenced, so you need to know the iterator category and use a tuple of values in this case. Finally, output iterators are even more bizarre, as writing to the result of dereferencing your combined output iterator needs to write to the result of dereferencing each of the individual output iterators, and there is no telling what type you get when you dereference an output iterator. I see now that with your tuple iterator, you are aiming much higher than I previously thought. Just like boost's transform iterators, my combining iterators are always and necessarily input iterators. (That's not really going to change under the new proposed iterator categories, although they'll help me.) I can cheat a little by returning a value that happens to hold a bunch of references, such as a boost::tuple of references. Nothing prevents me from doing that. But you want a parallel-iterator that one can, for example, pass to std::sort and have it order the underlying sequences lexicographically. That's a tall order. My combining iterator does not cover that. Neither do I think that my combining iterator is affected much by the ultimate solution to your problem. My combining iterator is a multi-dimensional boost::transforming_iterator. Yours would end up being a multi-dimensional boost::projection_iterator. That's a different colored horse. Thomas Becker Zephyr Associates, Inc. Zephyr Cove, NV [EMAIL PROTECTED] __ Do you Yahoo!? Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop! http://platinum.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Determining interest in combining_iterator
--- Anthony Williams [EMAIL PROTECTED] wrote: Basically, I think we have two contradictory scenarios. IIUC, the situations you have encountered are where you have a set of values in different containers that needed to be combined into a single value, in which case it makes sense to pass the values as distinct function arguments to a functor that does the combining. That's true, that was the scenario that the combining iterator grew out of, and that has certainly tilted my perception of the problem in that direction. But when I conceived of my combining iterator, I *did* think about the other scenario that you mention: OTOH, the situations I am thinking of require that the tuple of containers is really treated as a container of tuples, complete with the ability to update the source containers by writing to the tuple obtained by the dereferencing, but maintaining the value semantics when copied. This is really hard to do in any other way than by having *it return a magic tuple, IMHO, though if you can find a way of doing it as a functor that just works without the user having to know too much, I'll concede the point. Because of my tilted perception, I sort of dismissed that scenario by saying to myself, ah, shucks, just write a functional that returns a suitable reference, and you're good. You are now forcing me to think about this more carefully, for which I am grateful to you. Unless I'm missing something, I believe that my original rough intuition was ok. Given my combining iterator, it seems very easy to write your tuple iterator by providing a simple generic reference-tuple-making functional. As always in these situations, it's a little messy to provide one functional that will work for all n (n=number of member iterators), so for simplicity, here's the case n=2: templatetypename Type1_, typename Type2_ class FunMakeReferenceTuple_2 { public: typedef boost::tupleType1_, Type2_ result_type; boost::tupleType1_, Type2_ operator()( Type1_ refFirst, Type2_ refSecond ) const { return boost::tupleType1_, Type2_( refFirst, refSecond ); } }; I've tested this in several examples, e.g., I created two vectors of ints, filled them with values to equal length, then created a combining_iterator from the two begin positions and the functional FunMakeReferenceTuple_2int, int Once I have this combining iterator, I can read and write both vector elements to my hearts delight. E.g., std::swap(it-get0(), it-get1()); will swap the values at the current position, or, *it = boost::make_tuple(42, 43); will assign 42 and 43 to the respective vector elements. If you want to, you can easily wrap all this up and provide a tuple_iterator which internally uses my combining iterator in conjunction with the reference-tuple-making functional. I now strongly believe that that's the way to go. The combining iterator handles for you everything that has to do with the parallel-iteration. Via the funcional, you decide how to process the dereferenced iterators. The tuple_iterator is the special case (or rather, the large subclass of cases) where that processing consists of making a tuple of references. There's certainly more to think about, like, what about const tuple iterators, but I believe that the questions and answers are the same whether you write the tuple iterator from scratch or use my combining iterator. In fact, doing it with the combining iterator seems somehow intellectually cleaner to me, because all the parallel iteration stuff is hidden and out of the way, so you can focus on the tuple issues. BTW, in my software, I do have cases where I need to parallel iterate and write to the current positions, but in those cases, I always deal with sequences of possibly different length (think portfolio of assets with different dates of inception). Now parallel-iteration is really ugly business. There's always a bigger can of worms... Thomas Becker Zephyr Associates, Inc. Zephyr Cove, NV [EMAIL PROTECTED] __ Do you Yahoo!? Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop! http://platinum.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Re: Determining interest in combining_iterator
Anthony Williams wrote: The particular example I cited in the article is where a colleague had a pair of vectors which were the x and y values respectively for a graph. They were supplied as two vectors, and the graph drawing code required them as two vectors, yet the analysis code in the middle required a sequence of (x,y) pairs I have to admit this very example has convinced me that my original approach is right. Suppose we were to write, as you suggest, an iterator adaptor that holds a tuple of iterators and, upon dereferencing, returns a tuple made from the dereferenced iterators. What would we have done for the person in your example? Nothing. He needs a *pair*, not a tuple. The big picture is: we want an iterator that parallel-iterates through several sequences, and upon dereferencing, applies some user-defined (via a functional) prossesing to the dereferenced iterators. If the desired result is a pair, supply a functional that makes a pair from its arguments. In my applications, I want a number that is calculated from the dereferenced iterators, so I supply something like std::divides. If the desired result is a tuple made from the dereferenced iterators, no problem, supply a functional that makes a tuple from its arguments. If we used your approach, we would give this one special type of processing, where a tuple is made from the dereferenced iterators, a very special and prominent place in the design. Why? It's just one of infinitely many things that someone might want to do. (Ironically, it's the one for which we have not seen a real-life need.) My general approach covers it with no fuss and no overhead. One simple iterator adaptor that does it all. We get everything that we would get in your approach, and it's simpler and more user-friendly. Unless I'm missing something... Thomas Becker Zephyr Associates, Inc. Zephyr Cove, NV [EMAIL PROTECTED] __ Do you Yahoo!? Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop! http://platinum.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Determining interest in combining_iterator
On 26 Mar 2003, Anthony Williams wrote: It strikes me that if you dereference n iterators, you have n values, and the most natural way to store them is a tuple. --- Douglas Paul Gregor [EMAIL PROTECTED] wrote: I would agree if tuples and argument passing were more closely linked, i.e., if passing a tuple to a function meant that the tuple would be automagically unpacked into separate arguments. From a user's point of view, this seems a very strong argument to me. For instance, in my software, I use combining iterators with functionals such as std::divides. If I were forced to accept my arguments as a tuple, I couldn't use any of these functionals without the extra unpacking step. Besides, introducing the tuple in the middle between dereferencing the iterators introduces the possibility of inadvertent extra value copies. Another big headache for the user. And why all that? I really don't see any advantage to this intermediate step of packaging the derefernced iterators into a tuple, only to unpack it in 99.999% of the cases. What for? Once again: The big picture is that we want an iterator that parallel-iterates over several sequences and upon dereferencing, applies some processing to the dereferenced iterator. This processing is specified by the user via a fuctional. One of the many, many things that such a functional can do is package the arguments into a tuple, if that is what's needed. (Although we still haven't seen a single real-life request for that). Why on earth would I, in the general case, introduce a packaging/unpackaging step in the middle between dereferencing the iterators and passing them to the functional? Am I missing something? BTW, Anthony: In one of my CUJ columns, I made a big fool of myself by gratuitously packaging function arguments into a tuple, and I seem to remember that you were one of the people who pointed this out to me. Looks like we switched sides in this argument... ;-) Thomas Becker Zephyr Associates, Inc. Zephyr Cove, NV __ Do you Yahoo!? Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop! http://platinum.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Re: [boost] Determining interest in combining_iterator
Thanks for your comments on the combining iterator. David Abrahams wrote: It's a wonderful idea, Thomas! You might look at the Boost sandbox; Jeremy Siek, Thomas Witt and I are trying to finalize the work in the boost/iterator and libs/iterator directories to replace the current iterator adaptors Thanks for your kind words. I'll play with the sanbox stuff. Is the main purpose there to incorporate better iterator categories? Anyway, I won't take any further action until all that has settled down. Douglas Paul Gregor wrote: Sounds great. Since the functionality is a direct generalization of transform_iterator, I'd prefer to use the name transform_iterator and either (a) switch entirely to your combining_iterator implementation or (b) give transform_iterator_generator the brains to switch between your implementation and the existing implementation based on the number of iterators being adapted. Uh uh, I was kinda hoping nobody would bring that up, because I agree and at the same time strongly disagree. Of course you're right, the transforming iterator is a special case of the combining iterator, and under any kind of theoretical point of view, it should be treated as such. There is no way I can argue with you on that. And yet, I am very strongly in favor of keeping the two entirely separate. Here's why: From a library user's point of view, the fact that the transforming iterator is a special case of the combining iterator is quite accidental. If someone is looking for the functionality of the transforming iterator, she should find just that, without being forced to view the thing she's looking for as a special case of something completely different. One could in fact express this viewpoint in a somewhat theoretical manner by saying that the transforming iterator is not so much a *special* case of the combining iterator than a *degenerate* case. Combining iterators is not where one would naturally look when in need of a transforming iterator. Anthony Williams wrote: IMHO, it seems more logical to split the concept, so the grouping of the iterators is separated from the transformation By separating the grouping and the transforming, do you mean to write an iterator that holds a tuple of iterators and then, upon dereferencing, returns the tuple of dereferenced values, and then use that in conjunction with boost's transforming iterator? That would make a lot of sense. However, I would need a little convincing that it really adds useful functionality that people are looking for. Paul A. Bristow wrote: I can see this VERY useful to some, but probably not widely useful. In view of the emphasis on very, I'll count that as a yes vote. Thomas Becker Zephyr Associates, Inc. Zephyr Cove, NV __ Do you Yahoo!? Yahoo! Platinum - Watch CBS' NCAA March Madness, live on your desktop! http://platinum.yahoo.com ___ Unsubscribe other changes: http://lists.boost.org/mailman/listinfo.cgi/boost