TL;DR —
Optionalpermite que el llamador omita un argumento:Sub Export(ByVal path As String, Optional ByVal addDate As Boolean = True)se puede llamar comoExport "C:\Out"o comoExport "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», eIsMissingsolo funciona con unVariantsin valor predeterminado. Usa un valor predeterminado cuando omitir el argumento signifique lo mismo que pasar ese valor; usa unVarianteIsMissingsolo 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
Optionalva antes deByValoByRef, 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 = Datees un error de compilación (Constant expression required, «Se requiere una expresión constante»), porqueDatees 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 unLongo unString,IsMissingsiempre esFalse. - 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
