Call Using By Reference vs By Content: Qual é a diferença?

Você sabia que um subprograma pode alterar as variáveis do seu programa sem que você perceba?
Isso acontece por causa de uma diferença fundamental na cláusula USING do comando CALL: BY REFERENCE ou BY CONTENT.
E esse detalhe pode impactar diretamente a segurança dos dados do seu programa, especialmente quando você chama subrotinas externas.
Mas qual a diferença entre BY REFERENCE e BY CONTENT em COBOL?
O comando CALL
O comando CALL permite que um programa chame um subprograma em tempo de execução, e sua sintaxe básica é:
CALL nome-do-subprograma USING variavel-1 variavel-2 (...) variavel-n
O nome do subprograma pode ser um literal (para realizar chamadas estáticas) ou estar em uma variável (para realizar chamadas dinâmicas). Por exemplo…
CALL "SBP1900" USING WT-DATA WT-RC
…executa estaticamente um subprograma chamado SBP1900 passando como parâmetros as variáveis WT-DATA e WT-RC. Isso significa que SBP1900 será incorporado ao objeto do programa principal (o programa “chamador”) em tempo de compilação e linkedição.
Já…
CALL WT-NM-SUBPROGRAMA USING WT-DATA WT-RC
…executa dinamicamente um subprograma cujo nome está armazenado na variável WT-NM-SUBPROGRAMA, passando os mesmos parâmetros. Isso significa que o subprograma a ser executado será encontrado pelo programa “chamador” em tempo de execução.
As vantagens e desvantagens desses dois métodos de execução podem ser comentadas em outro artigo.
Neste artigo aqui, o objetivo é destacar como os parâmetros são passados para o subprograma, independentemente do método de execução.
O comportamento padrão: BY REFERENCE
Quando escrevemos…
CALL SUBPROG USING WT-DATA WT-VALOR
…o COBOL assume, por default, a mesma coisa que…
CALL SUBPROG USING BY REFERENCE WT-DATA WT-VALOR
Nesse modo, o programa chamador não envia os valores das variáveis; ele envia ponteiros que indicam onde essas variáveis estão na memória. Na prática, o subprograma recebe o(s) endereço(s) de memória onde os dados estão armazenados e pode modificar seus conteúdos diretamente.
Exemplo prático
Imagine o seguinte programa “chamador”:
identification division.
program-id. ymain.
data division.
working-storage section.
01 contador pic 9(003) value zeros.
procedure division.
inicio.
display "1) O contador e' " contador
call "ysubpro" using by reference contador
display "2) Depois da primeira chamada o contador passou a ser " contador
call "ysubpro" using by reference contador
display "3) Depois da segunda chamada o contador passou a ser " contador
stop run.
Esse programa chama duas vezes um subprograma chamado ysubpro e exibe o conteúdo do parâmetro (contador) antes e depois de cada chamada. O subprograma, por sua vez, faz o seguinte:
identification division.
program-id. ysubpro.
data division.
linkage section.
01 lk-contador pic 9(003).
procedure division using lk-contador.
add 1 to lk-contador
goback.
Ou seja, ele soma 1 diretamente na variável que recebeu como parâmetro.
Ao executar ymain, o que aconteceria é o seguinte:
1) O contador e' 000
2) Depois da primeira chamada o contador passou a ser 001
3) Depois da segunda chamada o contador passou a ser 002
Protegendo os dados com BY CONTENT
Se substituirmos a opção BY REFERENCE por BY CONTENT…
CALL "YSUBPROG" USING BY CONTENT CONTADOR
…o COBOL não passa o ponteiro da variável. Ele cria uma cópia do valor e envia essa cópia para o subprograma.
Ou seja, o subprograma continua podendo alterar o parâmetro recebido, mas essas alterações não afetam o programa chamador.
Se executarmos novamente o programa depois dessa alteração, o que vamos ver é o seguinte:
1) O contador e' 000
2) Depois da primeira chamada o contador passou a ser 000
3) Depois da segunda chamada o contador passou a ser 000
O valor original permaneceu intacto.
Quando usar um ou outro
Se o subprograma pertence ao seu sistema e você sabe exatamente o que ele faz, você pode usar a opção BY REFERENCE, por uma questão de performance ou mesmo porque você realmente quer que o subprograma modifique os valores dos parâmetros que você passou para ele.
BY REFERENCE é teoricamente mais rápido, porque passa ponteiros de 4 ou 8 bytes ao invés de criar cópias de todos os parâmetros antes da chamada.
BY CONTENT, por outro lado, é o mais indicado para subrotinas externas ao seu sistema cujo algoritmo você não consegue controlar. Essa opção protege os dados do programa chamador.
Conclusão
A diferença entre BY REFERENCE e BY CONTENT pode parecer apenas um detalhe de sintaxe e performance, mas na verdade sua escolha faz parte de uma decisão de arquitetura relacionada à segurança de dados.
Em COBOL, muitos detalhes aparentemente pequenos podem influenciar diretamente a forma como o sistema funciona.
E entender esses detalhes faz muita diferença quando você está mantendo ou evoluindo sistemas reais.
