Chapter 6. Creating and Using Arrays

The lion’s share of the work you’ll do with data structures will be with lists, introduced in the last chapter, and arrays, introduced in this chapter. Tcl arrays, like Perl’s hashes, are associative, meaning that they are indexed by strings rather than integers or other numeric types. In addition to learning how to create and use arrays, this chapter also shows you commands and techniques for handling errors. Error handling combines well with material on arrays because common mistakes that occur when using arrays (such as accessing out-of-bounds or non-existent array indices) raise errors that need to be handled gracefully.

What’s the Word?

This chapter’s game, What’s the Word?, introduces you to Tcl arrays using a Jeopardy-like game. It displays the definition of a common word and then prompts you to guess the corresponding word. To play the game, execute the script jeopardy.tcl in this chapter’s code directory. The following listing shows one round of the game:

$ ./jeopardy.tcl
Tcl command for performing mathematical operations
Your answer: string
Nope. Try again: [expr]
Nope. Try again: expr
Correct!
expr: Tcl command for performing mathematical operations

The Differences Between Arrays and Lists

Tcl arrays are variables that store collections of data in a key-value format. Arrays are similar to lists in that both are accessed using an index. With lists, the index is an integer; with arrays, the index can be any string (although I discourage using strings with embedded whitespace as keys for reasons I describe shortly). A more significant difference between arrays and lists is that arrays are unordered collections of values (or elements), whereas lists are ordered sequences of values. In this sense, Tcl arrays are much more like Perl hashes than arrays in third-generation compiled languages like C or C++. If it was even possible to do so, if you tried to access the third element of an array, the value of that element might change because Tcl’s arrays are organized for speedy, convenient access, not for orderly, sequential access.

Note: Arrays Are Maintained as Hashes

Note: Arrays Are Maintained as Hashes

The reason that Tcl does not guarantee array access order and does not even provide the capability to do reference array elements in sequential order is that, internally, arrays are maintained as hashes. As you add elements to an array, they aren’t necessarily put at the “end.” Rather, they are arranged and rearranged in a “tree” that provides optimal access to any given element. This is really more than you need to know about Tcl internals, but someone is going to ask why arrays work this way. So now you know.

Another significant difference between arrays and lists is the manner in which array elements are referenced. Specific array elements are accessed by enclosing the index in parentheses immediately following the name of the array. To get the value of a particular element, you use $ substitution on the array variable name. For example, suppose that you have a three-element array named roles, which contains the three character classes elf, dwarf, and wizard (yes, this is a dungeon-crawl game). The classes are the indices, and the elements are short descriptions of each class. To set the description of the elf, you might use the following syntax:

set role(elf) "Slender humanoids with pointed ears and an affinity for all things
natural"

To retrieve the description of the elf role, you would use the following syntax:

puts $roles(elf)

The following example, array_ref.tcl in this chapter’s code directory, shows a more complete example:

set role(elf) "
	Slender, forest-dwelling humanoid with pointed ears with
    prodigious talent for herbal lore and the healing arts"
set role(dwarf) "
	Short, stout, cave-dwelling humanoid, rarely seen in
    sunlight, possessing remarkable gifts for mining and working
    stone and metal"
set role(troll) "
	Lazy, misshapen creature endowed with extraordinary
    strength and endurance and the unfortunate characteristic of
    turning to stone when exposed to sunlight"

puts "Troll: $role(troll)
"
puts "Elf: $role(elf)
"
puts "Dwarf: $role(dwarf)
"

Here’s the output:

$ ./array_ref.tcl
Troll:
    Lazy, misshapen creature endowed with extraordinary
    strength and endurance and the unfortunate characteristic of
    turning to stone when exposed to sunlight

Elf:

   Slender, forest-dwelling humanoid with pointed ears with
   prodigious talent for herbal lore and the healing arts

Dwarf:

    Short, stout, cave-dwelling humanoid, rarely seen in
    sunlight, possessing remarkable gifts for mining and working
    stone and metal

With these few pieces of information, you’re ready to dive into the particulars of using arrays.

Working with Arrays

Much like the string command, you work with arrays using the array command and one of 11 options or subcommands. Table 6.1 lists and briefly describes each array option.

Table 6.1. Array Options

Option

Description

array anymore arrayVar id

Returns I if more elements exist in the search of arrayVar specified by id, 0 otherwise.

array donesearch arrayVar id

Ends the search of arrayVar specified by id.

array exists arrayVar

Returns I if arrayVar is an array variable, 0 otherwise.

array get arrayVar ?pattern?

Returns a list of index-value pairs from arrayVar; specifypattern as a glob-style match to limit the returned elements to indices which match pattern; returns the empty list if there are no matches or arrayVar is empty.

array names arrayVar ?mode? ?pattern?

Returns a list of indices in arrayVar which match pattern (all if pattern not specified); mode specifies the type of match, defaulting to glob-style matching if omitted.

array set arrayVar list

Initializes arrayVar to the elements in list.

array size arrayVar

Returns the number of indices defined in arrayVar.

array startsearch arrayVar

Returns a search ID for a search of arrayVar.

array statistics arrayVar

Returns interesting statistics about arrayVar.

array unset arrayVar ?pattern?

Deletes all elements of arrayVar; if pattern is specified, delete only elements matching the glob denoted by pattern.

Of the 10 options in Table 6.1, four deal with searching arrays and three provide information. The other three do real work.

Getting Information About Arrays

Array variables look like any other variable in Tcl and, in most cases, act like them. However, it is an error to try to assign a scalar (single) value to an array variable. Once a variable has been assigned to an array-type value, you cannot use it a as a scalar. You can use the array exists command to see if a variable is an array before you access it using array syntax (see array_exists.tcl in this chapter’s code directory):

array set nums {one 1 two 2 three 3 four 4}
set chars [list {a c e g b d f h}]

if {[array exists nums] == 1} {
    puts "nums is an array"

} elseif {[info exists num]} {
    puts "nums exists but is not an array"
} else {
    puts "nums doesn't exist"
}

if {[array exists chars]} {
    puts "chars is an array"
} elseif {[info exists chars]} {
    puts "chars exists but is not an array"
} else {
    puts "chars doesn't exist"
}

First, I set up a couple of variables, nums, which is an array variable, and chars, which is a list variable. Then each if block tests to see if the variable is an array or if it even exists (using the info exists command discussed at the end of the chapter—see the section titled “Examining Variables”). Based on the result of these tests, I print an appropriate message:

$ ./array_exists.tcl
nums is an array
chars exists but is not an array

Once you know that an array exists, you might be interested in how many elements it contains. The array size command will tell you how many indices have been defined in an array, which doesn’t necessarily correspond to the number of elements:

array size arrayVar

If arrayVar is undefined, array size returns 0. The script array_info.tcl in this chapter’s code directory shows both the array size and the array statistics in action:

array set nums {one 1 two 2 three 3 four 4}
array set chars {}
array set roles {elf {} dwarf {} troll {}}

puts "nums has [array size nums] elements"
puts "chars has [array size chars] elements"
puts "roles has [array size roles] elements"

Here’s the output of this script (array_size.tcl in this chapter’s code directory):

$ ./array_info.tcl
nums has 4 elements
chars has 0 elements
roles has 3 elements

Notice that the roles array has three indices but no values. Well, it has values, but they are all empty. For this reason, your array-handling code should not assume that the number of indices is the same as the number of elements.

If you are interested in the internal structure of an array, and you shouldn’t be, you can use the array statistics command to find out a little bit about the hash table used to maintain the array. The syntax is simple:

array statistics arrayVar

That said, the array statistics command is useful to Tcl developers debugging problems with the array command’s implementation, but not to mere mortals like you and me. You can safely ignore it, which is precisely what I’m going to do for the rest of the book.

Converting Lists to Arrays

As Table 6.1 showed, you can initialize an array from a list using the array set command. Each pair of values in the list becomes an index and value in the resulting array. At the risk of stating the obvious, array set is the command to use to convert a list to an array. Key facts to bear in mind when using array set are:

  • The initializing list must have an even number of elements.

  • The odd-numbered elements in the list become the array indices.

  • The even-numbered elements become the corresponding array values.

If your initializer list has an odd number of elements, array set returns an error, as shown in the following short example (array_error.tcl in this chapter’s code directory):

array set nums {one 1 two 2 three 3 four}
puts "nums has [array size nums] elements"

The initializer in this example only has seven elements. As a result, you’ll get the following error when you execute this script:

$ ./array_error.tcl

list must have an even number of elements
    while executing

"array set nums {one 1 two 2 three 3 four}"

    (file "./array_error.tcl" line 6)

You’ve already seen array set in several scripts (for example, array_size.tcl), so I won’t belabor it any further.

Converting Arrays to Lists

To convert an array to a list, or simply to retrieve elements from the list, the command to use is array get. It returns a pair of elements; the first item in each pair is the index and the second is the value corresponding to that index. The syntax is:

array get arrayVar ?pattern?

If you omit pattern, you’ll get all of the elements in arrayVar or an empty list if arrayVar doesn’t contain any elements (that is, if it’s empty) or if arrayVar isn’t an array. If specified, pattern limits the return lists to those elements whose indices match the glob-style pattern. If there are no matches, again, the return value is an empty list. The script array_get.tcl in this chapter’s code directory illustrates array get's behavior:

set roles(elf) "
	Slender, forest-dwelling humanoid with pointed ears with
    prodigious talent for herbal lore and the healing arts"
set roles(dwarf) "
	Short, stout, cave-dwelling humanoid, rarely seen in
    sunlight, possessing remarkable gifts for mining and working
    stone and metal"
set roles(troll) "
	Lazy, misshapen creature endowed with extraordinary
    strength and endurance and the unfortunate characteristic of
    turning to stone when exposed to sunlight"

puts "Number of elements in array of roles: [array size roles]"
puts "Number of elements in list of roles: [llength [array get roles]]"
puts "dwarf, n.: [array get roles dw*]"
puts "wizard, n.: [array get roles wizard]"

After initializing three elements in an array named roles, I first use array size to show the number of elements in the array. Next, I use llength to illustrate that the three elements of the array convert to six elements in a list. The first array get command uses a search glob, dw* to retrieve any matching elements from the roles array. The second array get command shows when a matching index (to wizard, in this case) doesn’t exist. The output of this script shouldn’t surprise you:

$ ./array_get.tcl
Number of elements in array of roles: 3
Number of elements in list of roles: 6
dwarf, n.: dwarf {
    Short, stout, cave-dwelling humanoid, rarely seen in
    sunlight, possessing remarkable gifts for mining and working
    stone and metal}
wizard, n.:

Retrieving Array Elements

The problem with array gets is that it returns both the index and the value and, as you can see in the output of array_get.tcl, the output retains the list grouping (the {} characters). Sometimes, or perhaps most of the time, you are only interested in either the index or the value. To access the values, you can use the $ substitution method I showed you earlier in the chapter. For example, to access the value corresponding to the dwarf index, you could say $roles(dwarf):

puts $roles(dwarf)
    Short, stout, cave-dwelling humanoid, rarely seen in
    sunlight, possessing remarkable gifts for mining and working
    stone and metal

Of course, using $ substitution assumes you know the indices of the array. If you don’t, you need to use the array names command, which returns a list of all the indices defined in an array. Its syntax is:

array names arrayVar ?mode? ?pattern?

As usual, pattern specifies a pattern to match. mode can be either -glob (the default) for glob-style matching, -exact to require an exact match, or -regexp to request a regular expression match. If you specify neither -mode nor -pattern, all indices will be returned. Otherwise, only indices that match pattern and match according to the matching rule specified by -mode will be returned. Given the definition of the roles array in array_get.tcl, the following array name commands illustrate the corresponding return values:

puts "All indices: [array names roles]"
puts "Glob '*r*': [array names roles *r*]"
puts "Exact 'd': [array names roles -exact d]"

These commands produce, respectively:

All indices: dwarf troll elf
Glob '*r*': dwarf troll
Exact 'd':

Once you have the indices, a foreach loop makes trivial work of accessing the corresponding values (remember, foreach is specifically designed for iterating through lists, and the array names command returns a list):

foreach role [array names roles *r*] {
        puts "$role: $roles($role)"
}

The output corresponding to this code fragment is:

dwarf:
        Short, stout, cave-dwelling humanoid, rarely seen in
        sunlight, possessing remarkable gifts for mining and working
        stone and metal

troll:
        Lazy, misshapen creature endowed with extraordinary
        strength and endurance and the unfortunate characteristic of
        turning to stone when exposed to sunlight

The script array_names.tcl in this chapter’s code directory contains all of the snippets of code used in this section.

Note: Names or Indices?

Note: Names or Indices?

The Tcl documentation uniformly refers to the index of an array as its name. I prefer to use the term index because it avoids the possible confusion that might arise when one uses the phrase array name, which might refer to the name of the array variable or the name used to index a particular value in the array. Neither term is incorrect, but the Tcl documentation is pretty consistent in its use of name, so you need to be aware of this matter of diction.

Searching Arrays

The final array-related functionality I should cover is how to search arrays using startsearch, nextelement, anymore, and donesearch. However, I’m not going to do so because you can obtain the same results using an appropriately crafted array get or array names command and a foreach loop. In addition, the processor and memory overhead of accessing very large arrays is, shall we say, suboptimal at this time. From the man page for the array command, “It is currently more efficient and easier to use either the array get or array names [commands], together with foreach, to iterate over all but very large arrays.” If Tcl’s maintainers recommend eschewing the array search commands, that’s good enough for me. If you insist, the man page (man 3tcl array) describes the syntax of the search commands and also includes examples. I think you’ll find that they are awkward and unintuitive to use, and, IMNSHO, very un-Tclish.

Grace Under Pressure

One of the hallmarks of high-quality code, regardless of the language in which it is written, is its robustness, that is, how it behaves in the face of unexpected conditions, invalid data, errors, and the other digital disasters that plague computers and computer users. The worst scripts and programs just crash or terminate without warning, without giving users a chance to save their work or possibly to recover from the situation, and without providing any clue regarding what happened. These are the programs about which some wit said, “If it breaks, you get to keep both pieces.”

At the opposite end of the spectrum are those programs that just seem to keep chugging along and, when errors do occur, degrade gracefully. Degrading gracefully means that when errors do occur (and they will), the application does more than just throw up its hands and abruptly terminate. Rather, it provides the user with information about errors, offers suggestions about how to recover, or tries to recover on its own without soliciting user input. Better still are those programs that attempt, to the degree it is possible, to anticipate potential problems and code around them, or at least provide meaningful diagnostic information.

Robustness is partially the result of seasoned programmers building their experience into the code they write and partially the result of taking advantage of language features designed to facilitate dealing with errors and exceptions. This section introduces you to some of Tcl’s built-in capabilities for responding to unanticipated situations and degrading gracefully in the face of unrecoverable errors.

Dealing with Exceptions: The catch Command

If you’ve been a diligent reader and tried the exercises at the end of each chapter, you’ve likely already experienced how Tcl (well, the Tcl interpreter) behaves when it encounters errors in a script: It terminates the script and displays a stack trace that begins at the point at which the error occurred. Errors include calling commands with the wrong number or type of arguments, such as calling the puts command with four arguments or attempting to use an array variable in a scalar context. Tcl commands all have command-specific errors, that is, errors that aren’t general Tcl runtime errors but peculiar to the implementation of a given command.

The Tcl command for trapping such errors and, if you wish, doing something other than bailing out, is catch. Its general syntax is:

catch script ?resultVar?

script consists of one or more Tcl commands that might generate errors you want to catch. resultVar, if specified, stores script's return value (that is, the result of the last command executed) or, if an error occurs, an error message. If script raises an error, catch itself returns 1. If script does not raise an error, catch returns 0.

To execute script, catch invokes the Tcl interpreter. As a result, you should always protect (group) script with braces rather than double quotes because if you use double quotes, script will go through a second round of substitution. catch itself always returns without raising an error, although the commands it is executing might raise errors.

I’ll start with a simple example, catch_1.tcl in this chapter’s code directory:

catch {[puts $str]}

Ordinarily, puts $str would raise an error, and the script would terminate because the variable str is undefined:

$ ./catch_1.tcl
can't read "str": no such variable
    while executing
"puts $str"
    (file "./catch_1.tcl" line 7)

However, if you use the catch command as shown, the error will be ignored. Comment out the line puts $str in catch_1.tcl before executing it a second time:

$ ./catch_1.tcl
$

As you can see in the second example, the invalid puts command does not terminate the script. The Tcl interpreter didn’t really “ignore” the error, though. Rather, the catch command trapped the error and modified the normal behavior.

If you’re trapping errors using catch, you’ll want to do something other than just eating the error and continuing. A more typical use is to embed the catch command in an if or switch command so you can test catch's return value and decide how to proceed based on the error that occurred. Here’s a slightly more involved example, catch_2.tcl:

if {[catch {[puts $str]} retVal]} {
    puts "An error occurred: $retVal"
} else {
    puts "Nope, no errors here!"
}

The if condition tests catch's return value, which will be 0 or 1, and then executes the corresponding block of code:

$ ./catch_2.tcl
An error occurred: can't read "str": no such variable

In this case, instead of the stack trace, the output simply states the nature of the error. If you’re so inclined, you can provide a definition for the string variable str to see how catch_2.tcl works if catch returns 0. But I bet you can figure it out yourself.

The idea with catch is to handle errors without your script or program unceremoniously crashing. For example, suppose that your script is supposed to open a file that contains a saved game. If it can’t find the file, the script can either give up and quit, or it can prompt the user for another filename. Guess which behavior will give users a more pleasant experience?

Raising Errors: The error Command

You’ve seen that you can trap errors raised by the Tcl interpreter and by Tcl commands using the catch command. You can also raise your own errors, which can in turn be caught by catch. The rationale here is to provide one or more custom error handlers to replace or supplement Tcl’s built-in error handling. The command to raise an error is, you guessed it, error. Its syntax is:

error msg ?info? ?code?

error returns 1 to the calling procedure or command. msg is the string that describes what went wrong. The info argument is used to initialize a special Tcl global variable, errorInfo, which, in turn, is used to store a stack trace, the chain of commands that led up to the error you raised with error. If you don’t specify info, msg will be displayed, followed by the stack trace. code is a machine-readable and succinct error description. If you use it, code will be stored in (yet another) special global Tcl variable, errorCode, and it should adhere to the format described in the tclvars man page (man 3tcl tclvars) for the errorCode global variable. If you don’t specify code, the Tcl interpreter sets it to NONE. To keep things simple, I recommend not using code in your scripts.

The following two scripts show how to raise errors with the error command. The first script (error_msg.tcl in this chapter’s code directory) sets only the msg parameter. The second example (see error_info.tcl) sets both msg and info:

set numerator 9;
set denominator 0;

# Just set the error message
if {$denominator == 0} {
    error "Dude! Division by zero is undefined"
}

The output of this script is:

$ ./error_msg.tcl

Dude! Division by zero is undefined
    while executing
"error "Dude! Division by zero is undefined""
    invoked from within
"if {$denominator == 0} {
    error "Dude! Division by zero is undefined"
}"
    (file "./error_msg.tcl" line 9)

As you can see, error still generates a stack trace, but the first entry is the message passed to it in msg:

set numerator 9;
set denominator 0;

# Set the error message and initialize errorInfo
if {$denominator == 0} {
    error "Dude! Division by zero is undefined" "Undefined"

}

When you execute the second script, it is the info parameter that is displayed at the top of the stack trace, rather than the msg parameter:

$ ./error_info.tcl
Undefined
    invoked from within

"if {$denominator == 0} {
    error "Dude! Division by zero is undefined" "Undefined"
}"
    (file "./error_info.tcl" line 9)

Which style should you use? Continuing with my theme of keeping things simple, I suggest using the format error msg because it has the virtue of preserving the complete stack trace created by the Tcl interpreter while displaying the error message you specify. You usually want to use the second form if you have a need to set or modify the stack trace.

Examining Variables

Earlier in the chapter, I used the info exists command to see if a variable existed before I tried to print its value. This technique is very handy as both a debugging tool and as part of making your code a little sturdier. Its syntax is:

info exists varName

This command returns 1 if the variable varName exists and has been defined (given a value). Otherwise, it returns 0. The array_info.tcl script contains an example, so I won’t repeat it here.

Another useful info command is info vars, which returns a list of the names of all of the variables visible in the current scope. Its syntax is:

info vars ?pattern?

If specified, pattern, which is a string match-style glob, limits the return list to those variables matching pattern. info vars might not seem terribly useful just now, but after you learn how to organize your scripts into modules and store each module in a separate file, it will be very useful. You will be able to load an arbitrary file of Tcl code and find out exactly what variables it contains. Yes, I still need to show you how to do that, too. Patience, grasshopper, I’m getting there. Chapter 7, “Writing Tcl Procedures,” shows you how to load Tcl code from one file into another.

In a newly started tclsh instance, there are a number of predefined variables that you might find useful:

% info vars
tcl_rcFileName tcl_version argv0 argv tcl_interactive auto_oldpath errorCode auto_path
errorInfo auto_index env tcl_pkgPath tcl_patchLevel argc tcl_libPath tcl_library
tcl_platform

To find out what these variables are, have a look at the tclvars man page (man 3tcl tclvars).

Similar to info vars is info procs, which displays a list of all the procedures defined in the current scope. Again, in a fresh tclsh instance, there are a number of predefined procedures. These won’t be much use to you at this stage of your Tcl programming, but later on you might find them useful:

% info procs
auto_load_index unknown auto_import auto_execok auto_qualify auto_load history tclLog

Unlike the predefined Tcl variables, these procedures have their own manual pages, which you can view using the command man 3tcl proc_name, replacing proc_name with the name of the procedure in which you are interested.

Analyzing What’s the Word?

Although it is simple, jeopardy.tcl combines features from several of the preceding chapters. In addition to using an array to store questions and answers, it uses list commands to access the list objects returned by array operations, mathematical calculations for selecting an array element to use, and string commands to massage user input and evaluate the user’s guess. In short, it exhibits a key characteristic of “real” Tcl programs, using a variety of commands and techniques to solve a programming problem.

Looking at the Code

#!/usr/bin/tclsh
# jeopardy.tcl
# Play a simple Jeopardy-like game

# Block 1
# Words and their definitions
array set words {
    "Tcl" "Programming language originally designed as a glue language"
    "Ousterhout" "Surname of the person who originally wrote Tcl"
    "expr" "Tcl command for performing mathematical operations"
    "HTML" "The 'language' of the World Wide Web"
    "9" "The Arabic numeral equivalent to the Roman numeral IX"
    "25" "The missing value in the sequence of numbers 4, 9, 16, 36"
    }

# Block 2
# Select a random word and definition
set i [expr {int(rand() * 6))}]
set word [lindex [array names words] $i]
set def $words($word)

# Block 3
# Show the definition and prompt for the word it defines
puts $def
puts -nonewline "Your answer: "
flush stdout
gets stdin input
set guess [string trim $input]

# Block 4
# Evaluate user's guess, prompt for new answer until correct
while {[string tolower $guess] ne [string tolower $word]} {
    puts -nonewline "Nope. Try again: "    flush stdout    gets stdin input
set guess [string trim $input]
}

# Block 5
puts "Correct!"
puts "$guess: $def"

Understanding the Code

Blocks 1 and 2 set up the game. Block 1 creates an array of words (with the wonderfully imaginative name $words) and their definitions using array set and a list. $words is indexed by the word I want to define, and the value of each index is the corresponding definition. Nothing terribly remarkable, but a necessary step. In Block 2, I use my (by now) familiar routine for generating a random number between 0 and 5 so I can select a random term and its associated definition from the $words array. The second set command in Block 2 uses the list operator lindex on the list returned by array names to select the word I want to define. The third set command uses a simple array reference ($words($word)) to retrieve the definition. Game play begins in Block 3. Here, I show the definition and then prompt the user to type a word. The user’s answer gets stored in the variable $input, which I store in $guess after using the trim command to remove leading and trailing whitespace, if any. Trimming input is a technique I often use to clean up user input before using it in comparisons. In this case, my goal is to reduce the likelihood of stray characters incorrectly causing a correct answer to be considered incorrect.

Block 4 uses a while loop to compare the player’s answer to the correct answer. If the answer is correct, the loop exits and control passes to Block 5. If the player guessed incorrectly, I ask for another guess, performing the same trim operation as described for Block 3. The loop condition, [string tolower $guess] ne [string tolower $word], converts both the player’s input and the correct answer to lowercase. I do this to enhance the game’s playability—it seems unfair to assert, for example, that HTML and html are not the same answer in the context of the game.

Block 5 ends the game, showing the player the guess and its definition.

Modifying the Code

Here are some exercises you can try to practice what you learned in this chapter:

  • 6.1 Modify Block 1 to use a different set of six words and definitions.

  • 6.2 Modify Block 4 to give users the option to play another round instead of exiting the game after guessing the correct answer.

  • 6.3 Modify the loop condition in Block 4's while loop to use a different string operation to compare the player’s guess to the correct answer.

Arrays are the second most important data structure (the most important is lists). Although arrays and lists share a number of characteristics and you can easily convert between arrays and lists, their syntax is different. Arrays also have a smaller range of natively supported operations that you can perform. This chapter also introduced you to the catch command, which allows you to handle runtime errors more gracefully than simply exiting the script abruptly. Robust, fault-tolerant programs are a hallmark of professional, skilled developers. The next chapter, “Writing Tcl Procedures,” introduces you to another characteristic of high-quality programming, which is modularization.

 

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.216.38.221