|
7 | 7 | [](http://codecov.io/github/davidanthoff/IteratorTraits.jl?branch=master) |
8 | 8 |
|
9 | 9 | IteratorTraits defines a small number of traits for iterators. |
| 10 | + |
| 11 | +## Overview |
| 12 | + |
| 13 | +This package adds a couple of extensions to the standard [iterator interface](https://docs.julialang.org/en/latest/manual/interfaces/#man-interface-iteration-1) |
| 14 | +in julia. |
| 15 | + |
| 16 | +### ``isiterable`` and ``getiterator`` |
| 17 | + |
| 18 | +The first extension is comprised of the functions ``isiterable`` and |
| 19 | +``getiterator``. ``isiterable(x)`` will return ``true`` or ``false, |
| 20 | +indicating whether ``x`` can be iterated. It is important to note that |
| 21 | +a ``true`` return value does *not* indicate that one can call the |
| 22 | +``start`` method on ``x``, instead a consumer *must* call ``getiterator(x)`` |
| 23 | +if ``isiterable(x)`` returned true, and can then call ``start`` on the |
| 24 | +instance that is returned by ``getiterator``. The proper pattern to |
| 25 | +consumer code therefore looks like this: |
| 26 | +````julia |
| 27 | +if isiterable(x) |
| 28 | + it = getiterator(x) |
| 29 | + for i in it |
| 30 | + # Custom code |
| 31 | + end |
| 32 | +end |
| 33 | +```` |
| 34 | +This consumer pattern will work with iterators that don't opt into the |
| 35 | +extensions in this package here and with iterators that have opted into |
| 36 | +the extended interface defined in this package. |
| 37 | + |
| 38 | +There are two scenarios when a source might participate in this extended |
| 39 | +iterator interface. |
| 40 | + |
| 41 | +The first scenario is one where a source could not |
| 42 | +implement a type-stable version of ``start``, ``next`` and ``done`` because |
| 43 | +the primary source type lacks the necessary type information. Such a |
| 44 | +source can add a method to ``getiterator`` that returns an instance |
| 45 | +of a different type with enough type information for a type stable |
| 46 | +implementation of the core iterator interface that iterates the elements |
| 47 | +of the original source. |
| 48 | + |
| 49 | +Sometimes such a source might not want to implement the ``start``, ``next`` |
| 50 | +and ``done`` method at all for its core type. If that is the case, this |
| 51 | +source can add a method to ``isiterable`` that returns ``true``, even |
| 52 | +though the source does not have a ``start`` method. As long as this source |
| 53 | +still implements the ``getiterator`` function, it still complies with the |
| 54 | +extended iterator contract defined in this package. |
| 55 | + |
| 56 | +### ``iteratorsize2`` |
| 57 | + |
| 58 | +``iteratorsize2`` extends ``Base.iteratorsize`` with an additional return |
| 59 | +value, namely ``HasLengthAfterStart()``. An iterator consumer that can |
| 60 | +provide an optimized implementation for iterators that know their length |
| 61 | +after the ``start`` method has been called, can call ``iteratorsize2`` |
| 62 | +instead of ``Base.iteratorsize``. The return value will either be one of |
| 63 | +the possible return values of ``Base.iteratorsize``, or |
| 64 | +``HasLengthAfterStart()``. If the return value is ``HasLengthAfterStart()``, |
| 65 | +the consumer can call ``length(x, state)`` to obtain the number of |
| 66 | +elements the iterator will return. Here ``x`` is the same value that |
| 67 | +``start`` was called on, and ``state`` is the value returned by |
| 68 | +``start(x)``. |
| 69 | + |
| 70 | +An iterator that implements ``iteratorsize2(x::MyType) = HasLengthAfterStart()`` |
| 71 | +must also implement ``Base.iteratorsize(x::MyType) = Base.SizeUnknown()``. |
0 commit comments