Lists Aren’t Just for Shopping

I’ve alluded to lists a few times now, and in Modules 7 and 8, you even used them a little. So what are lists, and what purpose do they serve?

Put most concisely, a list in Director is a collection of information that is indexed and stored in a single data container. This information can be almost anything; any data or variable type that Director itself can handle can also be tucked away into a list and passed around your Lingo like any other variable.

What makes lists particularly unique is the fact they are indexed. This means that if you stuff the value of pi into some list someplace at index position 2, it will remain in that position for as long as your program’s running and the list variable persists, provided you don’t explicitly change the list’s contents or sort order. No matter where you are in your code, you will be able to get that value from its index location in the list.

Director permits you to make two different kind of lists: linear lists, which we’ll be discussing right away, and property lists, which we’ll cover in the next few pages. the two formats are available because each works better than the other in a given circumstance.

A linear list can be thought of in terms of shopping. Before you go to the store, you might make a note that you need eggs, lettuce, milk, flour, and apples. If you were to put this kind of list into a variable in Director, you might do something like this:

shoppingList = [ "eggs", "lettuce", "milk", "flour", "apples" ]

That’s pretty simple, isn’t it? Then, if you wanted to find out what the third item in your list was, you would simply grab that item at its specific index number:

item = shoppingList[3]

In our example, the variable item would contain "milk", because "milk" is the third thing in the shoppingList container.

But this list isn’t all that well sorted, is it? Director includes a sort keyword, though, which allows us to sort lists in alphabetical order. (Numbers come first.) So if we did this to our list:

shoppingList.sort()

it would now look like this:

[ "apples", "eggs", "flour", "lettuce", "milk" ]

Suppose we want to add some more items to our list, items we’ve just remembered we need. Perhaps we need some grapes, cheese, and eggplant. We can’t just set shoppingList equal to those items, because if we do, the original contents of shoppingList will be gone forever.

You might be thinking of using addition here, something like:

shoppingList = shoppingList + [ "grapes", "cheese", "eggplant" ]

Clever, but Director doesn’t let you get away with that, unfortunately. What we want to do here is append the new items we need to the shoppingList, and append happens to be exactly the Lingo keyword we use to do that:

shoppingList.append( "grapes" )

This would append "grapes" to our shopping list variable, putting it at the end, so shoppingList now contains

[ "apples", "eggs", "flour", "lettuce", "milk", "grapes" ]

We then do the append two more times for "cheese" and "eggplant" and end up with this as our grand result:

[ "apples", "eggs", "flour", "lettuce", "milk", "grapes", "cheese", "eggplant" ]

Oh, but our alphabetical sort is off again. Furthermore, this list is not at all well organized. There are dairy products scattered through it, and frankly getting any item from a list by its index number is not especially convenient.

How are you supposed to know, without actually looking at the list, whether "milk" is in index position 5 (or if it’s even in the list for this week at all)? That’s not a very effective way to handle a list of any appreciable size, and it certainly would not be useful for handling contents that some user has entered him- or herself.

Imagine a 500-item list! Imagine a shopping list that contained things you never even considered adding, such as tofu or baklava!

Organizing Lists More Effectively

What we’d really need to make this shopping list of ours considerably easier to sort, modify, add things to, and read would be some kind of way to categorize the list’s contents, perhaps by produce type.

You might be thinking, well, then use different variables. For dairy, you could do this:

dairyList = [ "cheese", "eggs", "milk" ]

…and for vegetables you could do:

vegetableList = [ "eggplant" , "lettuce" ]

…and so on. That’s not the worst possible idea, of course, but it’s not particularly efficient, and it does not take into account how people may sort things. It also doesn’t let you add more categories to the overall shopping list; for instance, there’s no variable set for cleaning supplies. If a list is going to really be useful, it will be expandable, but it should be sortable as well.

This is where property lists come into play. In the examples we’ve done in the book so far, you haven’t used these; they add a dimension of sortability to plain linear lists that makes them genuinely powerful tools. (In fact, with a well-designed property list, you can create a rich, searchable database.) Property lists allow you to create lists like our one for shopping, but they allow you to create index handles in the list itself, which can give you an additional layer of sorting.

Tip: Actually, you can have essentially an infinite number of layers and categories in a property list. Property lists ideally use either integer numbers for those index handles, or symbols. A symbol is a special Lingo creature that consists of a single word preceded by the pound sign:

#thisIsASymbol

You might remember the pound sign from the last module, where it was used in a sendSprite call to tell a specific sprite to run a handler. The handler name was preceded, also, by the pound sign, and that does in fact imply a little something about how Director works under the hood, but that’s a discussion several parsecs off the main point here.

Symbols are extremely nice things. They are faster for Lingo to process than plain text, but they possess a great strength in that they can be made human readable. This means that if you get into the practice of using symbols instead of numbers to pass information around in your program (wherever feasible), your scripts will be considerably easier to understand.

I said that symbols must be one word. The rules that apply for handler names are the same as those for symbols: No spaces, no punctuation, no special characters except the underscore. Thus

#this_is_a_valid_symbol

but

#this is not

That’s pretty nice to know, but what’s even more fun is that you can convert plain text to a symbol, or a symbol to plain text, by using the symbol and string keywords, respectively. You probably remember seeing the string keyword in Module 6; it’s a way to specify that a given chunk of data is supposed to be converted to text, which in Director space is something surrounded by double quotes.

Well, if you pass something through the symbol keyword, it surely will be converted to a symbol, at least until Director encounters an illegal character. Here are some examples.
 

put symbol ( "hello" )
-- #hello
put string ( #goodMorning )
-- "goodMorning"
put symbol ( "Hello, world!" )
-- #Hello


Oho, in that third example you can see that our original text, "Hello, world!", did not get completely converted to a symbol. Only the first word ended up in the symbol result, with everything past the first illegal character (in this case the comma) truncated, or removed entirely.

And why does any of this bear any relevance to our discussion of property lists? Because, if you remember, property lists can use symbols as well as integers to provide index handles, that’s why, and those symbols can make our property lists very easy to manage.