C++ iterators are objects, distinct from the things being operated upon
Anything you want to ask for on the iterator would be done with a dot access, like a normal member
Anything you want to do with the current element you do through a dereference step * or an arrow which folds the dereference and dot access together ->
Like this:
iterator.act_on_iterator() // use dot to call method on iterator itself
Item item = *iterator; // use dereference to get at current item
String s1 = (*iterator).full // one way to extract property of current item
String s2 = iterator->full // alternative syntax convenience for arrow
iterator->delete_file(); // arrow can also call methods on current object
for (Item i : iterator) { ... } // modern C++ has range-based for loops
Standardized Methods
C++ iterators don't inherit from any common object, so they can have as much or as little data in them as you want. And they can have any custom method you like. They are just objects.
What makes an iterator an iterator is how they react to standard operators. They use increment (operator++) and decrement (operator--) to traverse forwards and backwards (not all can go backwards), and have a method for .begin() and .end() to tell you where the start and end are (plus .rbegin() and .rend() were later standardized for traversing in reverse, and .cbegin() and cend() for const traversals for data that can be either const or mutable... and .crbegin() and crend())
Here's some other required operators:
Equality/Inequality Comparison (operator==, operator!=): Required for Input, Output, Forward, Bidirectional, and Random Access Iterators.
Member Access (operator->): Required for Input, Forward, Bidirectional, and Random Access Iterators.
Random Access Operations (for Random Access Iterators only):
One fundamental difference between C++ iterators and @rgchris's iterators is that C++ iterator instances are very light... and you're expected to be able to copy them freely (at least, the ones that iterate over standard library collections).
For instance: an array iterator is as cheap as a pointer or index. If you want to you can store iterator positions at various points in the iteration, and use them as spans (to say "I want to copy from this iterator, to that iterator")
This would be kind of like storing a new BLOCK! position as pos: next block when compared with block-iter/next that mutably changes the internal state of a "heavyweight" block iterator.
But C++ also has the ability to modify iterators in place, without creating a new one. So it can do either, and optimize the in-place case.
Ren-C has ME and MY which means that there'd be a short syntax for if you wanted to advance an iterator that only supported "make a new copy" semantics via NEXT:
some-iterator: my next ; short macro for `some-iterator: next some-iterator`
But this might not be efficient, so one might want to call the method (as C++ does) ADVANCE
iter/advance
And then NEXT could simply be a synonym for (copy iter)/advance
Then iterators could be copyable or non-copyable. If they were not copyable you'd have to use ADVANCE, and if they were you'd have the option of NEXT.
UPDATE: Another possibly-more-interesting idea is to allow NEXT to take a variable, so next $iter..which would be a light syntax that doesn't invent more words. However, this still suggests that the variable-taking form would be the "more fundamental" version, so I'm not sure how that would all sift out in terms of making the easy version to write to be the non-copying form and get the rest for free...maybe you still would do that by writing ADVANCE.
While I accept that my iterators are currently tricky to copy (an aspect that I'd posit could be easily rectified), I'd contest the claim that their instances are not light. They do not carry copies of the operating logic—effectively just 'pointers' to NEXT or other functions. Rather they contain the information required to maintain and reflect state (possibly more than is needed regarding the latter, but that is in most cases is a feature anticipating further needs*). Indeed, it wouldn't take much effort at hacking at this state to subvert each instance for whatever ends. If patterns emerged from such efforts, I'd certainly not object to codifying them—I'm very much pro- that; it's one reason I am pushing this concept in a primitive state, to stimulate innovation.
Perhaps I misunderstand your meaning, that it's the essence of storing two different 'views' of a Rebol series that is 'heavy' vs. the way that C++ does things. If view-1: [a b c] view-2: next view-1 is 'heavy,' then yeah, I concede the point.
* For example, the FOLDERS iterator containing metadata for path, full path, and filename, anticipating the various needs of such an iterator.
Well by comparison, any Rebol OBJECT! is fairly "large"... even if it just holds only pointers to the functions from an archetypal object.
(C++ programs are compiled and so the functions live "in the ether" and unless they are virtual, cost no more than a "free function", as they know what data they operate on.)
However...my point was more about the working model of iter/advance vs. iter: next iter and what that difference means.
C++ has codified the iterator idea in a way that iter/(mutably-)advance and iter/(mutably-)regress are the foundational operations (++iter, --iter).
So the non-mutating versions are built on top of that: you copy the iterator, then increment or decrement it. And then depending on the kind of iterator you have maybe you offer other optimized operations, like random access or being able to skip N items vs. having to ++iter N times.
(The optimized versions being correct is your responsibility as an iterator author. e.g. by contract, if you implement (iter += N) then it is expected to give the same result as applying ++iter N times, but this is the job of the iterator author to ensure, C++ can't enforce the guarantee for you.)
Language builtin range-based for in C++ can exploit the fact that you don't need anything other than one, mutable, iterator. We could do the same with our FOR-EACH etc (e.g. it would be silly to use iter: next iter (or iter: my next) when FOR-EACH could just mutate the one iterator with /ADVANCE). But offer the other freedoms that being able to copy iterators gives.
Were we to follow this pattern, then iteration would be defined generally by a mutating operation (as you did, though you called it /NEXT, I am suggesting /ADVANCE to help distinguish from existing Rebol lore which doesn't think of NEXT as a mutating operation). But then non-mutating versions would come "for free" based on a COPY and then applying the mutating operation to the copy.
That would, I assume, be a cost of doing business in Rebol. Even so, only one object exists for the lifetime of an iterator—the greatest cost occurs at initiation.
This seems reasonable. I've used ADVANCE elsewhere with similar connotations.
I'm a little confused by the different idioms between NEXT and ADVANCE here—is this deliberate, iter/advance vs. advance iter?
I do like the sound of this, and is something I could do as an iterator author now in my current system were I to add ITERATE/COPY to imply something of a standard (limited as that is idiomatically—for me ITERATE/ANY-OP is a placeholder for something that could be done better were ITERATOR! to exist)
>> block: [a b c]
== [a b c]
>> next block
== [b c]
>> block
== [a b c]
And then, to have some "next" concept that is intrinsically mutating. I guess whether it is seen as incongruous is in some sense arbitrary: perhaps iter/next is mutating, but next iter runs by different rules as (copy iter)/next and that's "just the way it is"... the system can do this. Cognitively I think it's probably better to choose another word, and C++ does, so I'd propose perhaps following suit
So I was proposing that the mutating concept have a different name.
But really, don't think there's anything too much else to say on it... I am looking into if @iter being a dereferencing operator works, and if it does I think that's actually reasonably semiotic.
Main question I'm having is if @iter acting as get iter and @iter: X acting as set iter X is some kind of universally healthy concept. Should it apply to WORD!, too?