SkillsTecnológicas
Menu
Conteúdo da trilha

Funções e procedimentos

Entenda como rotinas nomeadas são definidas, chamadas e devolvem controle, diferenciando funções que produzem valores de procedimentos orientados a ações.

Conteúdo 35 de 39

Dois mecanismos desenhados a lápis representam uma função que transforma duas entradas e devolve uma peça e um procedimento que recebe um comando e produz uma marca

Rotinas dão nome a uma parte executável do algoritmo

Uma rotina é um conjunto nomeado de instruções que pode ser chamado quando uma responsabilidade precisa ser executada. O nome permite pedir “calcule o subtotal” sem repetir, no fluxo principal, todos os passos necessários para fazer esse cálculo.

Em muitos materiais introdutórios, duas categorias ajudam a explicar o que o chamador espera:

  • uma função produz um valor que pode ser usado em uma expressão;
  • um procedimento realiza uma tarefa e devolve o controle, mas não entrega um valor ao chamador.

Essa distinção é útil, porém a terminologia depende da linguagem. Delphi e Visual Basic possuem construções separadas para função e procedimento. C# chama ambas de métodos e usa void quando não há valor. Python e JavaScript usam o termo função mesmo quando não existe um return explícito.

Por isso, primeiro compreenda o contrato da rotina: como ela é chamada, qual trabalho realiza e o que o chamador recebe ou consegue observar. Depois traduza esse contrato para a sintaxe da linguagem escolhida.

Declarar uma rotina não é o mesmo que chamá-la

A declaração registra uma receita executável. Ela reúne nome, entradas previstas, corpo e, quando aplicável, um resultado. O corpo só é executado quando ocorre uma chamada.

Considere esta função em pseudocódigo:

FUNÇÃO calcularAreaRetangulo(largura, altura): REAL
  area <- largura * altura
  RETORNAR area
FIM FUNÇÃO

A declaração ensina ao algoritmo como calcular uma área, mas ainda não calcula nenhuma. A execução acontece aqui:

areaDaSala <- calcularAreaRetangulo(5, 4)

Nessa chamada, os valores 5 e 4 ocupam as entradas esperadas, o corpo calcula 20, e o valor retornado passa a ocupar o lado direito da atribuição. A próxima aula diferenciará formalmente os nomes declarados e os valores enviados; por enquanto, observe apenas que a chamada fornece o contexto necessário para uma execução específica.

A declaração reúne nome, entradas, corpo e resultado; uma chamada separada fornece valores e ativa o corpo da rotina
Declarar disponibiliza uma rotina; chamar cria uma execução concreta com os dados daquela chamada.

Se a chamada ocorrer novamente com 3 e 2, o mesmo corpo produzirá 6. A definição é uma só, mas cada chamada possui seus próprios valores e seu próprio percurso.

A chamada transfere o controle e depois o recebe de volta

Uma chamada não executa duas partes do programa ao mesmo tempo. Em um fluxo síncrono simples, ocorre esta sequência:

  1. o chamador chega à instrução que contém a chamada;
  2. os dados necessários para a chamada são obtidos;
  3. o controle entra no corpo da rotina;
  4. as instruções internas são executadas;
  5. a rotina termina e devolve o controle ao ponto posterior à chamada;
  6. se houver um valor retornado, ele substitui a chamada na expressão.
largura <- 5
altura <- 4
areaDaSala <- calcularAreaRetangulo(largura, altura)
EXIBIR areaDaSala

O comando EXIBIR não é executado enquanto o cálculo está no meio. Primeiro calcularAreaRetangulo termina; depois areaDaSala recebe 20; somente então o fluxo avança.

O fluxo sai do chamador, entra no corpo da rotina, produz o valor 20 e retorna ao ponto seguinte da chamada
A rotina devolve sempre o controle; entregar também um valor depende do seu contrato e da linguagem.

Essa diferença entre retorno de controle e retorno de valor é essencial. Um procedimento termina e o chamador continua, portanto o controle retornou. O que não existe, na distinção clássica, é um valor produzido para ocupar uma expressão.

Função produz um valor para o chamador usar

Uma função é adequada quando a responsabilidade pode ser formulada como uma pergunta cujo resultado será usado pelo restante do algoritmo:

  • qual é o subtotal?
  • esta entrada é válida?
  • qual é a maior nota?
  • quantos itens foram aprovados?

No fechamento de pedido da aula sobre como dividir um algoritmo em partes, o cálculo pode ser expresso assim:

FUNÇÃO calcularSubtotal(itens): REAL
  subtotal <- 0

  PARA CADA item DE itens FAÇA
    subtotal <- subtotal + item.preco * item.quantidade
  FIM PARA

  RETORNAR subtotal
FIM FUNÇÃO

O chamador usa o resultado em uma atribuição:

subtotalDoPedido <- calcularSubtotal(itensValidos)

Também poderia usar a chamada dentro de uma expressão:

total <- calcularSubtotal(itensValidos) - desconto

Guardar o resultado em uma variável intermediária costuma ajudar quando ele será reutilizado, inspecionado em um teste de mesa ou combinado em etapas posteriores. Colocar a chamada diretamente na expressão é apropriado quando a leitura continua clara.

Procedimento expressa uma ação completa

Um procedimento é adequado quando a intenção principal é realizar uma ação observável, não fornecer um valor para outro cálculo:

PROCEDIMENTO exibirResumo(subtotal, desconto, total)
  EXIBIR "Subtotal:", subtotal
  EXIBIR "Desconto:", desconto
  EXIBIR "Total:", total
FIM PROCEDIMENTO

A chamada forma uma instrução completa:

exibirResumo(subtotal, desconto, total)

A saída exibida é um efeito da execução. Ela não é um valor que substitui a chamada em uma expressão. Outros exemplos de ações são salvar um registro, enviar uma mensagem, alterar o estado de uma interface ou registrar um evento.

Isso não significa que um procedimento “não devolve nada” em qualquer sentido. Ele devolve o controle ao chamador e pode produzir efeitos que o restante do sistema observa. A formulação precisa é: na distinção clássica, o procedimento não retorna um valor ao chamador.

Use o espaço da chamada para reconhecer a intenção

Um teste simples ajuda a ler pseudocódigo e várias linguagens:

subtotal <- ________

Se calcularSubtotal(itens) preenche naturalmente esse espaço, a chamada está sendo usada como uma expressão que produz valor.

Agora observe:

________

Se exibirResumo(subtotal, desconto, total) forma sozinha uma instrução completa, sua intenção principal é executar uma ação.

À esquerda uma função ocupa o espaço de uma expressão e entrega um valor; à direita um procedimento forma uma instrução e produz uma saída observável
Observe como o chamador usa a rotina: como fonte de um valor ou como uma ação completa.

O teste não substitui a documentação da linguagem. Algumas linguagens permitem chamar uma função e ignorar seu resultado; outras representam rotinas sem retorno como funções que produzem um valor especial. Ele serve para revelar o contrato desejado, não para adivinhar toda a semântica pela aparência.

A mesma intenção recebe nomes diferentes nas linguagens

Compare como uma rotina orientada a ação aparece em diferentes contextos:

ContextoRotina que produz valorRotina sem valor útil para o chamador
pseudocódigo didáticoFUNÇÃOPROCEDIMENTO
Delphifunctionprocedure
Visual BasicFunctionSub
C#método com tipo de retornométodo void
Pythonfunção com return valorfunção sem retorno explícito produz None
JavaScriptfunção com return valorfunção sem retorno explícito produz undefined

Em C#, a distinção pode aparecer no tipo declarado:

decimal CalcularTotal(decimal subtotal, decimal desconto)
{
    return subtotal - desconto;
}

void ExibirTotal(decimal total)
{
    Console.WriteLine($"Total: {total:C}");
}

Já em Python, as duas rotinas são declaradas com def:

def calcular_total(subtotal, desconto):
    return subtotal - desconto

def exibir_total(total):
    print(f"Total: {total:.2f}")

calcular_total(200, 20) produz 180. exibir_total(180) mostra uma saída e, por não possuir return explícito, também produz implicitamente None. Isso não transforma None no resultado de negócio desejado; é a maneira como Python modela o término de uma função sem outro valor.

Em JavaScript, uma função que chega ao fim sem return com expressão produz undefined. Portanto, use a palavra “procedimento” como categoria didática quando ela ajudar, mas consulte a construção real da linguagem em que estiver programando.

Escolha o contrato antes da sintaxe

Para decidir a forma de uma rotina, pergunte primeiro como o chamador precisa colaborar com ela:

PerguntaTendência de contrato
o chamador precisa combinar o resultado em outro cálculo?produzir e retornar um valor
o resultado representa uma consulta, transformação ou decisão?produzir e retornar um valor
a responsabilidade principal é comunicar, persistir ou acionar algo?executar uma ação
o chamador precisa saber se a ação funcionou?a ação pode precisar devolver um estado explícito ou comunicar falha por outro mecanismo

Uma rotina que salva um pedido, por exemplo, pode apenas realizar a ação em um exercício simples. Em um sistema real, talvez precise entregar um identificador ou comunicar uma falha. A escolha não vem do verbo isolado; vem das informações necessárias para o chamador continuar corretamente.

Evite usar efeitos ocultos como substitutos convenientes para resultados. Se calcularSubtotal altera silenciosamente uma variável global em vez de retornar o subtotal, o chamador passa a depender de um estado que não aparece na chamada. Isso dificulta compreender entradas, saídas e testes.

O modelo de entrada, processamento e saída ajuda a explicitar o contrato: determine o que entra, qual transformação ocorre e se a saída será um valor retornado ou um efeito observável.

Evite quatro confusões frequentes

Achar que a declaração já executou o corpo

Definir calcularSubtotal disponibiliza a rotina. Cada cálculo acontece somente quando uma chamada é alcançada pelo fluxo.

Confundir saída exibida com valor retornado

EXIBIR total envia informação ao dispositivo de saída. RETORNAR total entrega um valor ao trecho que chamou a rotina. Uma função pode fazer ambos, mas são operações diferentes.

Ignorar um resultado importante

Algumas linguagens permitem chamar uma função como instrução isolada:

calcularSubtotal(itensValidos)

O cálculo acontece, mas seu valor pode ser descartado. Se o resultado é necessário, atribua-o ou use-o explicitamente.

Criar nomes que escondem o contrato

processarPedido não permite prever se a rotina valida, calcula, salva ou exibe. Nomes como calcularSubtotal, pedidoEhValido e exibirResumo tornam valor ou ação mais fáceis de antecipar.

Pratique montando um pequeno coordenador

Organize um algoritmo de boletim usando estas responsabilidades:

  • calcular a média de quatro notas;
  • decidir a situação a partir da média;
  • exibir média e situação.

Primeiro classifique cada responsabilidade como produtora de valor ou orientada a ação. Depois complete o coordenador:

media <- __________________________
situacao <- _______________________
__________________________________

Uma solução possível é:

media <- calcularMedia(notas)
situacao <- classificarSituacao(media)
exibirBoletim(media, situacao)

Verifique a execução com as notas 8, 7, 6 e 9: a média deve ser 7,5; essa média alimenta a classificação; e a apresentação só acontece depois que os dois valores existem. Em seguida, faça uma segunda chamada com outras notas para confirmar que a mesma declaração atende execuções independentes.

O que você deve guardar

Funções e procedimentos são formas de encapsular uma responsabilidade em uma rotina nomeada. Declarar registra o corpo; chamar transfere o controle para ele; terminar devolve o controle ao chamador. Na distinção didática clássica, a função também entrega um valor, enquanto o procedimento realiza uma ação sem retornar valor.

Trate essa diferença como um modelo de contrato, não como vocabulário universal. C#, Python e JavaScript representam rotinas sem valor de maneiras diferentes. Antes de escolher a sintaxe, determine o que o chamador precisa fornecer, observar e usar. Na próxima aula, aprofunde a relação entre parâmetros e argumentos para compreender como cada chamada preenche as entradas declaradas.

Referências