Wednesday, January 18, 2012

A List of List stuff

So I continued on reading Seth Ladd's blog post on Lists and Arrays in Dart. One thing I didn't see mentioned that I think should be said, is that Lists are not type dependent. For people familiar with current dynamic languages such as Python, Ruby, and JavaScript that's not a big deal. But for those coming from Java, C, and other similar languages it is important to note that a List doesn't need to be all the same type. For instance the following is entirely valid:
List list = [1, "two", 3.48283008, [4, 4, "four", 4]];

So a List can contact mixed variable types, numbers, strings, even more Lists. However for those familiar with Javascript and other such dynamic languages who are used to associative arrays, its important to know that Lists are not that. As such you cannot assign a value to an index that does not yet exist.
List list = new List();
list[0] = "zero";
list[1] = 1;
IndexOutOfRangeException: 0

However, for extendable arrays, you can call set on length and increase the value. So you can grow, or shrink with more than just the add or addAll methods. For instance the following is valid:
List list = new List();
list.length = list.length + 2; // Now have two null values in the list.
list[0] = "zero";
list[1] = 1;
list.length = list.length - 1; // This removes the last value from the list.

Something important to note however, currently the API does not specifically state that changing the length to a value lower than the current will always have this effect. Currently there is no guarantee that the values will be removed from the end of the List, or even that they will be removed at all. I can see a situation where, if the values at the end are not null, then they may not reduce the size of the List. That or when setting list size, the new value must be greater than or equal to current size. As the libraries are improved and change (and there will be change don't doubt that for a second), we'll get a better idea of what to expect.

There are a number of List methods which can be extremely useful, that require a function be passed to them as an argument. You can create these functions inline or pass the name of another function. I'll cover more on passing functions in another post. Some of these methods are: filter, some, every, sort. Some and Every return true or false values. every returns true if every value in a list meets the criteria defined by the function passed as an argument. some returns true if at least one of the values meets the criteria.
bool isNum(var e) => e is num;

main() {
  var list = [1, 2, "three"];
  print( list.every(isNum) );
  print( list.some(isNum) );
}

Gives the result:
false
true

Something to note is that the some, every and filter methods are defined as part of the Collection interface not specifically in List.

Something to make note of is that filter will return a new list of items that return true from the passed function, whereas the sort method will modify the existing list rather than return a new one. Take the following code as an example of how to use each.
main() {
  var list = [4, 3, 6, 1, 2, 5];
  list.sort(compare(a,b) {
    if (a == b) {
      return 0;
    } else if (a > b) {
      return 1;
    } else {
      return -1;
    }
  });
  // List is now [1, 2, 3, 4, 5, 6]

  var evens = list.filter(f(e) => e % 2 == 0);
  // list is still [1, 2, 3, 4, 5, 6]
  // evens is [2, 4, 6]
}

In the above code the list.sort method modifies the List we're working with, whereas the list.filter method returns a new List and does not make any changes to the existing list. One thing I'm not currently sure of is why the difference. Is it that sort is not removing or modifying the elements of the list where as filter does? To me anything that modifies the existing List, even if it's changing the ordering of the elements, should return a new List, which I can then assign back to the same variable if I so choose. As it stands now, I have to make a copy of the list prior to the sort if I want to keep the original ordering.

Another item to note, based on my limited trials, when iterating over the values of a List, elements are passed as value not reference. Thus if you make any changes to the value, they will not persist outside of the scope of the function. Here's an example of what I mean:
main() {
  var list = [1, 2, 3];
  for(var x in list) {
    x = x*2;
  }
  // List is still [1, 2, 3]
  
  list.forEach(f(x) { x = x*2; });
  // List is still [1, 2, 3]
}

In the first case, using the for loop I can understand that the elements are passed as values and that it does not modify the original list. However in the second case, using the forEach method, you would expect that any changes to the value there would be reflected in the list after the fact.

In any case. I highly recommend reading through the API references for List and for Collection to get an idea as to what other capabilities they hold.

No comments:

Post a Comment