A ideia básica de uma função, implementada em alguma linguagem de programação, é encapsular um código que poderá ser invocado/chamado por qualquer outro trecho do programa. Seu significado e uso é muito parecido com o de funções matemáticas, ou seja, existe um nome, uma definição e posterior invocação à função.
Explicitando o paralelo com a matemática, tomemos como exemplo a função trigonétrica cosseno(x), que é impossível de ser implementada de modo exato em um computador digital, entretanto é viável obter boas aproximações utilizando a série de Taylor. Como examinado na referida página, a série que aproxima a função cosseno próximo à origem é: (1) cos(x) = 1 - x2 /2! + x4 /4! - x6 /6! + x8 /8! + ...
Note que o lado direito da equação (1) é a definição da função e ela está escrita em termos do parâmetro formal x. Ao "chamarmos" a função com parâmetros efetivos, é sobre o valor desses parâmetros que computamos o lado direito da expressão, por exemplo, computar cos(0.1) ou de cos(1.1).
Por que usar o conceito de função?Assim, implementar códigos com objetivos específicos (como computar o cosseno de qualquer valor) apresentam três grandes vantagens:
Assim, agrupar trechos com objetivos específicos e implementá-los na forma de uma função que ajuda bastante o desenvolvimento e a organização dos códigos em programação.
Do ponto de vista prático, a estrutura básica de uma função em uma linguagem de programação está representada abaixo, com a declaração da função e sua lista de parâmetros formais, seguido de sua invocação (quando providenciamos os parâmetro efetivos).
Declaração: |
[enventual tipo de retorno] nome_da_funcao (lista_parametros_formais) comando1 ... comandoN return EXP |
Uso: | var = nome_da_funcao(lista_parametros_efetivos) |
A lista de parâmetros pode conter vários nomes de variáveis, geralmente, separadas por vírgula. Por exemplo, se houver necessidade de uma função que realiza vários cálculos com três variáveis pode-se usar como declaração da função algo como: nome_da_funcao (var1, var2, var3).
Parâmetros formais e efetivosDe modo geral, a diferença entre os parâmetros formais e efetivos é que o primeiro corresponde ao nome da variável utilizada dentro da função, enquanto o segundo é o nome da variável que será usado para iniciar o parâmetro formal ao iniciar a execução da função.
Assim durante a execução, ao encontrar uma chamada à função nome_da_funcao, o fluxo de execução segue a partir do código da função. Mas antes de executar a primeira linha de código da função, os valores dos parâmetros efetivos servem para inicializar os parâmetros formais (que são também variáveis locais à função). Após esta inicialização, inicia-se a execução do código da função e geralmente ao final, encontra-se um comando do tipo "retorne devolvendo um valor" (return).
Ilustrando a execução de um trecho de programa com 3 chamadas à mesma funçãoSuponhamos que precisemos computar o valor da combinação de N tomado k a k, ou seja, C(N,k) = N! / ( k! (N-k)!). Para isso percebe-se que é necessário implementar o cômputo de fatorial que será utilizado 3 vezes. Para facilitar a compreensão, podemos escrever um código com 3 variáveis auxiliares para armazenar, respectivamente, N!, k! e (N-k)!.
Na figura acima ilustra a execução do código para computar C(N,k), com o retângulo à esquerda contendo
o código que invoca a função fat e à direita a função fat.
Para entender o fluxo de execução destaremos a execução da linha 2, b = fat(k);.
Como b = fat(k); é uma atribuição, primeiro computa-se o valor do lado direito da atribuição
e só depois atribui-se à variável do lado esquerdo da atribuição o seu valor, ou seja,
1. primeiro executa-se o cômputo de fat(k), para isso
2. pega-se o valor do parâmetro efetivo k e usa-o para iniciar o parâmetro formal n da função
3. então inicia-se a execução da função fat
4. ao final da função fat, pega-se o valor da variável local ft e
5. atribui-se este valor para a variável b
6. então segue-se execução da próxima linha (3).
Vale notar que a execução da atribuição c = fat(N-k); seguirá um fluxo análogo aos 6 passos acima.
Uma vez entendido como é executado uma chamada á função, podemos novamente comparar com o conceito usual de função matemática. Existe a declaração da função, com seu parâmetro formal
fat : IN -> IN (nome 'fat', com domínio e imagem nos naturais) fat(n) = { 1, se n=0, n x fat(n-1), se n>0 }E existe o uso da função, como em
C(N,k) = fat(N) / (fat(k) x fat(N-k)Exemplo concreto em C e em Python
Para ilustrar o uso e sintaxe de funções em C e em Python, examinemos um exemplo em que implementamos uma função para cômputo do fatorial de um natural n, que será o nome de seu único parâmetro formal.
C | Python | ||||
|
|
|
Note na linha 2 do código acima que são declaradas duas novas variáveis, ft e i, dentro da fução fat. Isso significa que as variáveis ft e i são variáveis locais à função, ou seja, pode-se utilizar variáveis com os mesmos nomes em outras funções sendo que elas não terão qualquer relação. Em particular, na 11 do código em C ou na 9 do código em Python, poderia-se usar uma variável com nome n, ft ou i e ainda assim, está variável não teria qualquer relação com as correspondentes da função fat.
Para que serve função?A partir do exemplo acima, para cômputo de C(n,k) = n! / (k! (n-k)!), imagine como seria o código para computar a combinção se a linguagem de programação NÂO dispusesse do conceito de funções: em resumo, precisariamos repetir as linhas 2 a 5 (ou 6), que computam fatorial, três vezes. Portanto, o uso de função simplifica o código.
Mas existe uma outra razão para usar funções, que não tão óbvia, a maior facilidade para escrever um programa. E isso se deve à vários fatores, mas principalmente à quebra de um problema maior em vários menores. Isso facilita o desenvolvimento e reduz a incidência de erros de programação.
Por exemplo, pode-se implementar a função separadamente, testando-a até que ela fique pronta e sem erros. Assim, o código fica mais fácil de ser entendido, pois ao usar a função pode-se abstrair, o trecho fica curto (apenas a chamada à função) e pode-se concentrar em saber se o restante do código está correto.
Leônidas de Oliveira Brandão
http://line.ime.usp.br