Custom iterable intervals using sequenceable items
The following example demonstrates creating
a custom iterable interval using sequenceable items. A sequenceable item is a type that implements
the ISequenceable Gosu
interface, which defines how to get the next and previous items in a
sequence. If the item you want to iterate across implements that interface,
you can use the SequenceableInterval
Gosu class and you do not need to create your own interval class. Suppose
you want to create a new iterable interval that can iterate across a
list of predefined and ordered color names with a starting and ending
color value. Define an enumeration containing the possible color values
in their interval:
package example.pl.gosu.interval
enum Color {
Red, Orange, Yellow, Green, Blue, Indigo, Violet
}
All Gosu enumerations automatically implement the
java.lang.Comparable interface,
which is a requirement for intervals. However, Gosu enumerations do not
automatically implement the ISequenceable
interface.
To determine an iterable interval dynamically, Gosu requires that a comparable endpoint also be sequenceable. To be sequenceable means that a class knows how to find the next and previous items in the sequence. Sequenceable and interval types have a lot in common. Both types both have the concept of granularity in terms of step amount and optionally a unit such as weeks, months, and so on.
The interface for ISequenceable is as follows. Implement
these me thods and declare your class to implement this interface.
public interface ISequenceable<E extends ISequenceable<E, S, U>, S, U> extends Comparable<E> {
E nextInSequence( S step, U unit );
E nextNthInSequence( S step, U unit, int iIndex );
E previousInSequence( S step, U unit );
E previousNthInSequence( S step, U unit, int iIndex );
}
Method |
Parameter |
Description |
|---|---|---|
|
Returns |
|
|
An alias for the column name in the row query result |
|
|
A path expression that references the column to include in the row query result. For example, you can use a feature literal expression. |
|
|
Returns |
|
|
An alias for the column name in the row query result |
|
|
||
|
||
|
Returns |
|
|
An alias for the column name in the row query result |
|
|
||
|
Returns |
|
|
An alias for the column name in the row query result |
|
|
||
|
The syntax for the interface might look unusual because of the use of Gosu generics. This syntax indicates that the interface is parameterized across three dimensions:
- The type of each sequenceable element in the interval.
- The type of the step amount.
For example, to skip every other item, the step is 2, which is an
Integer. For typical use cases, passIntegeras the type of the step amount. - The type of units for the interval.
For example, for an integer (1, 2, 3), choose
Integer. For a date interval, the type isDateUnit.That type contains values representing days, weeks, or months. For instance,DateUnit.DAYS. If you do not use units with the interval, typejava.lang.Voidfor this dimension of the parameterization. Carefully note the capitalization of this type, because it is particularly important to access Java types, especially when using Gosu generics. In Gosu, as in Java,java.lang.Voidis the special type of the valuenull.
The example later in this topic has a class that extends the type:
IterableInterval<Color, Integer, void, ColorInterval>This bidirectional interface can fetch both next and previous elements. Gosu needs this capability to handle navigation from either endpoint in an interval to support the reverse mode. Gosu also requires that the class know how to jump to an element by its index in the series. This functionality can be achieved with the single step methods, some sequenceable objects can optimize this method without having to visit all elements in between. For example, if the step value is 100, Gosu does not need to call the nextInSequence method 100 times to get the next value.
The following example defines an enumeration
class with additional methods that implement the required methods of
ISequenceable.
package example.gosu.interval
enum ColorSequenceable
implements gw.lang.reflect.interval.ISequenceable<ColorSequenceable, Integer, java.lang.Void>
{
// Enumeration values....
Red, Orange, Yellow, Green, Blue, Indigo, Violet
// Required methods in ISequenceable interface...
override function nextInSequence( stp : Integer, unit : java.lang.Void ): ColorSequenceable {
return ColorSequenceable.AllValues[this.Ordinal + stp]
}
override function nextNthInSequence( stp : Integer, unit : java.lang.Void,
iIndex : int) : ColorSequenceable {
return ColorSequenceable.AllValues[this.Ordinal + stp * iIndex]
}
override function previousInSequence( stp : Integer, unit : java.lang.Void ) : ColorSequenceable {
return ColorSequenceable.AllValues[this.Ordinal - stp]
}
override function previousNthInSequence( stp : Integer, unit : java.lang.Void,
iIndex : int) : ColorSequenceable {
return ColorSequenceable.AllValues[this.Ordinal - stp * iIndex]
}
}
To use this class, run the following code in Gosu Scratchpad:
print("Red to Blue as a closed interval...")
var colorRange = new gw.lang.reflect.interval.SequenceableInterval(
ColorSequenceable.Red, ColorSequenceable.Blue, 1, null, true, true, false )
for (i in colorRange) {
print(i)
}
print("Red to Blue as an open interval...")
var colorRangeOpen = new gw.lang.reflect.interval.SequenceableInterval(
ColorSequenceable.Red, ColorSequenceable.Blue, 1, null, false, false, false )
for (i in colorRangeOpen) {
print(i)
}
This code prints:
Red to Blue as a closed interval...
Red
Orange
Yellow
Green
Blue
Red to Blue as an open interval...
Orange
Yellow
Green
To make your code look even more readable, you could
create your own subclass of SequenceableInterval
named for the sequenceable type that you plan to use. For example, ColorSequenceInterval.
See also
