¿Cuáles son las reglas que rigen el uso de corchetes en las llamadas a función VBA?

Acabo de tener unos irritantes 30 minutos en un “error de comstackción” en VBA (Access 2003) causado por el uso de corchetes alrededor de los argumentos que estoy pasando a un Sub I definido.

He estado buscando un artículo / tutorial / instrucción decente sobre cuándo son necesarios / adecuados / inapropiados / prohibidos los paréntesis, pero no encuentro ninguna guía clara.

Desde aquí :

Uso de la statement de llamadas de VBScript para llamar a una subrutina El uso de la statement de llamadas es opcional cuando desea llamar a una subrutina. El propósito de la statement de llamada cuando se usa con un Sub es permitirle encerrar la lista de argumentos entre paréntesis. Sin embargo, si una subrutina no pasa ningún argumento, entonces aún no debe usar paréntesis cuando llama a un Sub utilizando la instrucción Call.

Call MySubroutine 

Si una subrutina tiene argumentos, debe usar paréntesis cuando usa la instrucción Call. Si hay más de un argumento, debe separar los argumentos con comas.

 Call MySubroutine(intUsageFee, intTimeInHours, "DevGuru") 

Llamar a la función Hay dos formas posibles de llamar a una función. Puede llamar a la función directamente, solo por nombre, o puede llamarla utilizando la statement de VBScript Call.

Llamar a una función por nombre Cuando se llama a una función directamente por nombre y cuando no hay ninguna asignación a un valor devuelto, todas las siguientes son syntax legales:

 MyFunction MyFunction() MyFunction intUsageFee, intTimeInHours, "DevGuru" 

Si desea un valor devuelto, puede asignar la función a una variable. Tenga en cuenta que si hay uno o más argumentos, debe usar los paréntesis.

 returnval = MyFunction returnval = MyFunction() returnval = MyFunction(intUsageFee, intTimeInHours, "DevGuru") 

Existe una lógica perfecta para la regla de paréntesis en VB (A), y es así.

Si se llama a un procedimiento (función o sub) con argumentos, y la llamada está alineada con otras declaraciones o palabras clave, los argumentos deben estar entre paréntesis. Esto para distinguir los argumentos que pertenecen a la llamada de procedimiento del rest de la línea. Asi que:

 1: If CheckConditions(A, B, C) = DONT_PROCEED Then Exit Sub 

es una linea valida; la llamada a CheckConditions necesita los paréntesis para indicar qué otros bits de la línea son sus argumentos. Por el contrario, esto produciría un error de syntax:

 2: If CheckConditions A, B, C = DONT_PROCEED Then Exit Sub 

Porque es imposible de analizar.

Con una llamada de procedimiento como única instrucción en la línea, no se necesitan paréntesis porque está claro que los argumentos pertenecen a la llamada de procedimiento:

 3: SaveNewValues Value1, Value2, Value3 

Si bien esto da como resultado un error de syntax (por razones de sonido que se explica a continuación):

 4: SaveNewValues(Value1, Value2, Value3) 

Para evitar confusiones sobre paréntesis o sin paréntesis (de hecho, para evitar la regla de paréntesis por completo), siempre es una buena idea utilizar la palabra clave de llamada para llamadas como estas; eso asegura que la llamada al procedimiento no es la única instrucción en la línea, lo que requiere paréntesis:

 5: Call SaveNewValues(Value1, Value2, Value3) 

Por lo tanto, si adquiere el hábito de preceder a las llamadas a procedimientos independientes con la palabra clave de llamada, puede olvidar la regla de paréntesis, ya que siempre puede incluir sus argumentos entre paréntesis.

El asunto se confunde con el rol adicional que juegan los paréntesis en VB (A) (y en muchos otros lenguajes): también indican la prioridad de evaluación para las expresiones. Si usa paréntesis en cualquier otro contexto pero para encerrar los argumentos de llamada de procedimiento, VB (A) intentará evaluar la expresión entre paréntesis en un valor simple resultante.

Por lo tanto, en el ejemplo 4, donde los paréntesis son ilegales para adjuntar los argumentos, VB (A) intentará en su lugar evaluar la expresión entre paréntesis. Dado que (Valor1, Valor 2, Valor3) no es una expresión que se puede evaluar, se produce un error de syntax.

Esto también explica por qué las llamadas con una variable pasada ByRef actúan como si se llamara ByVal si el argumento está entre paréntesis. En el ejemplo anterior, donde se llama a la función p con el parámetro ByRef a, hay una gran diferencia entre estas dos llamadas a p:

 6: pa 

Y

 7: p(a) 

Como se discutió anteriormente, 6 es la syntax correcta: la llamada está sola en su línea, por lo tanto, los paréntesis no deben usarse para encerrar los argumentos.

En 7, el argumento está entre paréntesis de todos modos, lo que hace que VB (A) evalúe la expresión adjunta a un valor simple. Que, por supuesto, es la definición misma de pasar ByVal. Los paréntesis aseguran que en lugar de un puntero a a, se pasa el valor de a, y a no se modifica.

Esto también explica por qué la regla de paréntesis no siempre parece dominar. El ejemplo más claro es una llamada a MsgBox:

 8: MsgBox "Hello World!" 

Y

 9: MsgBox ("Hello World!") 

Ambos son correctos, aunque la regla de paréntesis dicta que 9 debe estar equivocado. Lo es, por supuesto, pero todo lo que sucede es que VB (A) evalúa la expresión entre paréntesis. Y el literal de cadena evalúa exactamente el mismo literal de cadena, de modo que la llamada real realizada es 8. En otras palabras: las llamadas a procedimientos de argumento único con argumentos constantes o de cadena literal tienen el mismo resultado con o sin paréntesis. (Esta es la razón por la que incluso mis llamadas a MsgBox están precedidas por la palabra clave de llamada).

Finalmente, esto explica los errores de desajuste de tipo extraños y el comportamiento extraño al pasar argumentos de objeto. Digamos que su aplicación tiene un procedimiento HighlightContent que toma un TextBox como argumento (y, nunca lo adivinará, lo resalta). Usted llama a esto para seleccionar todo el texto en el cuadro de texto. Puede llamar a este procedimiento de tres maneras sintácticamente correctas:

 10: HighlightContent txtName 11: HighlightContent (txtName) 12: Call HighlightContent(txtName) 

Digamos que su usuario ingresó “John” en el cuadro de texto y su aplicación llama a HighlightContent. ¿Qué sucederá, qué llamada funcionará?

10 y 12 son correctos; el nombre John se resaltará en el cuadro de texto. Pero 11 es sintácticamente correcto, pero dará como resultado un error de comstackción o de tiempo de ejecución. ¿Por qué? Porque los paréntesis están fuera de lugar. Esto provocará que VB (A) intente una evaluación de la expresión entre paréntesis. Y el resultado de la evaluación de un objeto generalmente será el valor de su propiedad predeterminada; .Texto, en este caso. Así que llamar al procedimiento como 11 no pasará el objeto TextBox al procedimiento, sino un valor de cadena “John”. Resultando en una Falta de coincidencia de tipo.

Acabo de encontrar un comportamiento extraño llamando a una función con / sin paréntesis. Google me llevó hasta aquí.

 sub test() dim a as double a = 1# p(a) 'this won't change a's value Debug.Print a '1 pa ' this is expected behavior Debug.Print a '2 Call p(a) 'this is also valid Debug.Print a '3 end sub Function p(a as Double) 'default is byref a = a + 1 end function 

Mi conclusión es que debe usar Llamar u omitir los paréntesis cuando llama a una función con un solo parámetro; de lo contrario, el parámetro no se pasa por referencia (todavía se llama a la llamada, como ya lo he comprobado).

Acabo de pasar 10 minutos descifrando una excepción de “tipos incompatibles” al llamar a un Sub que toma 1 argumento a través de

 CallMe(argument) 

Como resultado, esto no es válido, Google me lleva aquí y finalmente

 Call CallMe(argument) 

o

 CallMe argument 

Hizo el truco. Por lo tanto, no debe usar los corchetes cuando llama a un sub sin el enunciado de llamada que solo toma 1 argumento.

Cuando utilizas Call MySub debes usar paréntesis alrededor de los parámetros, pero si omites Call, no necesitas paréntesis.

1 – Por defecto, no use paréntesis cuando llame a procedimientos o funciones:

 MsgBox "Hello World" 

2 – Si está llamando a una función y está interesado en su resultado, debe encerrar sus argumentos entre paréntesis:

 Dim s As String Dim l As Long s = "Hello World" l = Len(s) 

3 – Si desea utilizar la palabra clave de llamada con un procedimiento, debe encerrar los argumentos entre paréntesis (por ejemplo, cuando desea asignar el resultado en una variable o usar la función en una expresión):

 Call MsgBox("Hello World") 

4 – Si desea forzar un ByRef argumento (el valor predeterminado) para pasar ByVal, a continuación, encierre el argumento ByRef con paréntesis:

 Sub Test Dim text As String text = "Hello World" ChangeArgument((text)) MsgBox text End Sub Sub ChangeArgument(ByRef s As String) s = "Changed" End Sub 

Esto muestra “Hola mundo”