Wednesday, October 28, 2009

Lab 19.2 Exercises



[ Team LiB ]





Lab 19.2 Exercises


19.2.1 Use Nested Records


In this exercise, you will learn more about nested records.


Create the following PL/SQL script:





-- ch19_3a.sql, version 1.0
SET SERVEROUTPUT ON
DECLARE
TYPE last_name_type IS TABLE OF student.last_name%TYPE
INDEX BY BINARY_INTEGER;

TYPE zip_info_type IS RECORD
(zip VARCHAR2(5),
last_name_tab last_name_type);

CURSOR name_cur (p_zip VARCHAR2) IS
SELECT last_name
FROM student
WHERE zip = p_zip;

zip_info_rec zip_info_type;
v_zip VARCHAR2(5) := '&sv_zip';
v_counter INTEGER := 0;
BEGIN
zip_info_rec.zip := v_zip;

FOR name_rec IN name_cur (v_zip) LOOP
v_counter := v_counter + 1;
zip_info_rec.last_name_tab(v_counter) :=
name_rec.last_name;
END LOOP;
END;

Answer the following questions:


a)

Explain the script ch19_3a.sql.

b)

Modify the script so that zip_info_rec data is displayed on the screen. Make sure that a value of the zipcode is displayed only once. Provide the value of '11368' when running the script.

c)

Modify the script created in the previous exercise (ch19_3b.sql). Instead of providing a value for a zipcode at runtime, populate via the cursor FOR loop. The SELECT statement associated with the new cursor should return zipcodes that have more than one student in them.






    [ Team LiB ]



    Chapter 1. Introduction








     

     












    Chapter 1. Introduction



    It's no secret that the Unix operating system has emerged as a standard operating system. For programmers who have been using Unix for many years now, this came as no surprise: The Unix system provides an elegant and efficient environment for program development. After all, this is what Dennis Ritchie and Ken Thompson strived for when they developed Unix at Bell Laboratories in the late 1960s.



    One of the strongest features of the Unix system is its wide collection of programs. More than 200 basic commands are distributed with the standard operating system. These commands (also known as tools) do everything from counting the number of lines in a file, to sending electronic mail, to displaying a calendar for any desired year.



    But the real strength of the Unix system comes not entirely from this large collection of commands but also from the elegance and ease with which these commands can be combined to perform far more sophisticated functions.



    To further this end, and also to provide a consistent buffer between the user and the guts of the Unix system (the kernel), the shell was developed. The shell is simply a program that reads in the commands you type and converts them into a form more readily understood by the Unix system. It also includes some fundamental programming constructs that let you make decisions, loop, and store values in variables.



    The standard shell distributed with Unix and Linux systems derives from AT&T's distribution, which evolved from a version originally written by Stephen Bourne at Bell Labs. Since then, the IEEE created standards based on the Bourne shell and the other more recent shells. The current version of this standard as of this revision is the Shell and Utilities volume of IEEE Std 1003.1-2001, also known as the POSIX standard. This shell is what we propose to teach you about in this book.



    The examples in this book were tested on both SunOS 5.7 running on a Sparcstation Ultra-30 and on Silicon Graphics IRIX 6.5 running on an Octane; some examples were also run on Red Hat Linux 7.1 and Cygwin. All examples, except some Bash examples in Chapter 15, were run using the Korn shell, although many were also run with Bash.



    Many Unix systems are still around that have Bourne shell derivatives and utilities not compliant with the POSIX standard. We'll try to note this throughout the text wherever possible; however, there are so many different versions of Unix from so many different vendors that it's simply not possible to mention every difference. If you do have an older Unix system that doesn't supply a POSIX-compliant shell, there's still hope. We'll list resources at the end of this book where you can obtain free copies of three different POSIX-compliant shells.



    Because the shell offers an interpreted programming language, programs can be written, modified, and debugged quickly and easily. We turn to the shell as our first choice of programming language. After you become adept at programming in the shell, you too may turn to it first.



    This book assumes that you are familiar with the fundamentals of the Unix system; that is, that you know how to log in; how to create files, edit them, and remove them; and how to work with directories. But in case you haven't used the Unix system for a while, we'll examine the basics in Chapter 2, "A Quick Review of the Basics." Besides the basic file commands, filename substitution, I/O redirection, and pipes are also reviewed in Chapter 2.



    Chapter 3, "What Is the Shell?," reveals what the shell really is. You'll learn about what happens every time you log in to the system, how the shell program gets started, how it parses the command line, and how it executes other programs for you. A key point made in Chapter 3 is that the shell is just a program; nothing more, nothing less.



    Chapter 4, "Tools of the Trade," provides tutorials on tools useful in writing shell programs. Covered in this chapter are cut, paste, sed, grep, sort, tr, and uniq. Admittedly, the selection is subjective, but it does set the stage for programs that we'll develop throughout the remainder of the book. Also in Chapter 4 is a detailed discussion of regular expressions, which are used by many Unix commands such as sed, grep, and ed.



    Chapters 5 through 10 teach you how to put the shell to work for writing programs. You'll learn how to write your own commands; use variables; write programs that accept arguments; make decisions; use the shell's for, while, and until looping commands; and use the read command to read data from the terminal or from a file. Chapter 6, "Can I Quote You on That?," is devoted entirely to a discussion on one of the most intriguing (and often confusing) aspects of the shell: the way it interprets quotes.



    By this point in the book, all the basic programming constructs in the shell will have been covered, and you will be able to write shell programs to solve your particular problems.



    Chapter 11, "Your Environment," covers a topic of great importance for a real understanding of the way the shell operates: the environment. You'll learn about local and exported variables; subshells; special shell variables such as HOME, PATH, and CDPATH; and how to set up your .profile file.



    Chapter 12, "More on Parameters," and Chapter 13, "Loose Ends," tie up some loose ends, and Chapter 14, "Rolo Revisited," presents a final version of a phone directory program called rolo that is developed throughout the book.



    Chapter 15, "Interactive and Nonstandard Shell Features," discusses features of the shell that either are not formally part of the IEEE POSIX standard shell (but are available in most Unix and Linux shells) or are mainly used interactively instead of in programs.



    Appendix A, "Shell Summary," summarizes the features of the IEEE POSIX standard shell.



    Appendix B, "For More Information," lists references and resources, including the Web sites where different shells can be downloaded.



    The philosophy this book uses is to teach by example. Properly chosen examples do a far superior job at illustrating how a particular feature is used than ten times as many words. The old "A picture is worth…" adage seems to apply just as well to examples. You are encouraged to type in each example and test it on your system, for only by doing can you become adept at shell programming. You also should not be afraid to experiment. Try changing commands in the program examples to see the effect, or add different options or features to make the programs more useful or robust.



    At the end of most chapters you will find exercises. These can be used as assignments in a classroom environment or by yourself to test your progress.



    This book teaches the IEEE POSIX standard shell. Incompatibilities with earlier Bourne shell versions are noted in the text, and these tend to be minor.



    Acknowledgments from the first edition of this book: We'd like to thank Tony Iannino and Dick Fritz for editing the manuscript. We'd also like to thank Juliann Colvin for performing her usual wonders copy editing this book. Finally, we'd like to thank Teri Zak, our acquisitions editor, and posthumously Maureen Connelly, our production editor. These two were not only the best at what they did, but they also made working with them a real pleasure.



    For the first revised edition of this book, we'd like to acknowledge the contributions made by Steven Levy and Ann Baker, and we'd like to also thank the following people from Sams: Phil Kennedy, Wendy Ford, and Scott Arant.



    For the second revised edition of this book, we'd like to thank Kathryn Purdum, our acquisitions editor, Charlotte Clapp, our project editor, and Geneil Breeze, our copy editor.












       

       


      Chapter 6.  Exception Handlers









      Chapter 6. Exception Handlers


      It is a sad fact of life that most programmers never take the time to properly bullet-proof their programs. Instead, wishful thinking often reigns. Most of us find it hard enoughand more than enough workto simply write the code that implements the positive aspects of an application: maintaining customers, generating invoices, and so on. It is devilishly difficult, from both a psychological standpoint and a resources perspective, to focus on the negative: for example, what happens when the user presses the wrong key? If the database is unavailable, what should I do?


      As a result, we write applications that assume the best of all possible worlds, hoping that our programs are bug-free, that users will enter the correct data in the correct fashion, and that all systems (hardware and software) will always be a "go."


      Of course, harsh reality dictates that no matter how hard you try, there will always be one more bug in your application. And your users will somehow always find just the right sequence of keystrokes to make a form implode. The challenge is clear: either you spend the time up-front to properly debug and bulletproof your programs, or you fight an unending series of rear-guard battles, taking frantic calls from your users and putting out the fires.


      You know what you should do. Fortunately, PL/SQL offers a powerful and flexible way to trap and handle errors
      . It is entirely feasible within the PL/SQL language to build an application that fully protects the user and the database from errors.









        Section 8.4. Configuring the Servers







        8.4. Configuring the Servers

        Once the replication user is set up on both servers, you will
        need to add some lines to the MySQL configuration file on the master and on the slave server. Depending on the type of
        operating system, the configuration file will probably be
        called either my.cnf or my.ini.
        On Unix types of systems, the configuration file is usually located in the
        /etc directory. On Windows systems, it's usually located in
        c:\ or in c:\Windows. If the file doesn't exist on
        your system, you can create it. Using a plain text editor (e.g., vi or
        Notepad.exe)—one that won't add binary formatting—add
        the following lines to the configuration file of the master under the
        [mysqld] group heading:

        [mysqld]
        server-id = 1
        log-bin = /var/log/mysql/bin.log
        ...


        The server identification number is an arbitrary number used to
        identify the master server in the binary log and in communications with
        slave servers. Almost any whole number from 1 to 4294967295 is fine. Don't
        use 0, as that causes problems. If you don't assign a server number, the
        default server identification number of 1 will be used. The default is all
        right for the master, but a different one should be assigned to each
        slave. To keep log entries straight and avoid confusion in communications
        between servers, it is very important that each slave have a unique
        number.

        In the configuration file excerpt shown here, the line containing
        the log-bin option instructs MySQL to perform
        binary logging to the path and file given. The actual path
        and filename is mostly up to you. Just be sure that the directory exists
        and that the user mysql is the owner, or at least has
        permission to write to the directory. By default, if a path is not given,
        the server's data directory is assumed as the path for log files. To leave
        the defaults in place, give log-bin without the equals
        sign and without the file pathname. This example shows the default
        pathname. If you set the log file name to something else, keep the suffix
        .log as shown here. It will be replaced automatically
        with an index number (e.g., .000001) as new log files
        are created when the server is restarted or the logs are flushed.

        These two options are all that is required on the master. They can
        be put in the configuration file or given from the command line when
        starting the mysqld daemon each time. On the command
        line, add the required double dashes before each option and omit the
        spaces around the equals signs.

        For InnoDB tables, you may want to add the following lines to the master's
        configuration file:

        innodb_flush_log_at_trx_commit = 1
        sync-binlog = 1


        These lines resolve problems that can occur with transactions and
        binary logging.

        For the slave server, we will need to add several options to the
        slave's configuration file, reflecting the greater complexity and number
        of threads on the slave. You will have to provide a server identification
        number, information on connecting to the master server, and more log
        options. Add lines similar to the following to the slave's configuration
        file:

        [mysqld]
        server-id = 2

        log-bin = /var/log/mysql/bin.log
        log-bin-index = /var/log/mysql/log-bin.index
        log-error = /var/log/mysql/error.log

        relay-log = /var/log/mysql/relay.log
        relay-log-info-file = /var/log/mysql/relay-log.info
        relay-log-index = /var/log/mysql/relay-log.index

        slave-load-tmpdir = /var/log/mysql/
        skip-slave-start
        ...


        At the top, you can see the server identification number is set to
        2. The next stanzas set the logs and related index files. If these files
        don't exist when the slave is started, it will automatically create
        them.

        The second stanza starts binary logging like on the master server,
        but this time on the slave. This is the log that can be used to allow the
        master and the slave to reverse roles as mentioned earlier. The binary log index file (log-bin.index)
        records the name of the current binary log file to use. The
        log-error option establishes an error log. Any problems
        with replication will be recorded in this log.

        The third stanza defines the relay log that records each entry in
        the master server's binary log, along with related files mentioned
        earlier. The relay-log-info-file option names the file
        that records the most recent position in the master's binary log that the
        slave recorded for later execution (not the most recent statement actually
        executed by the slave), while the relay log index file in turn records the
        name of the current relay log file to use for replication.

        The slave-load-tmpdir option is necessary only if
        you expect the LOAD DATA INFILE statement to
        be executed on the server. This SQL statement is used to import data in
        bulk into the databases. The slave-load-tmpdir option
        specifies the temporary directory for those files. If you don't specify
        the option, the value of the tmpdir variable will be
        used. This relates to replication because the slave will log LOAD
        DATA INFILE
        activities to the log files with the prefix
        SQL_LOAD- in this directory. For security, you may not
        want those logs to be placed in a directory such as
        /tmp.

        The last option, skip-slave-start, prevents the
        slave from replicating until you are ready. The order and spacing of
        options, incidentally, are a matter of personal style.

        To set variables on the slave related to its connection with the
        master (e.g., the master's host address), it is recommended that you use
        the [click here] statement to set the values on the
        slave. You could provide the values in the configuration file. However,
        the slave will read the file only the first time you start up the slave
        for replication. Because the values are stored in the master.info file, MySQL just relies
        on that file during subsequent startups and ignores these options in the
        main MySQL configuration file. The only time it adjusts the
        master.info file contents is when you tell it to
        explicitly through a [click here] statement. You could
        edit the master.info file and
        other replication information files directly, but you might cause more
        problems in doing so. It's best to use the [click here]
        statement to make changes. Here is an example:

        CHANGE MASTER TO MASTER_HOST = 'master_host';
        CHANGE MASTER TO MASTER_PORT = 3306;
        CHANGE MASTER TO MASTER_USER = 'replicant';
        CHANGE MASTER TO MASTER_PASSWORD = 'my_pwd';


        This set of SQL statements provides information about the master
        server. The first statement gives
        the hostname (or the IP address) of the master. The next one provides the
        port for the connection. Port 3306 is the default port for MySQL, but
        another could be used for performance or security considerations. The next
        two lines set the username and password for logging into the master
        server. After you run these SQL statements, their values are stored in the
        master.info file and you shouldn't need to rerun the
        statements upon subsequent startups.

        At this point, the servers should be configured properly. Next, you
        will need to get the slave's data current by making a backup on the master
        server and copying it manually to the slave. This is described in the
        following section. If the master and slave are new servers and the master
        has no data yet, you can skip the next section and proceed to Section 8.6."








        Section 6.3.  System Tray Integration










        6.3. System Tray Integration


        Another common feature of instant messaging applications is integration into the system tray. Using this idea, we want Hyperbola to appear in the system tray as an icon representing the user's presence. This also allows Hyperbola to minimize to the system tray rather than continuing to be displayed in the task bar even though it is minimized. The tray items are also a popular location for adding actions related to your application. Figure 6-8 shows how this looks for Hyperbola.



        Figure 6-8. Context menu on the Hyperbola task tray item







        Tip



        If you are going to use the system tray, it is good practice to make its use optionalif every application put itself in the system tray, it would get cluttered. When it is enabled, it should be used to display important status information to the user and provide a quick access point for running frequent actions.


        Also, the system tray is not available on all platforms, so do not make it the focal point of your application's workflow. It should be used as an optional integration feature.




        In this section, we show you how to:


        • Add the Hyperbola icon to the task tray.

        • Allow Hyperbola to minimize to the task tray.

        • Add the About and Exit actions to the context menu of the task tray item.



        6.3.1. Obtaining a Display


        To get the system tray, you need a Display. A Display is an SWT object that represents the underlying graphics system. Typically, the Display is not available until the window has been created. Figure 6-9 shows the WorkbenchWindow lifecycle and highlights the earliest point, in postWindowOpen(), where the Display is available. So, the first time a window is opened, the WorkbenchWindowAdvisor can get the Display via the window's shell and set up the system tray for Hyperbola. At this point, the tray item is created and configured such that when its menu is shown, the ActionBarAdvisor populates the menu.



        Figure 6-9. How the ActionBarAdvisor contributes actions to the task item









        6.3.2. Creating the Tray Item


        The code snippet below from ApplicationWorkbenchWindowAdvisor shows how the system tray item is created and how it operates. First, the item is created and configured and then listeners are added to support showing the menu and minimizing into the tray item. After the tray item is set up, a menu listener is added to it. That way, when the tray item is right-clicked, a context menu appears and is populated by the ActionBarAdvisor. Some platforms do not have system trays and initTaskItem() may return null. In that case, the tray item is not created.


        org.eclipsercp.hyperbola/ApplicationWorkbenchWindowAdvisor
        public void postWindowOpen() {
        initStatusLine();
        final IWorkbenchWindow window = getWindowConfigurer().getWindow();
        trayItem = initTaskItem(window);
        if (trayItem != null) {
        hookPopupMenu(window);
        hookMinimize(window);
        }
        }

        private void hookMinimize(final IWorkbenchWindow window) {
        window.getShell().addShellListener(new ShellAdapter() {
        public void shellIconified(ShellEvent e) {
        window.getShell().setVisible(false);
        }
        });
        trayItem.addListener(SWT.DefaultSelection, new Listener() {
        public void handleEvent(Event event) {
        Shell shell = window.getShell();
        if (!shell.isVisible()) {
        shell.setVisible(true);
        window.getShell().setMinimized(false);
        }
        }
        });
        }

        private void hookPopupMenu(final IWorkbenchWindow window) {
        trayItem.addListener(SWT.MenuDetect, new Listener() {
        public void handleEvent(Event event) {
        MenuManager trayMenu = new MenuManager();
        Menu menu = trayMenu.createContextMenu(window.getShell());
        actionBarAdvisor.fillTrayItem(trayMenu);
        menu.setVisible(true);
        }
        });
        }

        private TrayItem initTaskItem(IWorkbenchWindow window) {
        final Tray tray = window.getShell().getDisplay().getSystemTray();
        if (tray == null)
        return null;
        TrayItem trayItem = new TrayItem(tray, SWT.NONE);
        trayImage = AbstractUIPlugin.imageDescriptorFromPlugin(
        "org.eclipsercp.hyperbola", IImageKeys.ONLINE).createImage();
        trayItem.setImage(trayImage);
        trayItem.setToolTipText("Hyperbola");
        return trayItem;
        }

        public void dispose() {
        if (trayImage != null) {
        trayImage.dispose();
        trayItem.dispose();
        }
        }


        Note



        The image and tray item area are saved as fields on the WorkbenchWindowAdvisor so that they can be deleted when the window is closed.




        Since the ActionBarAdvisor already manages all of Hyperbola's actions, it is a good place to put the method that fills the system tray item's menu. This also allows the tray item menu to reuse actions created in the ActionBarAdvisor. Add the following snippet to ApplicationActionBarAdvisor:


        org.eclipsercp.hyperbola/ApplicationActionBarAdvisor
        protected void fillTrayItem(IMenuManager trayItem) {
        trayItem.add(aboutAction);
        trayItem.add(exitAction);
        }


        A shell listener is added in the hookMinimize() method to the window so that the window is marked as hidden when minimized. This simulates minimizing the window into the task bar. When the window is invisible, the only indication that Hyperbola is running is the system tray icon.


        Another listener, also added in the hookMinimize() method, listens to the tray item to detect when it is selected. Selecting the task item is the cue that Hyperbola's window should be made visible if it had previously been minimized.


        After setting this up, run Hyperbola and look for the system tray icon. Right-click it and the context menu appears. Minimize Hyperbola and notice that Hyperbola is completely gone except for the task tray icon. Click the tray icon and Hyperbola reappears.













        Points to Remember

        Points to Remember



        • Don't let a player make a move until both he and his opponent are ready to receive a move. Otherwise, the game's synchronization will be affected.

        • Given the same input on two SWF instances of the same game, Flash may not calculate the exact same result twice, although the numbers will be very close to each other. In some cases, like 9-ball, rounding will help you avoid synchronization issues.

        • All of the possible collisions during a frame are calculated, stored, and sorted from earliest time to latest time . Then the script goes back and calculates the reaction for the first collision (lowest time). We run the collision-detection script again to see if there are any more collisions. This is done until there are no more collisions, or ten times�whichever comes first.

        • For speed optimization, we use two arrays to store the state of the balls�a moving array and a notMoving array. We then perform collision detection between every ball in the moving array and then between every ball in the moving array with the balls in the notMoving array. We do not check for collisions between balls in the notMoving array.

        • When the moving array is empty, the turn is over.




        The set Command








         

         










        The set Command



        The shell's set command is a dual-purpose command: it's used both to set various shell options as well as to reassign the positional parameters $1, $2, and so forth.



        The -x Option



        This option turns on trace mode in the shell. It does to the current shell what the command





        sh -x ctype a



        did for the execution of the ctype program in Chapter 8, "Decisions, Decisions." From the point that the





        set -x



        command is executed, all subsequently executed commands will be printed to standard error by the shell, after filename, variable, and command substitution and I/O redirection have been performed. The traced commands are preceded by plus signs.





        $ x=*

        $ set -x Set command trace option

        $ echo $x

        + echo add greetings lu rem rolo

        add greetings lu rem rolo

        $ cmd=wc

        + cmd=wc

        $ ls | $cmd -l

        + ls

        + wc -l

        5

        $



        You can turn off trace mode at any time simply by executing set with the +x option:





        $ set +x

        + set +x

        $ ls | wc �l

        5 Back to normal

        $



        You should note that the trace option is not passed down to subshells. But you can trace a subshell's execution either by running the shell with the -x option followed by the name of the program to be executed, as in





        sh -x rolo



        or you can insert a set -x command inside the file itself. In fact, you can insert any number of set -x and set +x commands inside your program to turn trace mode on and off as desired.



        set with No Arguments



        If you don't give any arguments to set, you'll get an alphabetized list of all the variables that exist in your environment, be they local or exported:





        $ set Show me all variables

        CDPATH=:/users/steve:/usr/spool

        EDITOR=/bin/vi

        HOME=/users/steve

        IFS=



        LOGNAME=steve

        MAIL=/usr/spool/mail/steve

        MAILCHECK=600

        PATH=/bin:/usr/bin:/users/steve/bin:.:

        PHONEBOOK=/users/steve/phonebook

        PS1=$

        PS2=>

        PWD=/users/steve/misc

        SHELL=/usr/bin/sh

        TERM=xterm

        TMOUT=0

        TZ=EST5EDT

        cmd=wc

        x=*

        $



        Using set to Reassign Positional Parameters



        There is no way to directly assign a value to a positional parameter; for example,





        1=100



        does not work. These parameters are initially set on execution of the shell program. The only way they may be changed is with the shift or the set commands. If words are given as arguments to set on the command line, those words will be assigned to the positional parameters $1, $2, and so forth. The previous values stored in the positional parameters will be lost forever. So





        set a b c



        assigns a to $1, b to $2, and c to $3. $# also gets set to 3.





        $ set one two three four

        $ echo $1:$2:$3:$4

        one:two:three:four

        $ echo $# This should be 4

        4

        $ echo $* What does this reference now?

        one two three four

        $ for arg; do echo $arg; done

        one

        two

        three

        four

        $



        So after execution of the set, everything seems to work consistently: $#, $*, and the for loop without a list.



        set is often used in this fashion to "parse" data read from a file or the terminal. Here's a program called words that counts the number of words typed on a line (using the shell's definition of a "word"):





        $ cat words

        #

        # Count words on a line

        #



        read line

        set $line

        echo $#

        $ words Run it

        Here's a line for you to count.

        7

        $



        The program stores the line read in the shell variable line and then executes the command





        set $line



        This causes each word stored in line to be assigned to the positional parameters. The variable $# is also set to the number of words assigned, which is the number of words on the line.



        The -- Option



        Try typing in a line to words that begins with a - and see what happens:





        $ words

        -1 + 5 = 4

        words: -1: bad option(s)

        $



        After the line was read and assigned to line, the command





        set $line



        was executed. After the shell did its substitution, the command line looked like this:





        set -1 + 5 = 4



        When set executed, it saw the - and thought that an option was being selected, thus explaining the error message.



        Another problem with words occurs if you give it a line consisting entirely of whitespace characters, or if the line is null:





        $ words

        Just Enter is pressed

        CDPATH=.:/users/steve:/usr/spool

        EDITOR=/bin/vi

        HOME=/users/steve

        IFS=



        LOGNAME=steve

        MAIL=/usr/spool/mail/steve

        MAILCHECK=600

        PATH=/bin:/usr/bin:/users/steve/bin:.:

        PHONEBOOK=/users/steve/phonebook

        PS1=$

        PS2=>

        PWD=/users/steve/misc

        SHELL=/usr/bin/sh

        TERM=xterm

        TMOUT=0

        TZ=EST5EDT

        cmd=wc

        x=*

        0

        $



        To protect against both of these problems occurring, you can use the -- option to set. This tells set not to interpret any subsequent arguments on the command line as options. It also prevents set from displaying all your variables if no other arguments follow, as was the case when you typed a null line.



        So the set command in words should be changed to read





        set -- $line



        With the addition of a while loop and some integer arithmetic, the words program can be easily modified to count the total number of words on standard input, giving you your own version of wc -w:





        $ cat words

        #

        # Count all of the words on standard input

        #



        count=0

        while read line

        do

        set -- $line

        count=$(( count + $# ))

        done



        echo $count

        $



        After each line is read, the set command is executed to take advantage of the fact that $# will be assigned the number of words on the line. The -- option is supplied to set just in case any of the lines read begins with a - or consists entirely of whitespace characters.



        The value of $# is then added into the variable count, and the next line is read. When the loop is exited, the value of count is displayed. This represents the total number of words read.





        $ words < /etc/passwd

        567

        $ wc -w < /etc/passwd Check against wc

        567

        $



        (Our version is a lot slower than wc because the latter is written in C.)



        Here's a quick way to count the number of files in your directory:[1]



        [1] This technique may not work on very large directories because you may exceed the limit on the length of the command line (the precise length varies between Unix systems). Working with such directories may cause problems when using filename substitution in other commands as well, such as echo * or for file in *.





        $ set *

        $ echo $#

        8

        $



        This is much faster than





        ls | wc -l



        because the first method uses only shell built-in commands. In general, your shell programs run much faster if you try to get as much done as you can using the shell's built-in commands.



        Other Options to set



        set accepts several other options, each of them enabled by preceding the option with a -, and disabled by preceding it with a +. The -x option that we have described here is perhaps the most commonly used. Others are summarized in Table A.9 in Appendix A.












           

           


          Section 21.2. Internet Requirements







          21.2. Internet Requirements

          There are a couple of important requirements when supporting a web-based game from within the browser. The first is the Internet communication. Will your game require broadband-type speeds to function correctly, or will any Internet connection speeds suffice? Only you can answer this question. However, there is a factor that could narrow down the answer. The genre of game can dictate the types of communication required: strategy-based games would require much less bandwidth back and forth between client and server than an FPS game would. So, look at the type of game you plan to build, and think about the connection requirements you think you will need based on the amount of client/server communication necessary.

          The more important Internet requirement is what the game's platform will be. This requirement boils down to two choices: one of an assortment of plug-ins, or JavaScript with Ajax.

          21.2.1. Plug-ins

          There are few choices when it comes to plug-ins for browsers, and I am going to throw applets into this definition as well. Each type of plug-in has its advantages, of course, and the biggest disadvantage with all plug-ins is that they require a user to download software for them to work. The plug-ins that I will focus on are:

          • Flash

          • Shockwave

          • Java applets

          21.2.1.1. Flash

          Perhaps the most popular plug-in for browsers today is Flash. This could be because its interoperability within a browser has become nearly seamless. Whole sites are built using Flash to create all functionality and content. Media sites, especially those for movies, use Flash to allow more user interactivity.

          Macromedia released Flash in 1996, after acquiring the technology from FutureWave Software. Adobe acquired Macromedia and its software in December 2005, and the current version of Flash is Flash CS3. Originally developed as a multimedia platform for the World Wide Web, Flash has grown and become a tool for user interaction, as well as a platform for games and complicated presentation that is much more difficult to produce using XHTML, CSS, and JavaScript. Flash uses the ActionScript programming language, which has the same syntax as JavaScript, as it is an implementation of ECMAScript. ActionScript allows a developer to interact with all of the objects created within Flash, as well as communicate with a server.

          Flash is a small browser download, and according to Adobe's web site, it's available on nearly 99 percent of Internet-enabled desktops.[10] This makes it a good candidate for game development, and an alternative for web developers who have JavaScript experience. In fact, Ajax can be implemented within a Flash platform, as Flash uses ActionScript behind the scenes. ActionScript is a close cousin to JavaScript, and it follows ECMAScript more closely. Flash can be a good alternative for more complicated games in which you still wish to implement Ajax for communication between the client and the server.

          [10] * Flash Player Statistics from Adobe Systems (http://www.adobe.com/products/player_census/flashplayer/)

          21.2.1.2. Shockwave

          Macromedia Director was introduced before Flash. It was followed shortly after by Shockwave, which Macromedia introduced around the same time as Flash, and although both are from the same company, Shockwave was a direct competitor to Flash. Shockwave was geared more toward game development from the start, having a more powerful graphics engine. This made it a larger plug-in, however, and its size kept it from enjoying the same widespread adoption as Flash. Shockwave's other limitation is that it is not compatible with all operating systems—in particular, Linux.

          As noted earlier, Adobe bought Macromedia and all its products in 2005. The current version of Shockwave is 10.2.

          Today's Shockwave is well suited to games, as it renders faster, includes hardware-accelerated 3D images, and offers blend modes for layered display of graphical assets. This allows it to build much more graphically rich games, something Flash cannot do. The trade-off is its lack of support for operating systems other than Windows and Mac OS X, its larger initial download size, and its slower startup time in browsers.

          21.2.1.3. Java applets

          Java applets are specialized Java programs intended to run within browsers as plug-ins. The browser's operating system must have a compatible version of the Java Runtime Environment (JRE) for applets to function correctly. The most recent version of the JRE at the time of this writing is JRE 6 Update 2.

          You create an applet by extending a new class for the program with the Applet class. Any other classes supported by the JRE on the client can be used in the applet. The advantage is that you can build a pretty robust gaming application to run in the browser. Just remember that the larger and more complex the application, the larger the size of the file that the browser must download.

          Java applets can be well suited for games, as they have Java's graphing capabilities and the ability to handle network connections not available using Ajax. The only thing to remember is that the user must have the JRE associated with your build of the applet. This download may take a very long time, though, if the user doesn't have a compatible version of the JRE already installed. This may turn people away from using your gaming applet.

          21.2.2. Game Development with Ajax

          Ajax solutions to browser-based game programming have the advantage of complete browser reliance without the need for any additional software. This can improve startup times and give a completely seamless look within the browser. The real advantage over plug-ins for game programming is that there is nothing else new to learn.

          An Ajax solution for game development must rely on XHTML, CSS, JavaScript, and XML/JavaScript Object Notation (JSON). Do these skills sound familiar? They ought to, as they are the skills that every developer should possess. What's more, they are the skills that you either knew before reading this book, or hopefully have gained by now. This can be appealing to a developer who has always wanted to program a game, but has lacked the skills to create one on a traditional platform (i.e., the desktop).

          So that you can better understand the parts of a typical game, I will break them down in a modular manner, as each component of the game will need its own Ajax functionality. The parts that we will be interested in are:

          • Character animation

          • Collisions

          • Input

          Putting all of this together will result in a rough game client that can communicate with a server and handle the basic functionality most games need.








          Section 8.5. Device Drivers and the GPL











          8.5. Device Drivers and the GPL


          Much discussion and debate surrounds the issue of device drivers and how the terms of the GNU Public License apply to device drivers. The first test is well understood: If your device driver (or any software, for that matter) is based, even in part, on existing GPL software, it is called a derived work. For example, if you start with a current Linux device driver and modify it to suit your needs, this is certainly considered a derived work, and you are obligated to license this modified device driver under the terms of the GPL, observing all its requirements.


          This is where the debate comes in. First, the disclaimer. This is not a legal opinion, and the author is not a lawyer. Some of these concepts have not been tested in court as of this writing. The prevailing opinion of the legal and open source communities is that if a work can be proven [8] to be independently derived, and a given device driver does not assume "intimate knowledge" of the Linux kernel, the developers are free to license it in any way they see fit. If modifications are made to the kernel to accommodate a special need of the driver, it is considered a derived work and, therefore, is subject to the GPL.

          [8] This practice is not unique to open source. Copyright and patent infringement is an ongoing concern for all developers.


          A large and growing body of information exists in the open source community regarding these issues. It seems likely that, at some point in the future, these concepts will be tested in a court of law and precedent will be established. How long that might take is anyone's guess. If you are interested in gaining a better understanding of the legal issues surrounding Linux and open source, you might enjoy www.open-bar.org.












          22.1 Classes, objects and constructors



          [ Team LiB ]










          22.1 Classes, objects and constructors


          In object-oriented programming (OOP) we use a special kind of data structure called a class. A class is quite similar to an ordinary C struct. Particular instances of some class type are called objects. As well as having members which are data fields, a class also has members that are functions. If SomeClass
          were the name of a class and SomeFunction(…)
          happened to be the name of one of the class's member functions, then it would make sense to have two lines like:



          SomeClass K;
          K.SomeFunction(…);

          The first line says that K is an object of the class type SomeClass. You can also say that 'K is a SomeClass
          object' or you can say 'K is an instance of the SomeClass
          class.' Supposing K has a bunch of data fields, what gets put into these fields when you make the 'SomeClass
          K;' declaration? It turns out that when you define any class you also define a constructor function which serves to initialize new members of the class.


          The second line says to let the object K call the class member function SomeFunction
          . SomeFunction
          might act on K's data members, do something to the SomeFunction
          arguments, possibly return a value, or do any combination of these three actions.


          Sometimes a class's constructor function takes arguments. MFC includes, for instance, a CPoint
          class which has a constructor that can take two arguments, one for each of the point's coordinates. In this case you might have a declaration of the following form, creating a CPoint
          object with coordinates 3 and 7.



          CPoint cpdot(3,7);

          It is allowable for a class to have several kinds of constructors. The constructors can be thought of as functions that you can use to create objects of the class type.


          We need to mention still another way of initializing an object. Suppose that you want to have, say, a global SomeClass
          variable, but that you won't know what numbers to initialize the SomeClass
          with until well into your code. One approach that you could use would be to use a global pointer to a SomeClass.



          SomeClass *sc_ptr;

          When you declare a pointer to a class like this, no initialization happens. No constructor gets called. Depending on the context, a junk value like CDCDCDCD0x
          or the NULL (zero) value gets put into the pointer, and no effort is made to create a legitimate class object for the pointer to point to.


          The way that you make *sc_ptr correspond to a legitimate object is that later, down in the code when you find out what parameters, say x and y, you want to give to the SomeClass
          constructor, you put a line like the following.



          sc_ptr = new SomeClass(x, y);

          In C++, new
          is a special operator which (a) allocates space for a new object of the specified class, (b) calls the class's constructor on the indicated arguments in order to initialize the object, and then (c) returns a pointer to this newly constructed object.


          When you create an object of a given class type the constructor gets called; the constructor encapsulates the initialization and the allocation code. You can 'create' an object either by declaring it as a variable or by using the new
          operator to create an object and return a pointer to it.


          Note that in Java, all class instance variables are of the pointer type. Java doesn't explicitly use the *
          symbol to indicate pointers, but the variables for objects are indeed pointer variables. This is why in Java you need to call new
          whenever you want to initialize an object variable. Something that makes the situation a little confusing is that Java also has primitive type variables such as integers that are not pointers.


          Saying the same thing again in a different way:



          in the Java language every class instance is a pointer.



          Sometimes beginning Java programmers have the impression that 'Java has no pointers.' But exactly the opposite is true. Everything in Java is a pointer, other than primitives like int
          and char. The Java compiler will remind you of this if you try and compile code with a line like SomeClass nogood. You'll get an error message saying something about a NULL pointer. Java requires you to rewrite the offending line as SomeClass goodnow = new SomeClass().






            [ Team LiB ]



            How This Book Is Organized

            Team-Fly
             

             

            Oracle® PL/SQL® Interactive Workbook, Second Edition
            By
            Benjamin Rosenzweig, Elena Silvestrova
            Table of Contents
            Introduction



            How This Book Is Organized


            The intent of this workbook is to teach you about Oracle PL/SQL by presenting you with a series of challenges followed by detailed solutions to those challenges. The basic structure of each chapter is as follows:


            Chapter

            Lab

            Exercises

            Exercise Answers (with detailed discussion)

            Self-Review Questions

            Lab . . .

            Test Your Thinking Questions


            Each chapter contains interactive labs that introduce topics about Oracle PL/SQL. The topics are discussed briefly and then explored though exercises, which are the heart of each lab.


            Each exercise consists of a series of steps that you will follow to perform a specific task, along with questions that are designed to help you discover the important things about PL/SQL programming on your own. The answers to these questions are given at the end of the Exercises, along with more in-depth discussion of the concepts explored.


            The exercises are not meant to be closed-book quizzes to test your knowledge. On the contrary, they are intended to act as your guide and walk you through a task. You are encouraged to flip back and forth from the exercise question section to the exercise answer section so that, if need be, you can read the answers and discussions as you go along.


            At the end of each lab is a series of multiple-choice self-review questions. These are meant to be closed-book quizzes to test how well you understood the lab material. The answers to these questions appear in Appendix A.


            Finally, at the end of each chapter you will find a Test Your Thinking section, which consists of a series of projects designed to solidify all of the skills you have learned in the chapter. If you have successfully completed all of the labs in the chapter, you should be able to tackle these projects with few problems. You will find guidance and/or solutions to these in Appendix D and at the companion Web site.



              Team-Fly
               

               
              Top
               


              Recipe 21.15. Creating a GUI Application with Ruby/GTK










              Recipe 21.15. Creating a GUI Application with Ruby/GTK



              Problem


              You want to write a GUI application that uses the
              GTK widget library, perhaps so you can integrate it with the Gnome desktop environment.




              Solution


              Use the Ruby bindings to Gnome's
              GTK widget library, available as a third-party download. Here's a simple Ruby/GTK application (Figure 21-5).



              #!/usr/bin/ruby -w
              #
              gtktrout.rb
              require 'gtk2'

              Gtk.init
              window = Gtk::Window.new 'Tiny Ruby/GTK Application'
              label = Gtk::Label.new 'You are a trout!'
              window.add label
              window.signal_connect('destroy') { Gtk.main_quit }
              window.show_all
              Gtk.main




              Figure 21-5. You are a GTK trout






              Discussion


              Gnome is one of the two most popular Unix desktop suites. The Ruby-Gnome2 project provides and documents Ruby bindings to Gnome's vast array of C libraries. You can write Ruby applications that fully integrate with the Gnome desktop, but in this recipe I'm going to focus on the basics of the Gnome GUI library GTK.


              Although the details are different, the sample program above is basically the same as it would be with Tk (Recipe 21.12) or the wxRuby library (Recipe 21.13). You create two widgets (a window and a label), attach the label to the window, and tell the GUI library to display the window. As with Tk and wxRuby, the application goes into a display loop, capturing user events like mouse clicks.


              The sample program won't actually respond to any user events, though, so let's create a Ruby/GTK version of the stopwatch program seen in previous GUI recipes.


              The core methods, the ones that actually implement the stopwatch, are basically the same as the corresponding methods in the Tk and wxRuby recipes. Since GTK doesn't have a timer widget, I've implemented a simple timer as a separate thread. The other point of interest is the HTML-like markup that GTK uses to customize the font size and weight of the stopwatch text.



              #!/usr/bin/ruby -w
              # gtk_stopwatch.rb
              require 'gtk2'

              class Stopwatch

              LABEL_MARKUP = '<span font_desc="16" weight="bold">%s</span>'

              def start
              @accumulated ||= 0
              @elapsed = 0
              @start = Time.now

              @mybutton.label = 'Stop'
              set_button_handler('clicked') { stop }
              @timer_stopped = false
              @timer = Thread.new do
              until @timer_stopped do
              sleep(0.1)
              tick unless @timer_stopped
              end
              end
              end

              def stop
              @mybutton.label = 'Start'
              set_button_handler('clicked') { start }
              @timer_stopped = true
              @accumulated += @elapsed
              end

              def reset
              stop
              @accumulated, @elapsed = 0, 0
              @mylabel.set_markup(LABEL_MARKUP % '00:00:00.0')
              end

              def tick
              @elapsed = Time.now - @start
              time = @accumulated + @elapsed
              h = sprintf('%02i', (time.to_i / 3600))
              m = sprintf('%02i', ((time.to_i % 3600) / 60))
              s = sprintf('%02i', (time.to_i % 60))
              mt = sprintf('%1i', ((time - time.to_i)*10).to_i)
              @mylabel.set_markup(LABEL_MARKUP % "#{h}:#{m}:#{s}:#{mt}")
              end



              Now begins the GUI setup. Ruby uses VBox and HBox objects to pack widgets into the display area. The stopwatch application will give its main window a single VBox containing three widgets arranged from top to bottom: a menu bar, a label (displaying the stopwatch time), and a button (to start and stop the stopwatch):



              def initialize

              Gtk.init
              root = Gtk::Window.new('GTK Stopwatch')

              accel_group = Gtk::AccelGroup.new
              root.add_accel_group(accel_group)
              root.set_border_width 0

              box = Gtk::VBox.new(false, 0)
              root.add(box)



              The program's menu bar consists of many nested MenuBar, Menu, and MenuItem objects. Rather than create these objects ourselves, we define the parameters of our menu bar in a nested array, and pass it into an ItemFactory object:



              menu_factory =
              Gtk::ItemFactory.new(Gtk::ItemFactory::TYPE_MENU_BAR,
              '<main>', nil)
              menu_spec = [
              ['/_Program'],
              ['/Program/_Start', '<Item>', nil, nil, lambda { start } ],
              ['/Program/S_top', '<Item>', nil, nil, lambda { stop } ],
              ['/Program/_Exit', '<Item>', nil, nil,
              lambda { Gtk.main_quit } ],
              ['/_Reset'],
              ['/Reset/_Reset Stopwatch', '<Item>', nil, nil,
              lambda { reset } ]
              ]
              menu_factory.create_items(menu_spec)
              menu_root = menu_factory.get_widget('<main>')
              box.pack_start(menu_root)



              The label and the button are pretty simple: just define them and pack them into the VBox:



              @mylabel = Gtk::Label.new
              @mylabel.set_markup(LABEL_MARKUP % '00:00:00.0')
              box.pack_start(@mylabel)

              @mybutton = Gtk::Button.new('Start')
              set_button_handler('clicked') { start }
              box.pack_start(@mybutton)

              root.signal_connect('destroy') { Gtk.main_quit }
              root.show_all

              Gtk.main
              end



              I've been calling a nonexistent method Stopwatch#set_button_handler whenever I want to modify the code that runs when the user clicks the button. I close out the Stopwatch class by defining that method (Figure 21-6):



              def set_button_handler(event, &block)
              @mybutton.signal_handler_disconnect(@mybutton_handler) if @mybutton_handler
              @mybutton_handler = @mybutton.signal_connect(event, &block)
              end
              end

              Stopwatch.new



              In the Tk recipe, I simply called a button's command method whenever I needed to change the code block that runs when the user clicks the button. So why this set_ button_handler code? Why not just call signal_connect whenever I need to change what the button does here? I can't do that because GTK lets you associate multiple code blocks with a single event. This doesn't usually come up, but it's a problem here because I'm changing the function of a button.



              Figure 21-6. The GTK stopwatch






              If the button is set up to call start when you click it, and you call signal_ connect('clicked',proc { stop }), then clicking on the button will call start and then call stop. You've added a second code block to the "clicked" event, when what you want is to replace the old "clicked" code with the new code. To avoid this problem, set_button_handler removes any old handler from the button before installing the new handler. The set_button_handler method tracks the internal ID of the newly installed handler, so that it can be removed if the user clicks the button yet again.




              See Also


              • You can download the Ruby bindings to GTK from the project homepage (http://ruby-gnome2.sourceforge.jp/); the GTK homepage itself is at http://www.gtk.org; Debian GNU/Linux users can install the libgtk2-ruby package

              • The Ruby GTK bindings are documented on the Ruby-GNOME2 Wiki at http://ruby-gnome2.sourceforge.jp/hiki.cgi?Ruby%2FGTK; there's also a tutorial at http://ruby-gnome2.sourceforge.jp/hiki.cgi?tut-gtk

              • Don't confuse the Ruby-GNOME2 project with its predecessor, Ruby-GNOME; the documentation for the older project is still online and will mislead you if you go to the wrong web site













              16.1. Selecting the Kind of Loop










               < Free Open Study > 







              16.1. Selecting the Kind of Loop



              In most languages, you'll use a few kinds of loops:



              • The counted loop is performed a specific number of times, perhaps one time for each employee.

              • The continuously evaluated loop doesn't know ahead of time how many times it will be executed and tests whether it has finished on each iteration. For example, it runs while money remains, until the user selects quit, or until it encounters an error.

              • The endless loop executes forever once it has started. It's the kind you find in embedded systems such as pacemakers, microwave ovens, and cruise controls.

              • The iterator loop performs its action once for each element in a container class.



              The kinds of loops are differentiated first by flexibility�whether the loop executes a specified number of times or whether it tests for completion on each iteration.



              The kinds of loops are also differentiated by the location of the test for completion. You can put the test at the beginning, the middle, or the end of the loop. This characteristic tells you whether the loop executes at least once. If the loop is tested at the beginning, its body isn't necessarily executed. If the loop is tested at the end, its body is executed at least once. If the loop is tested in the middle, the part of the loop that precedes the test is executed at least once, but the part of the loop that follows the test isn't necessarily executed at all.



              Flexibility and the location of the test determine the kind of loop to choose as a control structure. Table 16-1 shows the kinds of loops in several languages and describes each loop's flexibility and test location.



              Table 16-1. The Kinds of Loops

              Language

              Kind of Loop

              Flexibility

              Test Location

              Visual Basic

              For-Next

              rigid

              beginning

               

              While-Wend

              flexible

              beginning

               

              Do-Loop-While

              flexible

              beginning or end

               

              For-Each

              rigid

              beginning

              C, C++, C#, Java

              for

              flexible

              beginning

               

              while

              flexible

              beginning

               

              do-while

              flexible

              end

               

              foreach[*]

              rigid

              beginning


              [*] Available only in C#. Planned for other languages, including Java, at the time of this writing.





              When to Use a while Loop



              Novice programmers sometimes think that a while loop is continuously evaluated and that it terminates the instant the while condition becomes false, regardless of which statement in the loop is being executed (Curtis et al. 1986). Although it's not quite that flexible, a while loop is a flexible loop choice. If you don't know ahead of time exactly how many times you'll want the loop to iterate, use a while loop. Contrary to what some novices think, the test for the loop exit is performed only once each time through the loop, and the main issue with respect to while loops is deciding whether to test at the beginning or the end of the loop.





              Loop with Test at the Beginning


              For a loop that tests at the beginning, you can use a while loop in C++, C#, Java, Visual Basic, and most other languages. You can emulate a while loop in other languages.





              Loop with Test at the End


              You might occasionally have a situation in which you want a flexible loop, but the loop needs to execute at least one time. In such a case, you can use a while loop that is tested at its end. You can use do-while in C++, C#, and Java, Do-Loop-While in Visual Basic, or you can emulate end-tested loops in other languages.





              When to Use a Loop-With-Exit Loop



              A loop-with-exit loop is a loop in which the exit condition appears in the middle of the loop rather than at the beginning or at the end. The loop-with-exit loop is available explicitly in Visual Basic, and you can emulate it with the structured constructs while and break in C++, C, and Java or with gotos in other languages.





              Normal Loop-With-Exit Loops


              A loop-with-exit loop usually consists of the loop beginning, the loop body (including an exit condition), and the loop end, as in this Visual Basic example:





              Visual Basic Example of a Generic Loop-With-Exit Loop










              Do

              ... <-- 1

              If ( some exit condition ) Then Exit Do

              ... <-- 2

              Loop







              (1)Statements.

              (2)More statements.





              The typical use of a loop-with-exit loop is for the case in which testing at the beginning or at the end of the loop requires coding a loop-and-a-half. Here's a C++ example of a case that warrants a loop-with-exit loop but doesn't use one:





              C++ Example of Duplicated Code That Will Break Down Under Maintenance










              // Compute scores and ratings.

              score = 0;

              GetNextRating( &ratingIncrement ); <-- 1

              rating = rating + ratingIncrement; <-- 1

              while ( ( score < targetScore ) && ( ratingIncrement != 0 ) ) {

              GetNextScore( &scoreIncrement );

              score = score + scoreIncrement;

              GetNextRating( &ratingIncrement ); <-- 2

              rating = rating + ratingIncrement; <-- 2

              }







              (1)These lines appear here.

              (2)…and are repeated here.





              The two lines of code at the top of the example are repeated in the last two lines of code of the while loop. During modification, you can easily forget to keep the two sets of lines parallel. Another programmer modifying the code probably won't even realize that the two sets of lines are supposed to be modified in parallel. Either way, the result will be errors arising from incomplete modifications. Here's how you can rewrite the code more clearly:





              C++ Example of a Loop-With-Exit Loop That's Easier to Maintain










              // Compute scores and ratings. The code uses an infinite loop

              // and a break statement to emulate a loop-with-exit loop.

              score = 0;

              while ( true ) {

              GetNextRating( &ratingIncrement );

              rating = rating + ratingIncrement;



              if ( !( ( score < targetScore ) && ( ratingIncrement != 0 ) ) ) { <-- 1

              break;

              }



              GetNextScore( &scoreIncrement );

              score = score + scoreIncrement;

              }







              (1)This is the loop-exit condition (and now it could be simplified using DeMorgan's Theorems, described in Section 19.1).





              Here's how the same code is written in Visual Basic:





              Visual Basic Example of a Loop-With-Exit Loop




              ' Compute scores and ratings

              score = 0

              Do

              GetNextRating( ratingIncrement )

              rating = rating + ratingIncrement



              If ( not ( score < targetScore and ratingIncrement <> 0 ) ) Then Exit Do



              GetNextScore( ScoreIncrement )

              score = score + scoreIncrement

              Loop





              Consider these finer points when you use this kind of loop:



              Put all the exit conditions in one place. Spreading them around practically guarantees that one exit condition or another will be overlooked during debugging, modification, or testing.



              Cross-Reference





              Details on exit conditions are presented later in this chapter. For details on using comments with loops, see "Commenting Control Structures" in Section 32.5.




              Use comments for clarification. If you use the loop-with-exit loop technique in a language that doesn't support it directly, use comments to make what you're doing clear.



              The loop-with-exit loop is a one-entry, one-exit, structured control construct, and it is the preferred kind of loop control (Software Productivity Consortium 1989). It has been shown to be easier to understand than other kinds of loops. A study of student programmers compared this kind of loop with those that exited at either the top or the bottom (Soloway, Bonar, and Ehrlich 1983). Students scored 25 percent higher on a test of comprehension when loop-with-exit loops were used, and the authors of the study concluded that the loop-with-exit structure more closely models the way people think about iterative control than other loop structures do.




              In common practice, the loop-with-exit loop isn't widely used yet. The jury is still locked in a smoky room arguing about whether it's a good practice for production code. Until the jury is in, the loop-with-exit loop is a good technique to have in your programmer's toolbox�as long as you use it carefully.





              Abnormal Loop-With-Exit Loops


              Another kind of loop-with-exit loop that's used to avoid a loop-and-a-half is shown here:



              C++ Example of Entering the Middle of a Loop with a goto---Bad Practice







              goto Start;

              while ( expression ) {

              // do something

              ...



              Start:



              // do something else

              ...

              }






              At first glance, this seems to be similar to the previous loop-with-exit examples. It's used in simulations in which // do something doesn't need to be executed at the first pass through the loop but // do something else does. It's a one-in, one-out control construct: the only way into the loop is through the goto at the top, and the only way out of the loop is through the while test. This approach has two problems: it uses a goto, and it's unusual enough to be confusing.



              In C++, you can accomplish the same effect without using a goto, as demonstrated in the following example. If the language you're using doesn't support a break command, you can emulate one with a goto.





              C++ Example of Code Rewritten Without a goto�Better Practice










              while ( true ) {

              // do something else <-- 1

              ...



              if ( !( expression ) ) {

              break;

              }

              // do something

              ...

              }







              (1)The blocks before and after the break have been switched.









              When to Use a for Loop



              A for loop is a good choice when you need a loop that executes a specified number of times. You can use for in C++, C, Java, Visual Basic, and most other languages.



              Further Reading





              For more good guidelines on using for loops, see Writing Solid Code (Maguire 1993).




              Use for loops for simple activities that don't require internal loop controls. Use them when the loop control involves simple increments or simple decrements, such as iterating through the elements in a container. The point of a for loop is that you set it up at the top of the loop and then forget about it. You don't have to do anything inside the loop to control it. If you have a condition under which execution has to jump out of a loop, use a while loop instead.



              Likewise, don't explicitly change the index value of a for loop to force it to terminate. Use a while loop instead. The for loop is for simple uses. Most complicated looping tasks are better handled by a while loop.





              When to Use a foreach Loop



              The foreach loop or its equivalent (foreach in C#, For-Each in Visual Basic, for-in in Python) is useful for performing an operation on each member of an array or other container. It has the advantage of eliminating loop-housekeeping arithmetic and therefore eliminating any chance of errors in the loop-housekeeping arithmetic. Here's an example of this kind of loop:





              C# Example of a foreach Loop




              int [] fibonacciSequence = new int [] { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 };

              int oddFibonacciNumbers = 0;

              int evenFibonacciNumbers = 0;



              // count the number of odd and even numbers in a Fibonacci sequence

              foreach ( int fibonacciNumber in fibonacciSequence ) {

              if ( fibonacciNumber % 2 ) == 0 ) {

              evenFibonacciNumbers++;

              }

              else {

              oddFibonacciNumbers++;

              }

              }



              Console.WriteLine( "Found {0} odd numbers and {1} even numbers.",

              oddFibonacciNumbers, evenFibonacciNumbers );














                 < Free Open Study >