Argumentos e Parâmetros

Nem sempre os procedimentos executam a mesma ação quando chamados. Uma das formas de alterar seu comportamento durante a execução para produzir um resultado diferente é passando argumentos a eles.

Introdução

Os argumentos que um procedimento aceita são definidos em sua declaração. O exemplo a seguir mostra um subprocedimento que aceita três argumentos:

Sub Mostrar(Nome, Idade, Altura)

Um procedimento pode receber até 30 argumentos.

O procedimento Mostrar exemplificado abaixo produz um resultado de execução diferente dependendo dos valores passados aos parâmetros Nome, Idade e Altura. Suponha que o subprocedimento Main chame Mostrar passando argumentos:

Sub Main()
    Mostrar "Felipe", 30, 2
End Sub
 
Sub Mostrar(Nome, Idade, Altura)
    MsgBox "Seu nome é " & Nome & "."
    MsgBox "Sua idade é de " & Idade & "."
    MsgBox "Você tem " & Altura & " metros de altura."
End Sub

Afinal, qual é a diferença entre argumentos e parâmetros?

Argumentos são as expressões passadas a um procedimento. Neste caso, foram passados os argumentos “Felipe”, 30 e 2. No entanto, poderiam ser passados argumentos diferentes desses a Mostrar. Por outro lado, cada parâmetro é representado por num nome de variável dentro do procedimento que recebeu os valores dos argumentos passados.

Logo, tente entender que parâmetros são fixos, como vagas de garagem. Argumentos são os vários carros que podem parar em cada uma dessas vagas delimitadas.

Nomear Parâmetros

Adquiri o costume de utilizar a letra p como prefixo para nomear parâmetros. Dessa forma, ao bater os olhos numa variável com esse prefixo num procedimento, já sei que ela é um parâmetro. No exemplo anterior, então eu escreveria:

Sub Mostrar(pNome, pIdade, pAltura)

Especificar Tipo de Dados de Parâmetros

Assim como nas boas práticas de declaração de variáveis explicitamos seu tipo de dados, recomenda-se também especificar o tipo de dados dos argumentos:

Sub Mostrar(pNome As String, pIdade As Long, pAltura As Double)

Se o procedimento possuir muitos parâmetros e sua linha de declaração ficar muito grande, sugiro quebrar a linha fisicamente na forma que se segue:

Sub Mostrar(pNome As String, _
            pIdade As Long, _
            pAltura As Double)

Fixando a terminologia, você deve entender que um procedimento chama outro procedimento passando a ele argumentos. Os argumentos passados estão definidos como parâmetros no procedimento que recebe os argumentos, e então ele faz uso desses valores para produzir um resultado de execução de código.

Economia de Código

Procedimentos com parâmetros podem ser usados para economizar código. Veja o exemplo a seguir:

Sub Main()
    Dim FirstName As String
    Dim CurrentAge As Long
    Dim Height As Double
    
    FirstName = "Felipe"
    CurrentAge = 30
    Height = 2
    MsgBox "Nome: " & FirstName & ", idade de " & CurrentAge _
           & " anos e " & Height & " metros de altura."
    
    FirstName = "Renata"
    CurrentAge = 32
    Height = 1.73
    MsgBox "Nome: " & FirstName & ", idade de " & CurrentAge _
           & " anos e " & Height & " metros de altura."
    
    FirstName = "Rodrigo"
    CurrentAge = 35
    Height = 1.87
    MsgBox "Nome: " & FirstName & ", idade de " & CurrentAge _
           & " anos e " & Height & " metros de altura."
    
    FirstName = "Maria"
    CurrentAge = 60
    Height = 1.7
    MsgBox "Nome: " & FirstName & ", idade de " & CurrentAge _
           & " anos e " & Height & " metros de altura."
    
    FirstName = "José"
    CurrentAge = 60
    Height = 1.8
    MsgBox "Nome: " & FirstName & ", idade de " & CurrentAge _
           & " anos e " & Height & " metros de altura."
End Sub

Seu usarmos um procedimento com parâmetros, o código pode ser simplificado para:

Sub Main()
    Dim FirstName As String
    Dim CurrentAge As Long
    Dim Height As Double
    
    FirstName = "Felipe"
    CurrentAge = 30
    Height = 2
    Mostrar FirstName, CurrentAge, Height
    
    FirstName = "Renata"
    CurrentAge = 32
    Height = 1.73
    Mostrar FirstName, CurrentAge, Height
    
    FirstName = "Rodrigo"
    CurrentAge = 35
    Height = 1.87
    Mostrar FirstName, CurrentAge, Height
    
    FirstName = "Maria"
    CurrentAge = 60
    Height = 1.7
    Mostrar FirstName, CurrentAge, Height
    
    FirstName = "José"
    CurrentAge = 60
    Height = 1.8
    Mostrar FirstName, CurrentAge, Height
    End Sub
    
Sub Mostrar(pNome As String, _
            pIdade As Long, _
            pAltura As Double)
    MsgBox "Nome: " & pNome & ", idade de " & pIdade _
    & " anos e " & pAltura & " metros de altura."
End Sub

Utilizando um procedimento auxiliar que defina parâmetros, o complicado código com várias concatenações da caixa de mensagem foi escrito apenas uma vez. Há um ganho na manutenção do código, já que se precisarmos alterar o conteúdo da caixa de mensagem, editaremos apenas uma vez, no procedimento auxiliar.

Nesse exemplo, observe que ao chamar o procedimento que possui os parâmetros, a ordem das variáveis deve seguir a ordem dos parâmetros na declaração do procedimento. Além disso, você não precisa declarar dentro do procedimento os parâmetros, pois a própria declaração do procedimento também as declara como variáveis. Pela obrigatoriedade de se passar pela ordem correta, diz-se que os argumentos foram passados por posição.

Se você tentar passar um argumento de um tipo de dados incompatível com o tipo de dados de um parâmetro, obterá um erro de tipos incompatíveis.

Argumentos Nomeados

Alternativamente, você pode passar os argumentos por nome, isto é, especificar explicitamente qual argumento cada parâmetro atribui. Para tal, utilize o símbolo := (dois pontos e símbolo de igualdade) com seus respectivos nomes e separe-os por vírgula:

Mostrar Nome:=FirstName, Idade:=CurrentAge, Altura:=Height
Se você passar um dos argumentos por nome na chamada de um procedimento, todos os outros deverão também ser passados por nome. Não misture a sintaxe de passar argumentos por nome e posição.

Quando são utilizados muitos argumentos e preciso quebrar linhas, organizo o código da seguinte forma:

  Mostrar Nome:=FirstName,  _
          Idade:=CurrentAge, _
          Altura:=Height

Uma vantagem de se passar argumentos por nome é que você pode trocar a ordem de atribuição deles, em detrimento de quando se passa por posição:

  Mostrar Altura:=Height, _
          Nome:=FirstName,  _
          Idade:=CurrentAge
Se o argumento em questão for uma variável, não é necessário que ela tenha nome diferente do nome do parâmetro. Diferenciei apenas para efeito didático e não confundir iniciantes.

Parâmetros Opcionais

Você pode criar parâmetros opcionais ao qualifica-los usando a palavra chave Optional, e coloca-lo por último na ordem da declaração dos parâmetros. Parâmetros opcionais são aqueles que você não é obrigado a passar a um procedimento.

Veja o exemplo a seguir:

Sub Main()
    Mostrar "Felipe"
    Mostrar "Renata", 32
    Mostrar "Rodrigo", , 1.87
    
    'As linhas abaixo são equivalentes às mostradas acima,
    'mas utilizando argumentos nomeados.
    Mostrar pNome:="Felipe"
    Mostrar pNome:="Renata", pIdade:=32
    Mostrar pNome:="Rodrigo", pAltura:=1.87
End Sub
 
Sub Mostrar(pNome As String, _
            Optional pIdade As Long, _
            Optional pAltura As Double)
    Dim TextMessage As String
    
    TextMessage = "Nome: " & pNome
    
    If pIdade > 0 Then
        TextMessage = TextMessage & ", idade de " & pIdade & " anos"
    End If
    
    If pAltura > 0 Then
      TextMessage = TextMessage & ", altura de " & pAltura & " metros"
    End If
    
    TextMessage = TextMessage & "."
    
    MsgBox TextMessage
End Sub

Vale ressaltar que na chamada Mostrar "Rodrigo", , 1.87 foram passados apenas o primeiro e terceiro argumentos, já que o segundo parâmetro está vazio. Na verdade, o segundo parâmetro assumirá o valor inicial de seu tipo de dados, explicado na subseção a seguir.

Valor Padrão de Argumento Opcional

Você pode definir um determinado valor para um parâmetro opcional. Por exemplo: se você trabalha numa fábrica em alguns testes de rotina são feitos geralmente na parte da noite, poderia usar a função:

Sub GerarRelatório(ByVal pAmostras As Long, _
                   Optional ByVal pPeríodo As String = "Noturno")
  '...código...
End Sub

Se você chamar essa função sem especificar o valor do Parâmetro pPeríodo, o VBA considerará seu valor como “Noturno”.

Parâmetros ByRef e ByVal

Parâmetros passados com a palavra chave ByVal (passados por valor) não podem ser alterados pela rotina chamada e argumentos ByRef (passados por referência) podem. Se você não qualificar seus argumentos com uma dessas palavras chave, o VBA o considerará como ByRef. Logo, as declarações abaixo são equivalentes:

Sub pProcessar(pCódigo)
 
Sub pProcessar(ByRef pCódigo)

O exemplo a seguir ilustra a diferença entre parâmetros que são ByRef ou ByVal:

Sub Main()
    Dim Número1 As Long
    Dim Número2 As Long
    
    Número1 = 3
    Número2 = 3
    Incrementar Número1, Número2
    
    Debug.Print "Número1=" & Número1, "Número2=" & Número2
End Sub
 
Sub Incrementar(ByVal pNúmero1 As Long, ByRef pNúmero2 As Long)
    pNúmero1 = pNúmero1 + 1
    pNúmero2 = pNúmero2 + 1
End Sub

A saída do programa acima nos mostrará que pNúmero1 teve seu valor preservado, mas pNúmero2 alterou.

Normalmente, não perco muito meu tempo atentando se meus parâmetros são ByRef ou ByVal. Costumo deixar em branco (consequentemente, são passados por referência) e tomo cuidado para não alterar o valor do parâmetro para que as alterações não reflitam no argumento passado.

Vale ressaltar que alguns objetos ou vetores não podem ser passados como valor, apenas por referência. Por exemplo, não é possível criar cópias de objetos complexos que se alocam em pontos específicos da memória do seu sistema.

Em termos de desempenho, não existem ganhos significativos quando comparamos argumentos passados como valor ou referência. Existe a falsa ideia (porém, lógica) de que ao passar como valor, se gasta mais tempo porque a estrutura de dados do argumento deve ser duplicada, ao invés de simplesmente ser passado um endereço de memória (que é o caso de passar por referência).

Sobre Felipe Gualberto

Microsoft Most Valuable Professional (MVP) de Excel.
Esta entrada foi publicada em Tutoriais e marcada com a tag , , , , , , , , . Adicione o link permanente aos seus favoritos.