Suggested change to TriangleMesh API

Jasper Potts jasper.potts at
Wed Apr 10 17:05:42 PDT 2013

Hi all,

The current API for TriangleMesh doesn't feel like it fits with the style of all other JavaFX API. The suggestion to to move to 4 ObservableLists for Points, Texture Coords, Faces and Smoothing Groups. The problem is for memory usage and performance we don't want to move from primitive "float/int" to "Float/Integer" so we need to add a Observable List type for "float" and "int". 

package javafx.scene.shape;

public class TriangleMesh {
	ObservableFloatList getPoints();
	ObservableFloatList getTextureCoords();
	ObservableIntList getFaces();
	ObservableIntList getSmoothingGroups();

Now this is where the problem is, there are 3 options I can think of:


Add 2 new interfaces that extend ObservableList<Float> and adds primitive float methods. Then we can add float[] implementations

package javafx.collections;

public interface ObservableFloatList extends ObservableList<Float> {
	public void addAll(float… elements);
	public void setAll(float... elements);
	float[] toArray(float[] a) 
	public float getFloat(int index)
	public void setFloat(int index, float value)
	public void addFloat(float value)
	public void addFloat(int index, float value)

public interface ObservableIntegerList extends ObservableList<Integer> {
	public void addAll(int… elements);
	public void setAll(int... elements);
	int[] toArray(int[] a) 
	public int getInt(int index)
	public void setInt(int index, int value)
	public void addInt(int value)
	public void addInt(int index, int value)

add to FXCollections {
	ObservableFloatList observableFloatList()
	ObservableFloatList observableFloatList(float[] values)
	ObservableIntegerList observableIntegerList()
	ObservableIntegerList observableIntegerList(int[] values)

The issue with this idea is how to create a implementation of ObservableList <Float> that uses a float[] as a internal backing store. The list contract states that myList.get(10) == myList.get(10) but this would fail as they would return two different instances of Float objects. So this option breaks the contract of "List" and "Collection" and may have issues if this list is passed into any API that accepts a standard Collection and relies on the fact that a get() will will return the same object as passed to the set().


Same API but inside the implementation of ObservableList <Float> we have two arrays a float[] and a Float[] when the use calls myList.get(10) we create a Float object and store it in the Float[] so on the next call the same object instance is returns. Then  myList.get(10) == myList.get(10) can be true. We can be lazy in creating the Float[] instance to only create it on the first call of get() or the use of any API methods that take a "Float". The pain with this approach is the memory consumption explodes when you use any "Float" API for example iterating of the List would result in the whole list expanding. A rough class is a List of 100,000 floats would take 400kb would expand to 1.6Mb if completely expanded to Float[]. But it could completely abide by the contract of Collection and List.


The other option is to create a new set of classes that are Observable primitive Arrays but does not implement Collection or List. Something like:

public interface ObservableFloatArray extends Iterable<Float>, Observable {
	public int size();
	public void addAll(float… elements);
	public void setAll(float... elements);
	float[] toArray(float[] a) 
	public float get(int index)
	public void set(int index, float value)
	public void add(float value)
	public void add(int index, float value)
	public float remove(int index);

The advantage of this option is don't have a contract of parent interface like "List" or "Collection" so can do anything we want. We can have only primitive "float" versions of get() and set() etc. It can also avoid all costly boxing/unboxing expect for implementing Iterable<Float>. The down side is that it is complete new collections class and can't be used with any existing Collections API.

So I am not loving any of the approaches at the moment but (2) seems like its the best, what do you guys think?



More information about the openjfx-dev mailing list