🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Optional Parameter en Excel — valores predeterminados, IsMissing, argumentos con nombre y ParamArray

|

VBA Optional Parameter en Excel — valores predeterminados, IsMissing, argumentos con nombre y ParamArray

TL;DR — Optional permite que el llamador omita un argumento: Sub Export(ByVal path As String, Optional ByVal addDate As Boolean = True) se puede llamar como Export "C:\Out" o como Export "C:\Out", False. Dale un valor predeterminado a cada Optional con tipo y listo. La única regla que debes conocer: un Optional con tipo no puede distinguir «no se pasó» de «se pasó el valor predeterminado», e IsMissing solo funciona con un Variant sin valor predeterminado. Usa un valor predeterminado cuando omitir el argumento signifique lo mismo que pasar ese valor; usa un Variant e IsMissing solo cuando omitirlo signifique algo que ningún valor puede expresar. Y cuando un procedimiento necesite una entrada nueva, añádela como Optional al final, con el comportamiento antiguo como valor predeterminado, para que todos los llamadores existentes sigan funcionando.

Sub ExportReport(ByVal folder As String, Optional ByVal addDate As Boolean = True)
    Dim fileName As String
    fileName = "Report"
    If addDate Then fileName = fileName & " " & Format(Date, "yyyy-mm-dd")
    Debug.Print folder & "\" & fileName & ".pdf"
End Sub

' ExportReport "C:\Out"             -> C:\Out\Report 2026-10-01.pdf
' ExportReport "C:\Out", False      -> C:\Out\Report.pdf

Este artículo cierra una serie de tres sobre dónde vive un valor. Una variable global la comparte todo el proyecto hasta que se restablece; una variable Static es la memoria privada de un procedimiento. Un parámetro Optional es el más estrecho de todos: el llamador entrega el valor para una sola llamada, o deja que lo sustituya el valor predeterminado. También es el más fiable, porque puedes ver de dónde viene el valor con solo leer la llamada.

Lo que aprenderás

  • El modelo mental: un Optional es una casilla de un formulario con un valor ya impreso
  • Las reglas de declaración, y por qué el valor predeterminado debe ser una constante
  • La única regla: un Optional con tipo no distingue lo omitido de lo predeterminado
  • IsMissing con un Variant, y cuándo es la opción correcta
  • Saltarse argumentos, y por qué los argumentos con nombre vuelven permanentes los nombres de los parámetros
  • ParamArray para cualquier número de valores, y la trampa del reenvío
  • Optional como la forma segura de cambiar un procedimiento al que ya llama todo el mundo

El modelo mental: una casilla de formulario con un valor ya impreso

Un parámetro obligatorio es una casilla en blanco que el llamador tiene que rellenar. Un parámetro Optional es una casilla con un valor ya impreso: el llamador puede escribir encima o dejarlo como está. En ambos casos el procedimiento siempre recibe un valor. Esa imagen explica todas las reglas que vienen a continuación: el valor impreso tiene que conocerse antes de que nadie rellene el formulario, tiene que ir después de las casillas obligatorias y, una vez impreso, el procedimiento ya no puede saber si el llamador lo dejó como estaba o escribió encima lo mismo.

Declarar parámetros Optional: las reglas

Function Discount(ByVal amount As Double, _
                  Optional ByVal rate As Double = 0.1, _
                  Optional ByVal roundTo As Long = 2) As Double
    Discount = Round(amount * (1 - rate), roundTo)
End Function
  • Optional va antes de ByVal o ByRef, y el valor predeterminado va después del tipo: = 0.1.
  • Todos los Optional van después de todos los parámetros obligatorios. En cuanto un parámetro es Optional, todos los que le siguen también tienen que serlo.
  • El valor predeterminado debe ser una expresión constante: un número, una cadena, True, una constante que hayas declarado. Optional asOf As Date = Date es un error de compilación (Constant expression required, «Se requiere una expresión constante»), porque Date es una función que se ejecuta más tarde. Omite el valor predeterminado y rellénalo al principio del procedimiento:
Sub Snapshot(Optional ByVal asOf As Date)
    If asOf = 0 Then asOf = Date     ' 0 significa no indicado - entonces la fecha de hoy
    Debug.Print Format(asOf, "yyyy-mm-dd")
End Sub

Un parámetro de objeto sin valor predeterminado llega como Nothing, lo que facilita «usa la hoja activa salvo que te digan otra cosa»: Optional ws As Worksheet, y luego If ws Is Nothing Then Set ws = ActiveSheet.

En una función de hoja, los parámetros Optional se comportan igual: =Discount(A2) usa los dos valores predeterminados y =Discount(A2, 0.2) sobrescribe uno. La guía de Function cubre el resto del diseño de una función definida por el usuario (UDF).

La única regla: un Optional con tipo no distingue lo omitido de lo predeterminado

Vuelve a mirar Snapshot. Si el llamador no pasa nada, asOf vale 0. Si el llamador pasa 0 a propósito, asOf también vale 0. El procedimiento no puede distinguirlos, y eso vale para todo Optional con tipo: un Long omitido es 0, un String omitido es "", un Boolean omitido es False, o el valor predeterminado que declaraste.

La mayoría de las veces es exactamente lo que quieres. «Omitirlo» y «pasar el valor predeterminado» deberían significar lo mismo, y un valor predeterminado hace que el comportamiento del procedimiento quede claro desde su primera línea. El problema llega cuando que el llamador lo omita tiene que significar algo que ningún valor del tipo puede expresar. Un caso típico es un filtro cuyo valor predeterminado es «sin filtro», donde 0 y "" son valores reales por los que alguien podría querer filtrar.

IsMissing: cuando omitirlo tiene que significar algo

Para ese caso, declara el parámetro como Variant sin valor predeterminado y pregunta a IsMissing:

Function CountWhere(rng As Range, Optional ByVal match As Variant) As Long
    Dim c As Range, n As Long
    For Each c In rng
        If IsMissing(match) Then
            If Not IsEmpty(c.Value) Then n = n + 1   ' sin filtro: cuenta las celdas con datos
        ElseIf c.Value = match Then
            n = n + 1                                ' filtro, incluso con 0 o ""
        End If
    Next c
    CountWhere = n
End Function

IsMissing tiene dos condiciones, y si incumples cualquiera de ellas devuelve False en silencio para siempre:

  • El parámetro tiene que ser un Variant. Con un Long o un String, IsMissing siempre es False.
  • El parámetro no debe tener valor predeterminado. Optional match As Variant = "" nunca falta, porque el valor predeterminado lo rellena.

Mi criterio: recurre a IsMissing solo cuando la ausencia es un tercer estado real. Si lo usas únicamente para rellenar un valor predeterminado al principio del procedimiento, declara en su lugar el valor predeterminado con tipo; así la firma documenta el comportamiento y el compilador comprueba el tipo.

Saltarse argumentos, y los argumentos con nombre

Para saltarte un Optional del medio, deja su hueco vacío o nombra el argumento que sí pasas:

Debug.Print Discount(200, , 0)            ' tasa predeterminada, redondeo a 0 decimales
Debug.Print Discount(200, roundTo:=0)     ' lo mismo, y legible
Debug.Print Discount(amount:=200, rate:=0.25)

Los argumentos con nombre usan := y el nombre del parámetro, en cualquier orden. Son la opción legible en cuanto un procedimiento tiene más de un Optional, porque , , 0 no dice nada sobre qué valor es cuál. Tienen una consecuencia que la gente pasa por alto: en cuanto algún llamador usa roundTo:=, el nombre del parámetro forma parte de la interfaz. Renombrar roundTo a decimals compila sin problemas en el procedimiento y rompe a todos los llamadores que lo nombraban, con «Named argument not found» («No se encontró el argumento con nombre»). Elige los nombres de los Optional con el mismo cuidado que los de los procedimientos.

ParamArray: cualquier número de valores

Cuando el llamador debe poder pasar tantos valores como quiera, usa ParamArray. Tiene que ser el último parámetro, tiene que ser una matriz de Variant y no se puede combinar con Optional en el mismo procedimiento:

Function SumAll(ParamArray values() As Variant) As Double
    Dim i As Long, total As Double
    For i = LBound(values) To UBound(values)
        total = total + values(i)
    Next i
    SumAll = total
End Function

' SumAll(1, 2, 3)  -> 6
' SumAll()         -> 0   (UBound es -1, asi que el bucle nunca se ejecuta)

La trampa es el reenvío. Si SumAll quiere pasar sus valores a un segundo procedimiento con ParamArray, Other values no los reparte: Other recibe un solo argumento, que es la matriz entera. Escribe la función auxiliar para que reciba un Variant normal que contenga una matriz, y recórrela ahí. La guía de UBound cubre los límites que hacen seguras las matrices vacías.

El criterio: Optional es cómo crece un procedimiento sin romperse

Lo más útil que hace Optional no es la comodidad. Es la compatibilidad. Supón que ExportReport folder se llama desde doce botones y otras tres macros, y ahora un informe necesita omitir la fecha. Cambiar la firma con un parámetro obligatorio nuevo rompe quince llamadores. Añadir Optional ByVal addDate As Boolean = True no rompe ninguno, porque el valor predeterminado es exactamente lo que recibían antes, y el único llamador nuevo pasa False.

Mis reglas:

  • Las entradas nuevas van al final, como Optional, con el comportamiento antiguo como valor predeterminado.
  • Prefiere un valor predeterminado con tipo a IsMissing, salvo que «no indicado» sea un tercer estado real.
  • A partir de dos o tres Optional, los llamadores deberían usar argumentos con nombre, y merece la pena preguntarse si el procedimiento está haciendo dos trabajos que deberían ser dos procedimientos, en la línea de la guía de Sub.
  • No uses nunca una variable global para pasar un ajuste a un procedimiento que podría recibirlo como Optional. El argumento se ve en la llamada; la global no se ve en ninguna parte.

Cómo ayuda ExcelMaster

Los errores con parámetros Optional se esconden en las llamadas: un filtro que nunca se aplica porque se le preguntó a IsMissing por un String, un cambio de nombre que rompe a todos los llamadores que usan argumentos con nombre, un procedimiento al que le creció un parámetro obligatorio y rompió los botones que lo llaman.

ExcelMaster te deja describir el cambio, por ejemplo «haz que esta exportación pueda omitir la fecha en el informe mensual». Añade la entrada como Optional con el comportamiento antiguo como valor predeterminado, para que los llamadores existentes sigan funcionando, y revisa todos los puntos de llamada del proyecto.

Preguntas frecuentes

¿Cómo hago que un parámetro sea opcional en VBA?

Pon Optional delante de él en la declaración y dale un valor predeterminado: Optional ByVal rate As Double = 0.1. Tiene que ir después de todos los parámetros obligatorios, y cualquier parámetro posterior también tiene que ser Optional. Así los llamadores pueden omitirlo y el procedimiento recibe el valor predeterminado.

¿Por qué IsMissing siempre devuelve False?

IsMissing solo funciona cuando el parámetro Optional es un Variant sin valor predeterminado. Con un parámetro con tipo, como Long o String, o con un Variant que tiene valor predeterminado, VBA rellena un valor cuando se omite el argumento, así que nunca falta.

¿Puede un parámetro Optional tener como valor predeterminado la fecha de hoy?

No directamente, porque un valor predeterminado debe ser una constante y Date es una función. Declara Optional asOf As Date sin valor predeterminado y escribe If asOf = 0 Then asOf = Date al principio del procedimiento.

¿Cómo me salto un argumento opcional que está en medio?

Deja su posición vacía con una coma, como en Discount(200, , 0), o usa argumentos con nombre, como en Discount(200, roundTo:=0). Los argumentos con nombre son más claros y se pueden dar en cualquier orden.

¿Qué es ParamArray en VBA?

ParamArray permite que un procedimiento acepte cualquier número de argumentos como una sola matriz de Variant, por ejemplo Function SumAll(ParamArray values() As Variant). Tiene que ser el último parámetro y no se puede usar junto con parámetros Optional. Recórrelo con LBound y UBound; cuando no se pasa ningún argumento, UBound vale -1.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 01/10/2026.

Guías relacionadas: VBA Global Variable · VBA Static Variable · VBA Function · VBA Sub · VBA ByRef frente a ByVal · VBA UBound · VBA Format · VBA Save as PDF