goto considered essential

new topic     » topic index » view thread      » older message » newer message

Consider the following program fragment, which copies one text file into
another text file:

    sequence cmd_args
    sequence cmd_line_words
    sequence input_file_name
    integer  input_file_nr
    object   line
    sequence output_file_name
    integer  output_file_nr

    cmd_line_words = command_line ( )
    if length ( cmd_line_words ) != 4 then
        Printf ( "Exactly two arguments expected -- %d supplied.\n",
            { length ( cmd_line_words ) - 2 } )
    else
        cmd_args = cmd_line_words [ 3..4 ]
        input_file_name = cmd_args [ 1 ]
        input_file_nr = open ( input_file_name, "r" )
        if input_file_nr = -1 then
            Printf ( "Can't open input file %s.\n",
                { input_file_name } )
        else
            output_file_name = cmd_args [ 2 ]
            output_file_nr = open ( output_file_name, "w" )
            if output_file_nr = -1 then
                Printf ( "Can't open output file %s.\n",
                    { output_file_name } )
            else
                while 1 do
                    line = gets ( input_file_nr )
                    if atom ( line ) then
                        exit
                    end if
                    puts ( output_file_nr, line )
                end while
                Printf ( "%s copied to %s.\n",
                    { input_file_name, output_file_name } )
            end if
        end if
    end if

Without a goto statement, or something like it, we have the creeping margin
problem.  In production code, with many error checks in the main logic, this
can make code very hard to understand.  With a goto, we have

    cmd_line_words = command_line ( )
    if length ( cmd_line_words ) != 4 then
        goto arg_count_is_wrong
    end if
    cmd_args = cmd_line_words [ 3..4 ]
    input_file_name = cmd_args [ 1 ]
    input_file_nr = open ( input_file_name, "r" )
    if input_file_nr = -1 then
        goto cant_open_input_file
    end if
    output_file_name = cmd_args [ 2 ]
    output_file_nr = open ( output_file_name, "w" )
    if output_file_nr = -1 then
        goto cant_open_output_file
    end if
    while 1 do
        line = gets ( input_file_nr )
        if atom ( line ) then
            exit
        end if
        puts ( output_file_nr, line )
    end while
    Printf ( "%s copied to %s.\n",
        { input_file_name, output_file_name } )
    goto halt

    arg_count_is_wrong:
        Printf ( "Exactly two arguments expected -- %d supplied.\n",
            { length ( cmd_line_words ) - 2 } )
        goto halt
    cant_open_input_file:
        Printf ( "Can't open input file %s.\n", { input_file_name } )
        goto halt
    cant_open_output_file:
        Printf ( "Can't open output file %s.\n", { output_file_name } )
        goto halt
    halt:

Here, the main (non-error) logic is much more apparent.  But what, you ask,
is then to prevent evil programmers from generating spaghetti code? Well,
nothing.  So perhaps a more constrained construct would be better.  In the
spirit of Ada exceptions, we might try something like this:

    --
    -- Function/procedure body or main program starts here.
    --
    cmd_line_words = command_line ( )
    exception arg_count_is_wrong if length ( cmd_line_words ) != 4
    cmd_args = cmd_line_words [ 3..4 ]
    input_file_name = cmd_args [ 1 ]
    input_file_nr = open ( input_file_name, "r" )
    exception cant_open_input_file if input_file_nr = -1
    output_file_name = cmd_args [ 2 ]
    output_file_nr = open ( output_file_name, "w" )
    exception cant_open_output_file if output_file_nr = -1
    while 1 do
        line = gets ( input_file_nr )
        exit if atom ( line )
        puts ( output_file_nr, line )
    end while
    Printf ( "%s has been copied to %s.\n",
        { input_file_name, output_file_name } )
    --
    -- Normal function/procedure return or program termination occurs here.
    -- Exception handlers follow function/procedure body or main program.
    --
    when arg_count_is_wrong do
        Printf ( "Exactly two arguments expected -- %d supplied.\n",
            { length ( cmd_line_words ) - 2 } )
        -- implicit return or halt here
    when cant_open_input_file do
        Printf ( "Can't open input file %s.\n", { input_file_name } )
        -- implicit return or halt here
    when cant_open_output_file do
        Printf ( "Can't open output file %s.\n", { output_file_name } )
        -- implicit return or halt here
    --
    -- Function/procedure body or main program source code ends here.
    --

The main logic is really obvious here.  Not only have we eliminated the
unconstrained goto, but we have reduced the number of lines per exception
check from three to one, thus reducing the visual noise that these checks
introduce into the main logic.  (Also, note the Ada-like conditional exit
statement.)

For me, some such capability is necessary in any programming language that
is to be used to write large production-quality programs. I make these
points because I understand that a major new release of Euphoria might be
in the works, and so this might be a good time to consider new features.

What do you think?

Tom Dailey

new topic     » topic index » view thread      » older message » newer message

Search



Quick Links

User menu

Not signed in.

Misc Menu