Working with lists

I’m curious why the commented out statements in the code below do not work.

  local lst1, lst2;

  lst1 = [0, 1, 2, 3];
  "The length of lst1 is <<lst1.length>>.\n";
  
  lst1 = lst1 + [4, 5, 0];
  "The length of lst1 is <<lst1.length>>.\n";
  
  lst2 = ['Tatiana', 'Emily', 'Debbie'].length();
  "The length of lst2 is <<lst2>>.\n";
  
  "Count of 0 in lst1: <<lst1.countOf(0)>>.\n";
  
  // The statements below cannot be executed.
  // Error: Runtime error: object value required
  //local debCount = lst2.countOf('Debbie');
  //local name = 'Debbie';
  //"Count of 'Debbie' in lst2: <<lst2.countOf(name)>>.\n";
  //"Items in lst2: "; lst2.forEach(new function(item) { "<<item>> "; }); "\n";

Am I missing something really obvious?

You’ve set lst2 not to the list of names, but to the integer value of the length of that list!

Conrad.

More mysteriously to me, why does this work?

[code] go () {
local lst1;

lst1 = [0, 1, 2, 3];
“lst1 = [0, 1, 2, 3]; \n”;
“The length of lst1 is <<lst1.length>>.\n”;
"Items in lst1: "; lst1.forEach(new function(item) { "<> "; }); “\n”;

lst1 = lst1 + [4, 5, 0];
“…adding [4, 5, 0]; \n”;
“The new length of lst1 is <<lst1.length>>.\n”;
"Items in lst1: "; lst1.forEach(new function(item) { "<> "; }); “\n”;

}[/code]

The output:

–I thought you couldn’t modify lists once they were made?

Conrad.

So how do you iterate over the contents of a list that contain value strings? And can I not count how many such values of ‘some string’ are in a list?

If [1, 2, 3] is a list of values than so, I presume, is [‘a’, ‘b’, ‘c’].

I should note I don’t actually have an immediate need for this; I’m just experimenting with the language.

No, you can do everything that you were doing. You just made a small error in your declaration.

lst2 = ['Tatiana', 'Emily', 'Debbie'].length(); "The length of lst2 is <<lst2>>.\n";

Clearly, this defines “lst2” not as a list, but as the length of a list (which is never recorded into any variable).

When you later try to work with the “lst2” variable as if it were a list, you are in fact working with an integer variable of value 3, since this is the length of the [list] that you set lst2 equal to.

Use instead

lst2 = ['Tatiana', 'Emily', 'Debbie']; "The length of lst2 is <<lst2.length()>>.\n";

For your declaration and reporting, and you’ll find the rest of the code works as you anticipate.

Conrad.

Ah, got it.

I see my error. I’m an idiot! I forgot I was testing out if methods can be called on a direct instance.

You can modify lists, but it always creates a new list, leaving the original unchanged. If you want to capture the result of that modification, you have to assign it to a local, property, or some other means of reference.

Here you’ve replaced the contents of the lst1 local with the modified list. The original list is still out there, floating in memory, but it can no longer be referred to and the garbage collector will eventually sweep it up.

Ok,

But what does that mean? What are the things I can’t do with lists?

Conrad.

Most of what applies to lists also applies to strings - they’re both immutable and both somewhat privileged in terms of the underlying VM. Obviously you can do a lot with strings, and the same is true of lists.

The main thing you can’t do is in-place modification. This gets me most often with strings, where I run a regex or replace part of a string and expect to retain that value without an assignment, which doesn’t work.

Related to that is that both have a counterpart class - Vector, StringBuffer - where you can do in-place modification. This is helpful when building a list or string out of lots of little units, since you don’t create an entire VM object whenever you append something. These can be converted back to the static kind when you finish.

Other than that, I don’t see a lot of limitations. I use lists extensively.

So I can iteratively build up lists? With, for example, lstA += [somevarX]; ? Or by passing a list into a function and then returning a new one?

Conrad.

You can do both. In the iteration case, it’s better to build it as a vector, then convert the vector to a list.

local lst = new Vector(50);
forEachInstance(Room, {room: lst.append(room)});
lst = lst.toList();

Lists and functions work very well together. A common pattern is to start with a list and filter it through many different functions (or recursively through the same function) before returning a value.

Ok. I’m hearing I just can’t reach inside and tweak it without a reassignment?

Thanks for clarifying, Ben.

Conrad.