sábado, 29 de julio de 2023

Funciones.

Macro, subrutina y función

Para entender en qué consisten las funciones hay que tener en cuenta dos cuestiones: las instrucciones específicas que incorpora todo lenguaje para realizar determinadas tareas y el modo en que programamos los script.



La primera de estas cuestiones nos lleva a pensar en las funciones que incorpora todo lenguaje y que sirven para realizar "funciones" concretas y específicas. Un ejemplo son las funciones de conversión de tipos de variables, como CInt() que sirve para convertir una variable de cualquier tipo (string, por ejemplo) a numérica tipo Integer.

La segunda cuestión nos lleva a plantearnos los modos de programar, cuestión ésta de mayor complejidad conceptual y práctica que la anterior, pero ineludible a partir de cierto nivel de extensión y complejidad del código.

La forma de programar básica puede describirse como lineal: el conjunto de tareas que se definen en el algoritmo se convierten en líneas de código que se van sucediendo una tras otra hasta la conclusión del proceso.

Un ejemplo de ello es la forma de programar en el lenguaje Basic al inicio de la popularización  de los ordenadores. Otra, sin ir muy lejos, la que supone grabar una macro mediante Grabar macro.

Otra forma de plantearse la creación de programas se basa en reutilizar segmentos de código para simplificar el programa y hacerlo más legible y funcional. La forma más sencilla en que se manifiesta esta opción consiste en llamar a un script desde otro script, algo que también podemos hacer con macros. 

Sub EscribirMsgA
Dim sMsg As String
sMsg = "Hola Mundo 1"
MsgBox sMsg,64, "MENSAJE"
End Sub

 

Sub Receptor1
MsgBox "Mensaje desde script",64,"RECEPTOR 1"
Call  EscribirMsgA
End Sub

En este caso el script EscribirMsgA es funcional en si mismo,  pero también podemos reutilizarlo desde un segundo script (Receptor1llamándolo mediante la expresión Call, de la que podemos prescindir ya que se da por supuesta. Y lo dicho: también podemos hacerlo con una macro en sustitución del script EscribirMsgAaunque en este caso para escribir un texto directamente en el documento Writer.

A pesar de las ventajas de esta opción, también  tiene sus limitaciones; y la más importante es quizá, que es necesario modificar (en este ejemplo) el texto del mensaje en el script (o en la macro) subordinado, lo que en programas largos supone mucho trabajo e incrementa la probabilidad de cometer errores. 

Frente a estas opciones, funcionales pero limitadas, tenemos las subrutinas y las funciones. Empezaremos por aclarar en qué se diferencian ambas.

En OOo Basic las funciones se diferencian de las subrutinas claramente: mientras que las funciones devuelven  un valor (un  dato) y las subrutinas hacen algo, así que lo que "devuelven" es eso que hacen.

Veamos cómo crear una subrutina a partir del script anterior:

Sub EscribirMsgB (sMsg As String)
MsgBox sMsg,64, "MENSAJE"
End Sub

 

Sub Receptor2
MsgBox "Mensaje desde script",64,"RECEPTOR 2"
        EscribirMsgB ("Hola Mundo")
End Sub

Vamos a analizar ahora las diferencias entre EscribirMsgA (script) y EscribirMsgB (sMsg As String) (subrutina), aunque en cosa de denominación podrás comprobar que existe cierta confusión: en la documentación se suele emplear indistintamente el término macro, pero yo prefiero diferenciar entre macro, script (o rutina) y subrutina (1).

  • El script auxiliar (el primero) funciona con independencia del script principal (el segundo); la subrutina no.
  • La subrutina incorpora un identificador de variable en el paréntesis que lleva tras el nombre. En el script no existe dicho paréntesis y, en caso de identificarse una variable asimilable a la que declara la subrutina (es el caso de EscribirMsgA) se declara dentro del script y asigna contenido también dentro del script.
  • Mientras que en la llamada al script desde el principal (Receptor1) simplemente se llama al script auxiliar (Call  EscribirMsgA), al ser llamada la subrutina es necesario añadir un paréntesis tras el nombre y un contenido, en este caso un texto  (EscribirMsgB ("Hola Mundo")(2)

También podemos convertir las macros simples (algunas de ellas) en subrutinas, pero no en funciones, ya que las macros siempre hacen algo. Para ello, y en primer lugar, tenemos que diferenciar las que llamamos variables de sistema (que son de tipo objeto) de las que utilicemos para dar contenido concreto a la macro. A estas segundas son a las que daremos el tratamiento de subrutina, ya que las primeras, es posible darlas ese tratamiento, pero también otros, siendo preferible optar por uno más propio del trabajo con macros simples. Lo veremos a continuación en el ejemplo que vamos a desarrollar en base a la macro de escritura de texto.

Sub EscribirMsgC  (sTexto As String)
Dim document   as object
Dim dispatcher as object
document   = ThisComponent.CurrentController.Frame
dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
Dim args2(0) as new com.sun.star.beans.PropertyValue
args2(0).Name = "Text"
args2(0).Value = sTexto
dispatcher.executeDispatch(document, ".uno:InsertText", "", 0, args2())
End Sub

 

Sub Receptor3
MsgBox "Mensaje desde macro",64,"RECEPTOR 3"
EscribirMsgC ("Hola Mundo")
End Sub
  • Puedes observar que he formulado la macro del mismo modo que la subrutina. Gracias a ello, de hecho, he convertido la macro en una subrutina, aunque sería más correcto decir que esta formulación está a medio camino entre macro y subrutina, ya que mantiene componentes y formas propias de las macros, incorporando otras propias de la subrutinas. También sus "limitaciones": no funciona autónomamente, debiendo ser llamada desde un script "principal". 
  • El script "receptor" trata la macro como subrutina, tal y como podemos observar en la forma en que la llama (EscribirMsgC ("Hola Mundo"))

Frente a las subrutinas, en OOo Basic las funciones se diferencian claramente ya en su formulación: al denominarlas (apertura y cierre) se debe usar el identificador Function:

Function AreaCuadrado( iLado As Integer) As Double
    Dim dArea as Double
    AreaCuadrado = iLado * iLado
End Function

Esto es:
    • La función se declara con la expresión Function y finaliza con  End Function.
    • La función no funciona independientemente, necesita ser "llamada" desde un script principal.
    • Además del paréntesis donde se declaran las variables, también finaliza con una tipificación (As Double) que permite entender qué tipo de valor devuelve (numérico Double, en este caso) así como que la propia función es una variable, como de hecho lo es (o como tal se comporta), ya que devuelve un valor (el que contiene como variable)
    • El resultado del procesamiento interno de la función se asigna a la misma función a modo de variable (volvemos al punto anterior): AreaCuadrado = iLado * iLado. Otra formulación no provoca que la "función" dé error, pero tampoco devuelve nada.
Veamos cómo se formula el que llamamos script principal:

Sub Cuadrado
Dim sResultado As String
Dim iLong As Integer
Dim dArea
iLong = InputBox ("Dime el lado del cuadrado")
dArea = AreaCuadrado(iLong)
sResultado = "El cuadrado de lado " & iLong & " tiene un área de " & dArea
MsgBox (sResultado,64,"AREA DEL CUADRADO")
End sub

Puedes observar que la "llamada" a la función se diferencia de la llamada a la subrutina en que en la primera utilizamos la asignación a una variable, lo cual no hacemos en la llamada a subrutina puesto que la función es un valor (se comporta como una variable que tiene asignado un dato o valor), por lo que debe ser recogido por (y asignado a) una variable. Después podrá ser tratado como dato, tal y como sucede en este ejemplo en su concatenación en la variable string sResultado (3)

NOTAS

(1) Las funciones se diferencian claramente, por lo que no existen estos problemas terminológicos.
(2) Podríamos sustituir el texto por una variable, pero en este ejemplo he optado por la formulación más sencilla. En ese caso, dicha variable es diferente de la que se declara en la subrutina, aunque termina cumpliendo la misma función que aquella. Esta equivalencia viene facilitada por la funcionalidad compartida de ambas: complementan la forma en que se escribe la subrutina.
(3) En la que contradigo lo que he considerado conveniente en otra entrada: no convierto las variables numéricas en string, como sería recomendable, por lo que una buena formulación de esta instrucción sería la siguiente: sResultado = "El cuadrado de lado " & CStr(iLong) & " tiene un área de " & CStr(dArea)

No hay comentarios:

Publicar un comentario

Comenta esta entrada