The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Iterator::Flex::Manual::Overview - An Abstract overview of Iterators

VERSION

version 0.18

DESCRIPTION

Iterator life-cycle

There are four iterator states:

  1. initialized

  2. iteration

  3. exhausted

  4. error

An iterator typically moves sequentially from initialized to iteration to exhausted.

Non-sequential transitions may occur from non-error states when

Attempts to transition from an error state to another state result in undefined behavior.

Initialized State

An iterator is in the initialized state immediately after it has been constructed, or if it has been reset.

In the initialized state,

  • "next" will attempt to retrieve the first element from the data stream.

    • If the data stream is empty, the iterator transitions to the "Exhausted State" and signals exhaustion.

    • If there was an error the iterator transitions to the "Error State" and signals error.

    • otherwise, the iterator transitions to the "Iteration State" and the element is returned.

  • "prev" and "current" (if they are supported) return an indeterminate value.

Iteration State

An iterator is in the iteration state if the last call to "next" successfully returned data.

In the iteration state,

  • "next" will attempt to retrieve the next element from the data stream.

    • If the data stream is empty, the iterator transitions to the "Exhausted State" and signals exhaustion.

    • If there was an error, the iterator transitions to the "Error State" and signals error.

    • otherwise, the element is returned.

  • "prev" returns

    • an indeterminate value If the previous call to "next" transitioned the iterator from the "Initialized State"

    • otherwise, the value returned by the penultimate successful call to "next".

  • "current" returns the value returned by the last successful call to "next".

Exhausted State

An iterator enters the exhausted state after a call to "next" when the iterator determines that there are no more data to retrieve.

In this state,

  • "prev" returns

    • an indeterminate value if the last "next" call transitioned the iterator from the "Initialized State";

    • otherwise, the value returned by the penultimate successful call to "next".

  • "current" returns an indeterminate value.

For example, if the data are 1, 2, 3, the following expressions, executed in order, are all true.

     1   $iter->prev    == ?;  # indeterminate; in initialized state
     2   $iter->current == ?;  # indeterminate; in initialized state
     3
     4   $iter->next    == 1;  # in iteration state
     5   $iter->prev    == ?;  # indeterminate
     6   $iter->current == 1;
     7
     8   $iter->next    == 2;
     9   $iter->prev    == 1;  # from line 4
    10   $iter->current == 2;
    11
    12   $iter->next    == 3;
    13   $iter->prev    == 2;
    14   $iter->current == 3;
    15
    16   $iter->next;          # signals exhaustion;
    17
    18   $iter->is_exhausted == 1;
    19
    20   $iter->prev    == 3;
    21   $iter->current == ?;  # indeterminate
    22   $iter->next;          # still signals exhaustion;

Error State

An iterator transitions to the error state when the iterator has determined that something went wrong.

Signaling State Transitions

The iterator signals transitions to the exhausted and error states.

Transitions to the Exhausted State

Signaling exhaustion (via the signal_exhaustion method) results in one of following actions:

  • throwing an exception of type Iterator::Flex::Failure::Exhausted; or

  • returning a sentinel value

The choice is made by the user of the iterator; iterators use a generic signaling mechanism.

Transitions to the Error State

Signaling error (via the signal_error method) results in one of following actions:

  • Throwing an exception of type Iterator::Flex::Failure::Error.

Capabilities

Iterators are capable of performing at least one task, namely retrieving the next datum in the data stream, but may be capable of others as well. These capabilities are invoked as methods with the name of the capability, e.g. $iter->next, $iter->prev, etc.

Required Capabilities

next

  # these are equivalent
  $value = $iter->next;
  $value = $iter->();

This provides the ability to return the next element from the iterator. During the first call to "next" the iterator transitions from the initialized state to another (iteration, exhausted or error).

If it has made it to the iteration state, it returns a valid value, otherwise, it signals either exhaustion or error.

Invoking next will either result in a valid value, or, if the iterator is exhausted, an indication of exhaustion, which may either be

  • A sentinel value, indicated by the Iterator::Flex::Role::Exhaustion::Return role.

  • An exception, indicated by the Iterator::Flex::Role::Exhaustion::Throw role.

Optional Capabilities

prev

  $value = $iter->prev;

If the iterator is in the iteration state, it returns the value returned by the penultimate "next" operation. If the last "next" operation transitioned the iterator from the initialized state, it returns an indeterminate value.

In any other state, it returns an indeterminate value.

current

  $value = $iter->current;

If the iterator is in the iteration state, returns the value returned by the last "next" operation.

In any other state, it returns an indeterminate value.

rewind

  $iter->rewind;

If the iterator is in the iteration state, ensures that the next "next" operation will retrieve the first element from the data stream.

Rewinding maintains the correctness of the "prev" and "current" capabilities, enabling cyclic iterators.

For example, if the data are 1, 2, 3, the following expressions, executed in order, are all true.

     1   $iter->prev    == ?;  # indeterminate; in initialized state
     2   $iter->current == ?;  # indeterminate; in initialized state
     3
     4   $iter->next    == 1;  # in iteration state
     5   $iter->prev    == ?;  # indeterminate
     6   $iter->current == 1;
     7
     8   $iter->next    == 2;
     9   $iter->prev    == 1;  # from line 4
    10   $iter->current == 2;
    11
    12   $iter->rewind;
    13
    14   $iter->prev    == 1;  # no change
    15   $iter->current == 2;  # no change
    16
    17   $iter->next    == 1;  # start all over
    18   $iter->current == 1;
    19   $iter->prev    == 2;  # from line 8
    20
    21   $iter->next    == 2;
    22   $iter->current == 2;
    23   $iter->prev    == 1;  # from line 17

reset

  $iter->reset;

Transitions the iterator to the initialized state.

For example, if the data are 1, 2, 3, the following expressions, executed in order, are all true.

     1   $iter->prev    == ?;  # indeterminate; in initialized state
     2   $iter->current == ?;  # indeterminate; in initialized state
     3
     4   $iter->next    == 1;  # in iteration state
     5   $iter->prev    == ?;  # indeterminate
     6   $iter->current == 1;
     7
     8   $iter->next    == 2;
     9   $iter->prev    == 1;  # from line 4
    10   $iter->current == 2;
    11
    12   $iter->reset;
    14
    15   $iter->prev    == ?;  # indeterminate; in initialized state
    16   $iter->current == ?;  # indeterminate; in initialized state
    17
    18   $iter->next    == 1;  # in iteration state
    19   $iter->prev    == ?;  # indeterminate
    20   $iter->current == 1;
    21
    22   $iter->next    == 2;
    23   $iter->prev    == 1;  # from line 18
    24   $iter->current == 2;
    25

freeze

  $state = $iter->freeze;
  $iter = ithaw( $state );

freeze serializes the state of the iterator and the data stream so that the state can be saved and later restored. This puts significant constraints on the nature of the data source.

ithaw is a subroutine (not a method) which is the opposite of "freeze". Given a serialized iterator, it reconstitute it so that it behaves exactly as it would before it was frozen. Under the hood it calls the thaw method.

Generator Parameters

Parameters are passed to iterator and attribute generators, either through the convenience functions in Iterator::Flex::Common, the constructors in Iterator::Flex::Factory or the constructors in bespoke iterator classes which subclass Iterator::Flex::Base.

Classes of Parameters

There are several classes of parameters used by iterators and adapters:

  • Model parameters are specific to a type of iterator. For example, the cache iterator has a model parameter for the cache capacity.

  • Interface parameters provide implementations of the capabilities that the iterator provides.

  • Exhaustion parameters define how the iterator signals exhaustion.

  • Error parameters define how the iterator signals error.

Exhaustion, Error, and Interface parameters are also called General Parameters.

Interface Parameters

_self

A reference to a lexical variable which will be set by the iterator generator to a reference to the iterator object. This is used only if the iterator class consumes the Iterator::Flex::Role::Next::ClosedSelf role.

_name

The name of the iterator to be used in error messages. If not specified, it is set to the iterator class.

state

A reference to a lexical variable which will reflect whether the state is one of exhaustion, error, or something else. This is used if the iterator class consumes the Iterator::Flex::Role::State::Closure role. (The alternative is for the state to be stored in the iterator registry by consuming the Iterator::Flex::Role::State::Registry role).

Using this functionality the state stored in the lexical variable can be accessed directly from iterator closures and compared to one of the constants IterState_EXHAUSTED or IterState_ERROR (see "Iterator State Constants" in Iterator::Flex::Utils).

The state is also queryable via the is_exhausted and is_error iterator object methods.

class

The class which will consume iterator roles and from which the object will be instantiated. This option is only used by Iterator::Flex::Factory generators. It defaults to Iterator::Flex::Base.

next

A code reference which returns the next element in the data source. This will be made available as the object method next, but may also be invoked directly as a subroutine (e.g. $next->()).

Access to the iterator object can be obtained by either:

prev

A code reference which returns the value retrieved by the penultimate call to "next". This will be made available as the object method prev.

This is used only if the iterator class consumes the Iterator::Flex::Role::Prev::Closure role.

Classes constructed via the Iterator::Flex::Factory constructors will automatically be composed with the Iterator::Flex::Role::Prev::Method if the "prev" parameter is not specified and the class specified by the "class" parameter provides a prev object method.

Bespoke classes should apply the Iterator::Flex::Role::Prev::Method role using the "_add_roles" in Iterator::Flex::Base class method.

current

A code reference which returns the value retrieved by the last call to "next". This will be made available as the object method current.

This is used only if the iterator class consumes the Iterator::Flex::Role::Current::Closure role.

Classes constructed via the Iterator::Flex::Factory constructors will automatically be composed with the Iterator::Flex::Role::Current::Method if the "prev" parameter is not specified and the class specified by the "class" parameter provides a prev object method.

Bespoke classes should apply the Iterator::Flex::Role::Current::Method role using the "_add_roles" in Iterator::Flex::Base class method.

reset

A code reference which will restore the iterator to the initialized state.

This is used only if the iterator class consumes the Iterator::Flex::Role::Reset::Closure role.

Classes constructed via the Iterator::Flex::Factory constructors will automatically be composed with the Iterator::Flex::Role::Reset::Method if the "prev" parameter is not specified and the class specified by the "class" parameter provides a prev object method.

Bespoke classes should apply the Iterator::Flex::Role::Reset::Method role using the "_add_roles" in Iterator::Flex::Base class method.

The state variable (accessible via the is_exhausted and is_error iterator object methods) will automatically be reset.

If the iterator is an adapter depending upon other iterators, they will automatically be reset.

rewind

A code reference which will ensure that the next call to "next" returns the first element in the data stream.

This is used only if the iterator class consumes the Iterator::Flex::Role::Rewind::Closure role.

Classes constructed via the Iterator::Flex::Factory constructors will automatically be composed with the Iterator::Flex::Role::Rewind::Method if the "prev" parameter is not specified and the class specified by the "class" parameter provides a prev object method.

Bespoke classes should apply the Iterator::Flex::Role::Rewind::Method role using the "_add_roles" in Iterator::Flex::Base class method.

If the iterator is an adapter depending upon other iterators, they will automatically be rewound.

freeze

A code reference which returns a serialized version of the iterator. See Iterator::Flex::Manual::Serialization and "Serialization" in Iterator::Flex::Manual::Caveats.

methods

A hash whose keys are method names and whose values are coderefs. These will be added as methods to the iterator class. Useful for making a set of closures available as methods.

_depends

A list of iterator objects that the adapter depends upon. Used by iterator adapters. Automatically added by Iterator::Flex::Factory constructors. Bespoke classes must provide this explicitly.

Exhaustion

There are two parameters that specify how exhaustion is signalled:

input_exhaustion

This applies only to iterator adapters, and indicates how the consumed iterator signals exhaustion. It can take the following values:

throw

The consumed iterator throws an indeterminate exception on exhaustion.

[ throw => $class ]

The consumed iterator throws an exception upon exhaustion in the given class on exhaustion.

[ throw => \@classes ]

The consumed iterator throws an exception upon exhaustion in one of the given classes on exhaustion.

[ throw => $regexp ]

The consumed iterator throws an exception upon exhaustion which when stringified matches the passed regular expression.

[ throw => $coderef ]

The consumed iterator throws an exception; $coderef->( $e ) returns true if the exception indicates exhaustion.

return

The consumed iterator returns a sentinel value of undef on exhaustion.

[ return => $value ]

The consumed iterator returns a sentinel value of $value on exhaustion.

exhaustion

This applies to both iterators and adapters, and indicates how they signal exhaustion. It can take the following values:

[ throw => 'passthrough' ]

Only for adapters where the consumed iterator will throw on exhaustion; this lets that exception propagate.

throw

Throw an exception of Iterator::Flex::Failure::Exhaustion.

[ throw => $coderef ]

Invoke $coderef. If it does not throw, an exception of Iterator::Flex::Failure::Exhaustion. will be thrown.

return

For both iterators and adapters, indicates that a sentinel value of undef will be returned.

[ return => $value ]

For both iterators and adapters, indicates that the specified sentinel value will be returned.

Error

error

This applies to both iterators and adapters, and indicates how they signal error. It may have one of the following values:

throw

Throw an exception of Iterator::Flex::Failure::Error.

[ throw => $coderef ]

Invoke $coderef. If it does not throw, an exception of Iterator::Flex::Failure::Error. will be thrown.

INTERNALS

SUPPORT

Bugs

Please report any bugs or feature requests to bug-iterator-flex@rt.cpan.org or through the web interface at: https://rt.cpan.org/Public/Dist/Display.html?Name=Iterator-Flex

Source

Source is available at

  https://gitlab.com/djerius/iterator-flex

and may be cloned from

  https://gitlab.com/djerius/iterator-flex.git

SEE ALSO

Please see those modules/websites for more information related to this module.

AUTHOR

Diab Jerius <djerius@cpan.org>

COPYRIGHT AND LICENSE

This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory.

This is free software, licensed under:

  The GNU General Public License, Version 3, June 2007