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

CALL BY REFERENCE vs BY CONTENT: Qual é a diferença?
Photo by The Infinity Shutter on Pexels

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.