out of bounds Intlist index returns zero

edited January 2014 in Programming Questions

Does anyone know why, with an IntList that has less than 10 elements, using list.get(n) for values of n greater than the last index and less than 10 returns 0 as opposed to giving an "index out of bounds" error?

Answers

  • edited January 2014 Answer ✓

    IntList and many of such are new-comers in Processing 2+! =D>

    In particular, IntList was meant to replace Java's ArrayList<Integer>.
    But w/ the added bonus of storing faster primitive int values rather than references for Integer wrappers! \m/

    Both of them have an underlying array instance to store its entries though. And as most of us know, arrays can't be resized!
    If we need to, we gotta create another 1 w/ the length we wish and transfer everything to that and discard the old 1!

    From that we can conclude that the # of items stored, its size(), are <= to the current capacity, the length, of the internal array.

    Whilst an ArrayList always checks whether we try to use an index >= of its size(), the new storage classes are much less strict!
    I find it cool, b/c besides not being that important, it's 1 less bottleneck performance-wise!
    And that's stacked upon the fact that they already store primitive values instead! =:)

    An IntList starts out w/ capacity 10. That's why we can access up to index 9, even though its size() is less than that!

    Likewise a List, we can specify its initial capacity when we instantiate it.
    But unlikewise, we can initiate it w/ an array too! :ar!

  • "I find it cool"
    I find it inconsistent, because a.get(8) is 0 and a.get(88) throws an error in an uninitialized IntList...

  • edited January 2014

    I find it inconsistent, because a.get(8) is 0 and a.get(88) throws an error in an uninitialized IntList...

    As I had already informed, initial capacity is 10. Thus indices from 0 to 9 are already available from the get-go!
    But size() method is still firmly consistent to the highest index set. It's not that bad! ~:>

    Nonetheless, if you do insist, you can instantiate it w/ initial capacity set to 0 -> new IntList(0);.
    Or if it's about known how many we're gonna need, it's even better to use that as initial capacity:

    static final int NUM = 0400;
    final IntList ints = new IntList(NUM);
    

    Anyways, just keep playing safe as we already do w/ more strict bound-check data-structures.
    That is, in doubt, always check size() before accessing an item from it, rather than shoot in the dark! [..]

  • Thanks for the explanation. When I try to set the capacity to 0 and then append an element, I get an "ArrayIndexOutOfBoundsException: 0". If I set the capacity to 1, I don't get the error, but then if I add more items to the list, the list grows by doubling. So there will always be cases where it won't throw index out of bounds exceptions the way an ArrayList would, but the size() function is consistent. OK. And if checking the size during every call to an IntList function would slow things down, and speed more than convenience is the priority, then OK. Thanks again.

  • edited January 2014

    ... but then if I add more items to the list, the list grows by doubling.

    That doubling behavior is the same for ArrayList and List in general too! (~~)
    That is, if we try to append()/add() or set() w/ an index >= its capacity, capacity is doubled! :(|)

    I've been looking at IntList's source code:
    https://github.com/processing/processing/blob/master/core/src/processing/data/IntList.java

    And below the reason why get() is so "anarchist" but fast:


    public int get(int index) {
      return data[index];
    }
    

    And I've found a fix for your "problem" -> a secret method called values() which invokes top secret private method crop(): >:)


    // Default's internal capacity is 10, even though count = 0 yet:
    final IntList myIntList = new IntList(); // data.length = 10 (capacity).
    
    // No problem accessing an index >= count, while still < capacity:
    println(myIntList.get(5)); // returns int 0.
    
    // This hidden method, besides returning the real internal int[] data,
    // it also invokes a private method called crop(),
    // which resizes the internal int[] data to current element count:
    myIntList.values();
    
    // Now we've got an exception to a get() w/ an index >= count:
    println(myIntList.get(5)); // ArrayIndexoutOfBoundsException: 5.
    
    exit();
    

    And their respective source codes: (*)


    public int[] values() {
      crop();
      return data;
    }
    

    private void crop() {
      if (count != data.length)  data = PApplet.subset(data, 0, count);
    }
    

    Also, a way to initialize an IntList w/ a numerical sequence: :bz


    final IntList myIntList = IntList.fromRange(1, 10+1);
    println(myIntList);
    exit();
    

  • "That doubling behavior is the same for ArrayList and List in general too!"
    From memory, it uses to be the case, but now Java uses a more conservative growing scheme, using a factor around 1.3, IIRC.

    "if checking the size during every call to an IntList function would slow things down"
    You should not worry about this "slow down", it would count in microseconds (at worst) per draw() loop (16,666 µs by default!).

Sign In or Register to comment.