16. Práticas e recursos a evitar

16. Práticas e recursos a evitar

Toda linguagem de programação oferece recursos que, se mal utilizados, podem comprometer a qualidade do código e a facilidade de manutenções futuras. E isso é mais verdade ainda numa linguagem como o COBOL que existe há décadas e está em constante evolução.

Alguns recursos que eram úteis nos anos 1960 e 1970 para superar limitações de hardware e software não são mais necessários nos dias de hoje. Mas a preocupação do COBOL em garantir compatibilidade total com as versões anteriores faz com que esses recursos estejam disponíveis até hoje na maioria dos compiladores. O COBOL é uma das poucas linguagens de programação que não têm comandos “deprecados”.

Alguns desses recursos podem ser encontrados em antigos programas que ainda estão funcionando plenamente em sistemas legados. Por esse motivo é importante que você conheça alguns comandos, estruturas, abordagens e técnicas de programação que ainda são suportados pela linguagem mas que você deve evitar nos seus programas novos e/ou tentar substituir nos programas antigos, quando for possível.

O controverso GO TO

O comando GO TO é provavelmente um dos mais combatidos desde que surgiram as primeiras linguagens programação de terceira geração. O senso comum alega que seu uso prejudica a leitura do programa ao forçar desvios incondicionais de qualquer lugar para qualquer lugar sem restrições.

Mais uma vez, o problema está na dose do remédio, que pode matar ou curar. Naturalmente, você nunca deverá codificar um programa que faça desvios para frente ou para trás indiscriminadamente.

O primeiro programa de exemplo que construímos nesse livro usava esse comando. Era um programa bem simples, onde o GO TO foi usado para provocar um loop de leitura do arquivo e depois para sair desse loop. Todos os exemplos posteriores passaram a usar a técnica de programação estruturada, e talvez você tenha percebido que nenhum desvio foi necessário.

Mas existe uma situação onde o GO TO seria aceitável e não comprometeria o entendimento do programa. Essa situação ocorre quando precisamos interromper o fluxo de execução de um parágrafo, como se fosse um comando break da linguagem C ou Java.

Observe o parágrafo abaixo, extraído de um programa real. Esse parágrafo tem por objetivo validar um arquivo de chamadas telefônicas. Ele foi modificado para mostrar que, tecnicamente, seria possível construí-lo sem o uso de desvios. Também retiramos as linhas de comentários para deixar o trecho mais curto:

    PERFORM S005-PROCESSAMENTO

...

S005-PROCESSAMENTO.

    MOVE ZEROS TO W31-CODG-ERRO-AUX
                  W31-CODG-SERVICO-AUX
                  W32-CODG-NAT

    COMPUTE W32-CODG-NAT = W01-NATUREZA + 1

    IF W22-CODG-NATUREZA(W32-CODG-NAT) = ZEROS
        DISPLAY 'NATUREZA NAO CADASTRADA ' W01-NATUREZA
        MOVE 51630 TO W31-CODG-ERRO-AUX
    ELSE
    IF W22-INFO-FATURA(W32-CODG-NAT) = 'N'
        MOVE 51630 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-EOT-ORIGEM = ZEROS
        DISPLAY 'EOT ORIGEM ZERADA       '
        MOVE 51651 TO W31-CODG-ERRO-AUX
    ELSE
    IF W21-COD-EOT(W01-EOT-ORIGEM) = ZEROS
       DISPLAY 'EOT ORIGEM NAO CADASTRADA  ' W01-EOT-ORIGEM
       MOVE 51651 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-IDENT-REGISTRO = '1' AND
       W01-EOT-DESTINO = ZEROS
       DISPLAY 'EOT DESTINO ZERADA      '
       MOVE 51652 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-IDENT-REGISTRO = ‘1’ AND
       W21-COD-EOT(W01-EOT-DESTINO) = ZEROS
       DISPLAY 'EOT DESTINO NAO CADASTRADA ' W01-EOT-DESTINO
       MOVE 51652 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-EOT-DESTINO NOT = ZEROS
       DISPLAY 'EOT DESTINO NAO ZERADA ' W01-EOT-DESTINO
       MOVE 51652 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-CSP NOT = W31-CSP-AUX
       DISPLAY 'CSP INVALIDO            ' W01-CSP
       MOVE 51631 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-CNL-ORIGEM = ZEROS
       DISPLAY 'CNL ORIGEM  ZERADA      '
       MOVE 51666 TO W31-CODG-ERRO-AUX
    ELSE
    IF W19-NUMR-CNL(W01-CNL-ORIGEM) = ZEROS
       DISPLAY 'CNL ORIGEM NAO CADASTRADA ' W01-CNL-ORIGEM
       MOVE 51666 TO W31-CODG-ERRO-AUX
    ELSE
    IF 88TIPO-ARQ-SMP AND
       W01-CODG-DDD NOT EQUAL W01-CNL-ORIGEM
       DISPLAY 'CNL ORIGEM DIFERENTE DDD  '  W01-CNL-ORIGEM
       MOVE 51666 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-IDENT-REGISTRO EQUAL '1' AND
       W01-CNL-DESTINO EQUAL ZEROS
       DISPLAY 'CNL DESTINO ZERADA      '
       MOVE 51668 TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-IDENT-REGISTRO EQUAL ‘1’ AND
       W19-NUMR-CNL(W01-CNL-DESTINO) EQUAL 0
       DISPLAY 'CNL DESTINO NAO CADASTRADA ' W01-CNL-DESTINO
       MOVE 51668     TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-IDENT-REGISTRO EQUAL ‘1’ AND
       W01-CNL-DESTINO EQUAL ZEROS
       DISPLAY 'CODIGO PAIS NAO CADASTRADO'
       MOVE 51637     TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-GRUPO-HORARIO GREATER 5
       DISPLAY 'GRUPO HORARIO INVALIDO  ' W01-GRUPO-HORARIO
       MOVE 51645     TO W31-CODG-ERRO-AUX
    ELSE
    IF W01-IDENT-REGISTRO EQUAL '1' AND
       W01-DEGRAU-N NOT EQUAL 99 AND
       W20-EXISTE-DEGRAU(W01-DEGRAU-N) NOT EQUAL 'S'
       DISPLAY 'DEGRAU INVALIDO         ' W01-DEGRAU
       MOVE 51671     TO W31-CODG-ERRO-AUX
    ELSE
    IF NOT (W01-COD-CONTEST EQUAL '  ' OR = 'RC' OR = 'RR'
            OR = 'RD' OR = 'RP')
        DISPLAY 'COD CONTESTACAO INVALIDA  ' W01-COD-CONTEST
        MOVE 51648     TO W31-CODG-ERRO-AUX
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF
    END-IF.

Ok, os dezessete END-IFs no final do parágrafo foi um exagero. Bastaria ter encerrado o último IF com um ponto:

    ELSE
    IF NOT (W01-COD-CONTEST EQUAL '  ' OR = 'RC' OR = 'RR'
            OR = 'RD' OR = 'RP')
        DISPLAY 'COD CONTESTACAO INVALIDA  ' W01-COD-CONTEST
        MOVE 51648     TO W31-CODG-ERRO-AUX.

Repare que tivemos que mudar a edentação do programa. Se fizéssemos aquela edentação padrão, deslocando o próximo IF quatro bytes para a direita depois de cada ELSE, certamente faltaria colunas no final do parágrafo. Afinal, uma linha de programa COBOL só pode ir até a coluna 72.

Mas seria aceitável criar um ponto de saída (um parágrafo chamado, digamos, S005-FIM, e modificar o PERFORM incluindo opção THRU.

PERFORM S005-PROCESSAMENTO THRU S005-FIM

Essa opção faz com que o comando execute mais de um parágrafo. Ele executará do primeiro comando do parágrafo S005-PROCESSAMENTO até o último comando do parágrafo S005-FIM, incluindo (se for o caso) quaisquer outros parágrafos que existam entre esses dois.

No nosso exemplo, não haveria nenhum outro parágrafo entre o parágrafo inicial e o final. E o parágrafo final teria um único comando, EXIT, que não tem nenhuma outra função além de marcar esse parágrafo como ponto de saída.

Isso nos permitiria quebrar a cadeia de IFs e incluir um comando que desviasse para S005-FIM sempre que as condições fossem verdadeiras. Observe como era o parágrafo originalmente e faça sua avaliação:

    PERFORM S005-PROCESSAMENTO THRU S005-FIM

...

S005-PROCESSAMENTO.

    MOVE ZEROS TO W31-CODG-ERRO-AUX
                  W31-CODG-SERVICO-AUX
                  W32-CODG-NAT

    COMPUTE W32-CODG-NAT = W01-NATUREZA + 1

    IF W22-CODG-NATUREZA(W32-CODG-NAT) = ZEROS
        DISPLAY 'NATUREZA NAO CADASTRADA ' W01-NATUREZA
        MOVE 51630 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF W22-INFO-FATURA(W32-CODG-NAT) = 'N'
        MOVE 51630 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF W01-EOT-ORIGEM = ZEROS
        DISPLAY 'EOT ORIGEM ZERADA       '
        MOVE 51651 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF W21-COD-EOT(W01-EOT-ORIGEM) = ZEROS
        DISPLAY 'EOT ORIGEM NAO CADASTRADA  ' W01-EOT-ORIGEM
        MOVE 51651 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF W01-IDENT-REGISTRO = '1'
        IF W01-EOT-DESTINO = ZEROS
            DISPLAY 'EOT DESTINO ZERADA      '
            MOVE 51652 TO W31-CODG-ERRO-AUX
            GO TO S005-FIM
        END-IF
        IF W21-COD-EOT ( W01-EOT-DESTINO ) = ZEROS
           DISPLAY 'EOT DESTINO NAO CADASTRADA ' W01-EOT-DESTINO
           MOVE 51652 TO W31-CODG-ERRO-AUX
           GO TO S005-FIM
        END-IF
    ELSE
        IF W01-EOT-DESTINO NOT = ZEROS
            DISPLAY 'EOT DESTINO NAO ZERADA ' W01-EOT-DESTINO
            MOVE 51652 TO W31-CODG-ERRO-AUX
            GO TO S005-FIM
        END-IF
    END-IF

    IF W01-CSP NOT = W31-CSP-AUX
        DISPLAY 'CSP INVALIDO            ' W01-CSP
        MOVE 51631 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF W01-CNL-ORIGEM = ZEROS
        DISPLAY 'CNL ORIGEM  ZERADA      '
        MOVE 51666 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF W19-NUMR-CNL(W01-CNL-ORIGEM) = ZEROS
        DISPLAY 'CNL ORIGEM NAO CADASTRADA '  W01-CNL-ORIGEM
        MOVE 51666 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF 88TIPO-ARQ-SMP
        IF W01-CODG-DDD NOT EQUAL W01-CNL-ORIGEM
            DISPLAY 'CNL ORIGEM DIFERENTE DDD  '  W01-CNL-ORIGEM
            MOVE 51666 TO W31-CODG-ERRO-AUX
            GO TO S005-FIM
        END-IF
    END-IF

    IF W01-IDENT-REGISTRO EQUAL '1'
        IF W01-CNL-DESTINO EQUAL ZEROS
            DISPLAY 'CNL DESTINO ZERADA      '
            MOVE 51668 TO W31-CODG-ERRO-AUX
            GO TO S005-FIM
        END-IF
        IF W19-NUMR-CNL(W01-CNL-DESTINO) EQUAL 0
            DISPLAY 'CNL DESTINO NAO CADASTRADA ' W01-CNL-DESTINO
            MOVE 51668 TO W31-CODG-ERRO-AUX
            GO TO S005-FIM
        END-IF
    ELSE
        IF W01-CNL-DESTINO EQUAL ZEROS
            DISPLAY 'CODIGO PAIS NAO CADASTRADO'
            MOVE 51637 TO W31-CODG-ERRO-AUX
            GO TO S005-FIM
        END-IF
    END-IF

    IF W01-GRUPO-HORARIO GREATER 5
        DISPLAY 'GRUPO HORARIO INVALIDO  ' W01-GRUPO-HORARIO
        MOVE 51645     TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF

    IF W01-IDENT-REGISTRO EQUAL '1'
        IF W01-DEGRAU-N NOT EQUAL 99
            IF W20-EXISTE-DEGRAU(W01-DEGRAU-N) NOT EQUAL 'S'
                DISPLAY 'DEGRAU INVALIDO         ' W01-DEGRAU
                MOVE 51671 TO W31-CODG-ERRO-AUX
                GO TO S005-FIM
            END-IF
        END-IF
    END-IF

    IF NOT (W01-COD-CONTEST EQUAL '  ' OR = 'RC' OR = 'RR'
            OR = 'RD' OR = 'RP')
        DISPLAY 'COD CONTESTACAO INVALIDA  ' W01-COD-CONTEST
        MOVE 51648 TO W31-CODG-ERRO-AUX
        GO TO S005-FIM
    END-IF.

S005-FIM. EXIT.

Muitas empresas adotam esse padrão. Há algumas, inclusive que exigem o uso do PERFORM THRU para todos os parágrafos, mesmo quando eles não precisam de desvios para o final. Outras empresas proíbem seu uso terminantemente. Há autores que consideram uma opção válida, outros que rejeitam completamente.

O fato é que, se realmente essa técnica for usada, é importante que ela faça parte de um padrão de codificação. Por exemplo, o nome do parágrafo final pode ser formado pelo prefixo do parágrafo inicial mais a palavra “FIM”, como fizemos nesse exemplo. Os GO TOs serão sempre para o parágrafo final, nunca para outro lugar.

Como não há questões relacionadas a consumo ou performance, a pergunta que devemos sempre fazer é: essa abordagem prejudica suas manutenções posteriores? Outro programador, anos depois, terá dificuldade para entender e alterar o código? Se a resposta for sim, devemos evitá-la; se for não, podemos prosseguir.

Cobol: O controverso comando GO TO

O inútil GO TO DEPENDING ON

Pior do que um GO TO é um GO TO que depende do valor de uma variável, em tempo de execução, para decidir para onde vai. E é justamente essa a função do comando GO TO DEPENDING ON.

Alguns autores chamam esse comando de GO TO condicional, uma vez que ele exige uma decisão do programa. Seu formato geral é:

GO TO Paragrafo1
      Paragrafo2
      Paragrafo3
      ...
      ParagrafoN
      DEPENDING ON variável

Ele provoca um desvio para um dos parágrafos indicados dependendo do valor numérico da variável informada após a cláusula DEPENDING ON. Se o valor dessa variável for 1, dele desvia para o primeiro parágrafo informado; se for 2, ele desvia para o segundo; e assim sucessivamente.

A variável deve ter um valor consistente com a quantidade de parágrafos codificados no comando. Se esse valor for negativo, se for zero ou se for maior que a quantidade de parágrafos indicados, o comando simplesmente é ignorado.

O trecho abaixo mostra o uso desse comando na prática:

PROCEDURE DIVISION.
INICIO.

    OPEN INPUT MOVIMENTO
         I-O   CADASTRO.

PROCESSA.

    READ MOVIMENTO AT END GO TO FIM.

    GO TO INCLUI-REGISTRO
          ALTERA-REGISTRO
          EXCLUI-REGISTRO
          DEPENDING ON MOVIMENTO-OPERACAO.

    GO TO PROCESSA.

INCLUI-REGISTRO.

    MOVE MOVIMENTO-REGISTRO TO CADASTRO-MOVIMENTO
    WRITE CADASTRO-MOVIMENTO
    GO TO PROCESSA.

ALTERA-REGISTRO.

    MOVE MOVIMENTO-REGISTRO TO CADASTRO-REGISTRO
    REWRITE CADASTRO-REGISTRO
    GO TO PROCESSA.

EXCLUI-REGISTRO.

    MOVE MOVIMENTO-CHAVE TO CADASTRO-CHAVE
    DELETE CADASTRO
    GO TO PROCESSA.

FIM.

    CLOSE MOVIMENTO CADASTRO

    STOP RUN.

Nesse exemplo, o campo MOVIMENTO-OPERACAO, que faz parte do arquivo de entrada, é um campo numérico que pode estar com os valores 1, 2 ou 3. Esse valor fará com que o GO TO DEPENDING ON desvie, respectivamente, para os parágrafos INCLUI-REGISTRO, ALTERA-REGISTRO ou EXCLUI-REGISTRO. Se esse campo estiver preenchido com qualquer valor diferente de 1, 2 ou 3, o comando será ignorado e o fluxo de execução será desviado para nova leitura.

O GO TO DEPENDING ON exige técnicas não-estruturadas de programação, o que pode prejudicar significativamente a clareza do programa. Ele foi muito usado antes da revisão do COBOL de 1985, que implementou estruturas case. O surgimento do comando EVALUATE, nessa versão, tornou o GO TO DEPENDING ON obsoleto e desnecessário.

O famigerado ALTER

Esse talvez seja a única unanimidade quando se discute práticas de programação em COBOL. Poucos comandos podem ser tão contrários às boas práticas quanto o comando ALTER.

Esse comando existe desde a primeira versão do COBOL, de 1959. A ideia era permitir que o programa fosse “automodificável”. E essa expressão, por si só, já dá uma ideia dos efeitos negativos que ele pode provocar na facilidade de manutenções futuras.

O ALTER permite que, em tempo de execução, um comando GO TO seja modificado para desviar para um outro parágrafo, que não aquele que foi originalmente codificado pelo programador. Sua sintaxe é:

ALTER parágrafo1 TO PROCEED TO parágrafo2

A natureza desse comando, por si só, encoraja a utilização de técnicas não-estruturadas de programação. Para entendê-lo é mais fácil acompanhar um exemplo hipotético:

PROCEDURE DIVISION.
INICIO.

    ACCEPT PARAMETRO FROM COMMAND-LINE
    IF PARAMETRO = “A”
       ALTER PROCESSAMENTO TO PROCEED TO SOMA-VALORES
    ELSE
       ALTER PROCESSAMENTO TO PROCEED TO SUBTRAI-VALORES
    END-IF

    OPEN INPUT MOVIMENTO

    OPEN I-O CADASTRO.

LE-MOVIMENTO.

    READ MOVIMENTO AT END GO TO FIM.

    MOVE MOVIMENTO-CHAVE TO CADASTRO-CHAVE.
    READ CADASTRO INVALID KEY GO TO LE-MOVIMENTO.

PROCESSAMENTO.

    GO TO SOMA-VALORES.

SOMA-VALORES.

    ADD MOVIMENTO-VALOR TO CADASTRO-VALOR
    REWRITE CADASTRO-REGISTRO
    GO TO LE-MOVIMENTO.

SUBSTRAI-VALORES.

    SUBTRACT MOVIMENTO-VALOR FROM CADASTRO-VALOR
    REWRITE CADASTRO-REGISTRO
    GO TO LE-MOVIMENTO.

FINALIZA.

    CLOSE MOVIMENTO CADASTRO

    STOP RUN.

Esse programa recebe um argumento (chamado PARAMETRO) que pode ser “A” ou “B”. Se o valor for “A” ele vai somar os valores do arquivo MOVIMENTO aos valores do arquivo CADASTRO. Se o valor for “B” ele vai subtrair esses valores. As somas e subtrações acontecem em dois parágrafos distintos, e logo após a leitura do argumento o programa decide para que parágrafo o fluxo será desviado durante a sua execução.

Uma exigência da sintaxe do ALTER é que o GO TO seja o único comando do parágrafo afetado.

Observe que após o IF inicial, o parágrafo PROCESSAMENTO poderá desviar para SUBTRAI-VALORES, apesar de originalmente ter sido codificado GO TO SOMA-VALORES. O programa fonte mostra uma coisa, mas em tempo de execução ele pode fazer outra.

Para entender a finalidade de um comando assim precisamos voltar no tempo e pensar nas restrições de hardware e software que existiam nos primeiros anos do COBOL. IFs eram recursos “caros”, pois geravam uma grande quantidade de instruções de máquina. Numa época em que os ciclos do processador eram lentos, economizar IFs podia fazer a diferença entre uma performance razoável e um desempenho inaceitável.

Nosso programa exemplo poderia ter executado um IF para cada registro lido, mas o ALTER no início do programa fez com que todo o fluxo fosse desviado uma única vez; o programa se “automodificou”.

Hoje em dia, não existe mais justificativa técnica para isso. Felizmente, o uso do comando ALTER foi limitado mesmo nos primeiros anos do COBOL. Dificilmente você encontrará um programa real que faça uso desse recurso.

O transtorno das SECTIONS

A PROCEDURE DIVISION pode ser dividida em SECTIONS, que por sua vez são divididas em parágrafos:

Cobol: Divisão da Procedure Division em Sections
Figura 74. Divisão da PROCEDURE em SECTIONS

Uma seção termina quando começa a próxima seção, ou quando o programa termina. Seções recebem nomes, como os parágrafos. O que diferencia uma seção de um parágrafo é a palavra SECTION codificada depois do nome:

PROCEDURE DIVISION.
S0-PRINCIPAL SECTION.

    PERFORM S1-PROCEDIMENTOS-INICIAIS

    ...

S1-PROCEDIMENTOS-INICIAIS SECTION.

P11-ABRE-ARQUIVOS.

    OPEN INPUT  CRA0101 CRA0102
         OUTPUT CRA0103.

P12-LE-ARQUIVOS.

    READ CRA0101.
    READ CRA0102.

No trecho acima o comando PERFORM executa S1-PROCEDIMENTOS-INICIAIS, que sabemos que é uma seção por causa da palavra SECTION depois do seu nome.

Quando uma seção é executada, todos os parágrafos dessa seção são executados. No exemplo acima, o comando PERFORM é equivalente a:

PERFORM P11-ABRE-ARQUIVOS THRU P12-LE-ARQUIVOS

A lógica com seções pode ficar mais confusa, uma vez que não dá pra ler o PERFORM e saber se o que está sendo chamado é uma seção com vários parágrafos, ou apenas parágrafo.

A divisão da PROCEDURE em seções se justificava numa época em que memória era um recurso escasso. Os antigos compiladores conseguiam segmentar o programa de maneira que as seções fossem carregadas em memória uma de cada vez. Um programa muito grande, portanto, podia ser modularizado de tal forma que parágrafos muito dependentes uns dos outros seriam carregados juntos, o que melhorava significativamente a performance.

Hoje, o uso de seções tem pouquíssimos efeitos práticos sobre o desempenho do programa, com o prejuízo de deixar a lógica desnecessariamente mais complexa.

As feias DECLARATIVES

A PROCEDURE DIVISION permite que você crie seções especiais para capturar erros de I/O em operações com arquivos. Essas seções devem ser codificadas no início da PROCEDURE entre as palavras DECLARATIVES e END-DECLARATIVES, e seu uso exige que todo o resto do programa seja dividido em seções:

PROCEDURE DIVISION.
DECLARATIVES.

CAPTURA-ERRO-CRA0101 SECTION.

    USE AFTER ERROR PROCEDURE ON CRA0101
    DISPLAY “ERRO “ WT-ST-CRA0101 “ NO ARQUIVO CRA0101”.

CAPTURA-ERRO-CRA0102 SECTION.

    USE AFTER ERROR PROCEDURE ON CRA0102
    DISPLAY “ERRO “ WT-ST-CRA0102 “ NO ARQUIVO CRA0102”.

END-DECLARATIVES.

INICIO-DO-PROGRAMA SECTION.

    ...

O comando USE estabelece em que condições essas seções serão executadas. No exemplo acima, a seção CAPTURA-ERRO-CRA0101 será executada sempre que ocorrer um erro de I/O no acesso ao arquivo CRA0101. Depois que o último comando da seção for executado, o fluxo de execução retorna para o comando seguinte àquele que provocou o erro de I/O.

O uso de DECLARATIVES dá uma falsa impressão de que você vai economizar linhas de código ao concentrar o tratamento de exceções num só lugar. No entanto, suas disfunções são várias. Se você deixar que a DECLARATIVE capture todo e qualquer erro de I/O que acontecer no programa, seu controle será menor sobre o que fazer em cada caso:

  1. Um erro na abertura do arquivo teria que ser tratado da mesma forma que um erro na leitura ou na gravação;
  2. Se você usar cláusulas como AT END ou INVALID KEY nas leituras, eventuais exceções serão tratadas por essas cláusulas, e não pelas DECLARATIVES, e você terá diferentes tratamentos de erro, acontecendo em diferentes lugares do programa;

Além disso, o uso de DECLARATIVES fere os princípios da programação estruturada. Quando um erro exigir o fim anormal do programa você terá que encerrá-lo nessas seções especiais, e seu programa passará a ter mais de um ponto de saída.

Testar o file status após cada comando OPEN, READ, WRITE, REWRITE, DELETE ou CLOSE é uma opção muito melhor. Além de oferecer mais liberdade sobre o que fazer em cada caso, você não prejudica a estruturação do programa.


Anterior Conteúdo Próxima