Basics of JavaFX sequence implementation
This article introduces the core classes used for
the JavaFX sequence implementation.
Note that these are internal classes and interfaces,
not a supported API.
This is purely for your information and edification:
The goal is to help you get a mental model of what is under the hood
,
and the approximate cost of the various sequence operations.
The Sequence interface
A JavaFX sequence type T[]
is implemented
using classes that implement the Sequence<T>
interface:
public interface Sequence<T> { /** Number of items in sequence. */ public int size(); public T get(int position); /** Copy elements from sequence into an array. */ public void toArray(int sourceOffset, int length, Object[] array, int destOffset); /** Get this[startPos..<endPos]. */ public Sequence<T> getSlice(int startPos, int endPos); /** What to return when an index is out-of-range. */ T getDefaultValue(); ... a few more ...; }
All (existing) Sequence
concrete classes extend
AbstractSequence
, which implements various utility methods:
public class AbstractSequence<T> implements Sequence<T> { ... default implementations of some methods ... }
(Idea to consider: We might want to merge Sequence
and
AbstractSequence
. That would save a little bit of static
footprint. It should also slightly improve performance, since
virtual method calls are usually more efficient than interface
method calls, especially on not-so-smart VMs.)
The default
sequence implementation
is ArraySequence
, which (surprise!) uses a Java array.
The following is highly simplified;
we'll go into ArraySequence
in more detail in a later note.
public class ArraySequence<T> extends AbstractSequence<T> { T[] array; // Warning - this is simplified! public T get(int position) { if (position < 0 || position >= array.length) return getDefaultValue(); return array[position]; } ... }
There are a few special Sequence
classes.
SingletonSequence
is an optimization for single-item
sequences. IntRangeSequence
(and the similar
NumberRangeSequence
) are used to implement
[start..<end]
ranges:
public class IntRangeSequence extends AbstractSequence<Integer> { int start, step, size; ...; public Integer get(int position) { if (position < 0 || position >= size) return getDefaultValue(); else return (start + position * step); } }
Finally, SubSequence
is used for sequence slices:
public class SubSequence<Integer> extends AbstractSequence<Integer> { public T get(int position) { if (position < 0 || position >= size) return getDefaultValue(); else return sequence.get(startPos + step * position); } ... }
The JavaFX type T[]
is actually mapped to the
Java type Sequence<? extends T>
,
where the
specifies a wildcard.
This is to support
co-variance of sequence types. You see this below.
? extends T
What about sequences of primitive
types, such as Integer
,
which corresponds to the Java int
type?
That deserves a separate article.
A named mutable variable is represented by SequenceVariable
.
It stores the current value
,
which is a sequence value, of type Sequence<? extends T>
.
class SequenceVariable<T> { protected Sequence<? extends T> $value; public Sequence<? extends T> getAsSequence() { return $value; } public Sequence<? extends T> setAsSequence (Sequence newValue) { $value = newValue; ... handle triggers and dependencies ... } public void insertBefore(T value, int position) { replaceSlice(position, position, value); } public void replaceSlice(int startPos, int endPos, T newValue) { ... interesting stuff ... } public void replaceSlice(int startPos, int endPos, Sequence newValue) { ... interesting stuff ... } ... }
All of the sequence insert/delete/replace operations map down to either
replaceSlice(int startPos, int endPos, T newValue)
or replaceSlice(int startPos, int endPos, Sequence<? extends T> newValues)
, where the former can be viewed as optimizations of the latter.
These operations for updating sequence variables are interesting and tricky enough that they deserve separate articles JavaFX-sequence-updating and JavaFX-sequence-triggers.