Mattia Barbon wrote: >> set P1, P0 # tells P1 that he's going to iterate P0 > > This looks like a kludge. IMHO the correct way of getting an iterator > is having the aggregate return it (say, using find_method/invoke);
that's a correct assumption, and when find_method/invoke will be implemented, there will be something like that. but this doesn't change much in the Iterator implementation. it will be just another way (probably the preferred one) to get an Iterator. <rant> either way, the PASM language is not intended for humans(*), doesn't strive for inner elegance and perfect orthogonality, so kludges are legal as long as they gain us speed :-) (*) read: it is not intended to be something you will have fun(**) programming in, there's Perl for this. (**) but then, there are people actually having fun programming in Befunge, so this statement could not apply at all :-) </rant> > and the iterator does not need to be of class Iterator, it just needs > to behave like one. Otherwise your Iterator needs to know all the > types it has to iterate over, which is bad. that's not the case. the Iterator *need* to be of class Iterator, as I'm going to demonstrate. as I implemented it, it actually doesn't need to know all the types it has to iterate over, as I'm going to show. on the other hand, the current Iterator PMC does not actually *implement* an iterator, but in some sense it behaves like one. it's the aggregate itself that needs to implement the methods to iterate its own data structure, so what you say is partly correct. the design of Iterator.pmc has the following objectives: 1. provide an abstract (read: aggregate-independant) interface to iterate an aggregate 2. provide an object that is external to the aggregate, so that one aggregate can have multiple iterators point 1. is accomplished through vtable entries. the aggregate should implement the following functions for Iterator to work: INTVAL iterator_sizeof() void iterator_reset() void iterator_set(void *data) void iterator_get(void *data) PMC* iterator_get_current() void iterator_next(); once an Iterator is "assigned" to an aggregate PMC, it calls its iterator_sizeof() method. INTVAL iterator_sizeof() this should return the amount of memory required to store and mantain iterator state information. for example, iterating an Array only requires an INTVAL (the current index in the array), so sizeof(INTVAL) will be returned. iterating an Hash requires two values (the bucket chain index and a pointer to the current HashBucket, but these are details), so PerlHash's iterator_sizeof() will return sizeof(HashIndex) + sizeof(HASHBUCKET*). the Iterator PMC allocates the proper amount of memory so that it can mantain its own state information (see point 2.). void iterator_set(void *data) this sets the aggregate's iterator state to the given "data", eg. the amount of memory allocated with iterator_sizeof(). void iterator_get(void *data) this gets the aggregate's iterator state so that the Iterator PMC can update its own "data". PMC* iterator_get_current() void iterator_reset() void iterator_next() these are the methods that actually does the iteration. as you can see, all the iteration stuff is done by the aggregate PMC class itself. the Iterator PMC provides opcode mapping for its action (eg. inc for next, etc.), as well as storage for its own state. this way, an aggregate (which really does the iteration) does not need to mantain such information for multiple iterators. it only needs to receive the relevant information from the Iterator who's currently acting on the aggregate. the iterator updates its own memory from the aggregate on each operation, as the following pseudocode shows (hope it's clear :-): reset { AGGREGATE->iterator_reset() ITERATOR->data = AGGREGATE->iterator_get() } next { AGGREGATE->iterator_set(ITERATOR->data) AGGREGATE->iterator_next() ITERATOR->data = AGGREGATE->iterator_get() } get_current { AGGREGATE->iterator_set(ITERATOR->data) return AGGREGATE->iterator_get_current } this accomplishes point 2. and shows why Iterator needs to be a class of its own. the implementation could surely be improved, and it certainly need to(*), but I hope the design does make some sense :-) (*) just to make an example, this approach is absolutely not thread-safe. cheers, Aldo __END__ $_=q,just perl,,s, , another ,,s,$, hacker,,print;