Just for more data points (not proposing anything), perhaps look at how C++ 
handles iterables I'll only be referencing the immutable iterator types or 
the types that can be immutable based on their contained types, I'll also 
be using the C++ names for them rather than the more traditional 
OCaml'y/Haskell'y or so names as C++'s is more expressive due to having 
more 'types':

* Iterator:  This defines something is an iterator, however it has no way 
to actually iterate it, it is only a marker trait that says that something 
is some type of iterator

* InputIterator:  This is something that you can 'get' something out of, 
then 'next' to the next element until it 'ends' (or does not end, it could 
be infinite).  You cannot go back over an iteration, it is consume-once 
thus it is read-once, and you cannot write an element, even of the slot 
that you are in.  The only real Elixir/Erlang 'InputIterator' that I can 
think of off the top of my mind is the process mailbox.

* OutputIterator:  This is something that you can 'put' something in to, 
then next to the next 'slot' to put something in to it as well.  You cannot 
read from an element even of the slot that you are currently in nor can you 
write to an element multiple times, only once.  The only real Elixir/Erlang 
'OutputIterator' that I can think of is sending a message to a process.

* ForwardIterator:  Every ForwardIterator is also an InputIterator and/or 
an OutputIterator (depending on its contained types), you can get/put and 
next, however unlike InputIterator/OutputIterator you can read/write 
from/to a slot multiple times and you can also hold a cursor to a given 
slot to read/write from/to it again even after you have 'next'/iterated 
past it.  You cannot iterate backwards from a given slot, only forwards. 
 This would be like iterating through a list in Elixir/Erlang.

* BidirectionalIterator:  Every BidirectionalIterator is also a 
ForwardIterator, except you can also go backwards from a slot.  In 
Elixir/Erlang this would be like a zipper structure.

* RandomAccessIterator:  Every RandomAccessIterator is also a 
BidirectionalIterator except that you can jump to any slot in *constant* 
time via an index.  An Elixir equivalent would be like accessing a tuple.



C++ also has traits that define if something is a type of container, these 
are:

* Container:  The base Container trait (do note, these are not C++ classes, 
they are 'traits', if something implements the required functions for their 
type then they are considered to fulfill a given 'trait', there is no 
inheritence or anything of the sort).  This defines something that 
'manages' something else.  It has a way to acquire a ForwardIterator (or 
anything else that implements a ForwardIterator, such as a 
Bidirectionaliterator).  This is like an Elixir list or a map or really 
anything that holds something.

* ReversibleContainer: A ReversibleContainer must also be a Container.  It 
adds the constraints that acquiring an iterator must return an iterator 
that fulfills a Bidirectionaliterator in capability.  It also adds the 
constraint that it must be possible to get an iterator that iterates over 
the elements in reverse order.  This is like an Elixir zipper.

* AllocatorAwareContainer:  An AllocatorAwareContainer must also be a 
Container.  It is a container that creates it's own elements via a (either 
passed in or internal) allocator function instead of the user supplying the 
element.  This is like an Elixir Stream.

* SequenceContainer:  A SequenceContainer must also be a Container.  It 
adds the constraints that the returned iterator must be in a linear 
arrangement, such as getting different iterators on the same container must 
always result in the same order and in constant iteration time (thus that 
'next' is constant time).  This is like iterating over an Elixir List but 
not a map.

* ContiguousContainer:  A ContiguousContainer must also be a Container.  It 
adds the constraint that the returned iterator must be of type 
RandomAccessIterator, thus allowing for constant time element access.  This 
is like an Elixir tuple.


A given iterator can fulfill multiple even disjoint iterator traits, like 
being both an input and an output iterator (in Elixir this would be like a 
File access interface).

A given container can fulfill multiple container traits, like being both a 
SequenceContainer and a ContiguousContainer, which in Elixir would be a 
tuple since it fulfills both requirements.


Just putting it out there that there are a lot of different kinds of 
Sequences, and even in C++ you cannot know if an iterator (or even a 
container) is not 'infinite'.  Like take stdin/stdout in C++, those are 
InputIterator and OutputIterator respectively, yet you do not know if 
either 'end' until you next() on them and test (and 'next()ing' on the 
stdin InputIterator may 'wait' in time until more input comes in for 
example, and writing to an OutputIterator of stdout may 'wait' in time if 
the buffer is full and the receiving pipe has not processed the buffered 
data yet, which can also happen when sending/receiving message on the BEAM 
as well).



On Monday, July 24, 2017 at 4:37:41 PM UTC-6, [email protected] wrote:
>
> This is a good point. I was looking for an example of how these protocol 
> changes could allow us to make some enumerables not allow negative access. 
> No existing thing in the language is a good example, though, because we 
> would break current behaviour.
>
> It does present the interesting option of adding an `infinite` boolean 
> field, defaulting to false, to the Stream struct and having the 
> exhaustiblity protocol function check that. Then stream constructors that 
> are known to generate infinities like Stream.cycle could opt-in to erroring 
> on negative access. Stream modifiers known to 'curb' the infinities could 
> reset it to true. Ambiguous operations would leave it unmodified.
>
> My exhaustible impl attempt will come well after my take on 
> Enumerable.fetch, so I'm not really thinking very hard about this yet––just 
> spitballing. But definitely the intention is not to have exhaustible? do 
> any work, merely allow Enumerable implementers outside of core to opt-out 
> of negative integer access if they wish.
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/b9ab9bb6-1edc-40d8-961a-7207944c4926%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to