Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1937 string iterator suffix #1938

Merged
merged 2 commits into from
Jan 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 47 additions & 8 deletions doc/source/structures/collections/iterator.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
Iterator
========

An iterator can be obtained from :attr:`List:ITERATOR`. Once a :struct:`List` has given you an :struct:`Iterator` object, you can use it to access elements inside the :struct:`List`. An ITERATOR is a `generic computer programming concept <http://en.wikipedia.org/wiki/Iterator>`__. In the general case it's a variable type that allows you to get the value at a position in some collection, as well as increment to the next item in the collection in order to operate on all objects in the collection one at a time. In kOS it operates on :struct:`Lists <List>`.
An iterator can be obtained from :attr:`List:ITERATOR` as well as from other places.
An ITERATOR is a
`generic computer programming concept <http://en.wikipedia.org/wiki/Iterator>`__.
In the general case it's a variable type that allows you to get
the value at a position in some collection, as well as increment
to the next item in the collection in order to operate on all
objects in the collection one at a time. In kOS it operates
on :struct:`Lists <List>` and most other collection types.

A loop using an :struct:`Iterator` on a :struct:`List` might look like this::

Expand All @@ -12,8 +19,7 @@ A loop using an :struct:`Iterator` on a :struct:`List` might look like this::

// It could be looped over like this
SET MyCurrent TO MyList:ITERATOR.
MyCurrent:RESET().
PRINT "After reset, position = " + MyCurrent:INDEX.
PRINT "before the first NEXT, position = " + MyCurrent:INDEX.
UNTIL NOT MyCurrent:NEXT {
PRINT "Item at position " + MyIter:INDEX + " is [" + MyIter:VALUE + "].".
}
Expand All @@ -22,11 +28,31 @@ A loop using an :struct:`Iterator` on a :struct:`List` might look like this::

Which would result in this output::

After reset, position = -1.
before the first NEXT, position = -1.
Item at position 0 is [Hello].
Item at position 1 is [Aloha].
Item at position 2 is [Bonjour].

When you first create an iterator by using an ITERATOR suffix of some collection
type like :struct:`List`, :struct:`List`, or even :struct:`String`, the
initial position of the index is always -1, and the current value is always
invalid. This represents a position just *before the start* of the list of
items. Only after the first time :attr:`NEXT` is called does the value of
:attr:`VALUE` become usable as the first thing in the collection.

Rewinding No Longer Supported
-----------------------------

.. note::

There used to be a :RESET method for iterators, but it has been
removed as it was not always implemented and sometimes gave an
error. Now to start the enumeration over you need to obtain a
new iterator.

Members
-------

.. highlight:: kerboscript

.. structure:: Iterator
Expand All @@ -41,8 +67,8 @@ Which would result in this output::


* - :meth:`RESET`
-
- Rewind to the just before the beginning
- n/a
- (This method has been removed)
* - :meth:`NEXT`
- :ref:`boolean <boolean>`
- Move iterator to the next item
Expand All @@ -59,7 +85,20 @@ Which would result in this output::

.. method:: Iterator:RESET

Call this to rewind the iterator to just before the beginning of the list. After a call to :meth:`Iterator:RESET`, the iterator must be moved with :meth:`Iterator:NEXT` before it gets to the first value in the list.
:returns: n/a

This suffix has been deleted from kOS.

.. note::

Previous versions of kOS had a ``:RESET`` suffix for Iterators. This doesn't
exist anymore and is being left in the documentation here just so people trying
to search for it will find this message explaining where it went. kOS had to
drop it because it's no longer as easy to implement it under the hood with
newer versions of .Net.

(If you want to restart an iteration you must call the ``:ITERATOR`` suffix of
the collection again to obtain a new iterator.)

.. method:: Iterator:NEXT

Expand All @@ -83,7 +122,7 @@ Which would result in this output::

.. note::

If you have just used :meth:`Iterator:RESET` or have just created the ITERATOR, then the value of :attr:`Iterator:INDEX` is -1. It only becomes 0 after the first call to :meth:`Iterator:NEXT`.
If you have just created the ITERATOR, then the value of :attr:`Iterator:INDEX` is -1. It only becomes 0 after the first call to :meth:`Iterator:NEXT`.

.. attribute:: Iterator:VALUE

Expand Down
63 changes: 60 additions & 3 deletions doc/source/structures/misc/string.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,56 @@ of existing strings. For example::
SET s TO "Hello, Strings!".
SET t TO s:REPLACE("Hello", "Goodbye").

Strings are iterable. This scripts prints the string's characters one per line::
ACCESSING INDIVIDUAL CHARACTERS
-------------------------------

There's two main ways to access the individual characters
of a string - using an iterator or using index numbers:

Using an Iterator (FOR)
~~~~~~~~~~~~~~~~~~~~~~~

Strings can be treated a little bit like iterable lists
of characters. This allows them to be used in FOR loops
as in the example below:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to add a : for the code example to work. I'll handle it in my review edits.


SET str TO "abcde".
LOCAL str is "abcde".

FOR c IN str {
PRINT c.
PRINT c. // prints "a" the first time, then "b", etc.
}

The reason you can use Strings with the FOR loop like this is
because you can obatain an :struct:`Iterator` of a string with the
:attr:`ITERATOR` suffix mentioned below. (Any type that
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because I'll be pointing to Enumerator below, I'll edit this to match.

implements the ITERATOR suffix can do this.)

Using an Index ( [i] )
~~~~~~~~~~~~~~~~~~~~~~

Strings can also be treated a little bit like lists in that
they allow you to use the square-brackets operator `[`..`]`
to choose one character by its index number (numbers start
counting at zero). Here's an example that does the same thing
as the FOR loop above, but using index notation::

LOCAL str is "abcde".
local index is 0.
until index = str:LENGTH {
print str[index].
set index to index + 1.
}

Be aware that despite being able to read the characters this way,
you cannot set them this way. The following will give
an error::

LOCAL str is "abcde".

// The following line gives an error because you can't
// change the characters inside a string:
set str[0] to "X".

Boolean Operators
-----------------

Expand Down Expand Up @@ -127,6 +169,9 @@ Structure
* - :meth:`INSERT(index, string)`
- :struct:`String`
- Returns a new string with the given string inserted at the given index into this string
* - :attr:`ITERATOR`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all of our other structures, we don't duplicate suffixes from inherited structure types. But this table doesn't direct the user to go look for Enumerator. I think I will add that reference and delete the ITERATOR documentation in this file if that's OK with you. It also fixes an error since Sphinx is complaining that it's defined twice.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does string inherit from Enumerator?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh hey, you're right. It is literally just an iterator suffix, not the rest of the enumerator stuff... I take it all back. I'll just remove the enumerator portion of that attribute definition below instead. Ignore my craziness.

- :struct:`Iterator`
- generates an iterator object the elements
* - :meth:`LASTINDEXOF(string)`
- :struct:`Scalar`
- Alias for FINDLAST(string)
Expand Down Expand Up @@ -233,6 +278,18 @@ Structure

Returns a new string with the given string inserted at the given index into this string

.. attribute:: Enumerable:ITERATOR

:type: :struct:`Iterator`
:access: Get only

An alternate means of iterating over a string's characters
(See: :struct:`Iterator`).

For most programs you won't have to use this directly. It's just
what enables you to use a string with a FOR loop to get access
to its characters one at a time.

.. method:: String:LASTINDEXOF(string)

Alias for FINDLAST(string)
Expand Down
6 changes: 0 additions & 6 deletions src/kOS.Safe/Encapsulation/Enumerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ public Enumerator(IEnumerator enumerator)

private void EnumeratorInitializeSuffixes()
{
AddSuffix("RESET", new NoArgsVoidSuffix(() =>
{
index = -1;
status = false;
enumerator.Reset();
}));
AddSuffix("NEXT", new NoArgsSuffix<BooleanValue>(() =>
{
status = enumerator.MoveNext();
Expand Down
2 changes: 1 addition & 1 deletion src/kOS.Safe/Encapsulation/StringValue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ private void StringInitializeSuffixes()
// Aliased "IndexOf" with "Find" to match "FindAt" (since IndexOfAt doesn't make sense, but I wanted to stick with common/C# names when possible)
AddSuffix(new[] { "INDEXOF", "FIND" }, new OneArgsSuffix<ScalarValue, StringValue> ( one => IndexOf(one)));
AddSuffix(new[] { "LASTINDEXOF", "FINDLAST" }, new OneArgsSuffix<ScalarValue, StringValue> ( s => LastIndexOf(s)));

AddSuffix ("ITERATOR", new NoArgsSuffix<Enumerator>( () => new Enumerator(GetEnumerator()) ));
}

public static bool operator ==(StringValue val1, StringValue val2)
Expand Down