Fundamentos

Funciones – Introducción

Básicos Definiciones Fundamentos

Ya conocemos cómo utilizar las estructuras de control condicionales e iterativas con las que podíamos controlar el flujo de nuestros programas. Ahora nuestros programas han ganado en potencia y flexibilidad. ¿Recordáis aquel sumatorio que repetíamos 1000 veces? Luego lo solucionamos con el bucle WHILE y de 1000 líneas pasamos a tener menos de 10. Pero aún podemos mejorar y ahorrar más líneas con el concepto de funciones.

Repetimos código sin parar

Recordemos el pseudocódigo que realizaba el sumatorio de los 1000 primeros números.

sumatorio = 0
incremento = 1
WHILE (incremento <= 1000) {
  sumatorio += incremento
  incremento += 1
}
IMPRIMIR sumatorio

Gracias a WHILE hemos recorrido todos los números del 1 al 1000 y hemos ido guardando su suma en la variable sumatorio. Ahora, queremos saber también la suma de los 5000 primeros números.

sumatorio = 0
incremento = 1
WHILE (incremento <= 5000) {
  sumatorio += incremento
  incremento += 1
}
IMPRIMIR sumatorio

Ningún problema, cambiamos 1000 por 5000 y listo. Sin embargo, ahora nos emocionamos más y queremos un programa que nos muestre la suma de los 10 primeros números, de los 100 primeros números, de los 1000 primeros números y de los 10000 primeros números. Aquí lo tenemos.

sumatorio = 0
incremento = 1
WHILE (incremento <= 10) {
  sumatorio += incremento
  incremento += 1
}
IMPRIMIR sumatorio

sumatorio = 0
incremento = 1
WHILE (incremento <= 100) {
  sumatorio += incremento
  incremento += 1
}
IMPRIMIR sumatorio

sumatorio = 0
incremento = 1
WHILE (incremento <= 1000) {
  sumatorio += incremento
  incremento += 1
}
IMPRIMIR sumatorio

sumatorio = 0
incremento = 1
WHILE (incremento <= 10000) {
  sumatorio += incremento
  incremento += 1
}
IMPRIMIR sumatorio

¿No estamos repitiendo siempre el mismo código con alguna ligera variación? ¿No podríamos “empaquetar” ese código de alguna manera? Sí, ahí entra el concepto de funciones.

Funciones, o cómo nombrar partes de código

Nuestros programas podrían vivir sin funciones, por supuesto, pero sería un absoluto caos, los códigos serían eternos y se prestarían a múltiples errores. Además, si quisiéramos cambiar un pequeño detalle, tendríamos que ir a todos los sitios donde ese detalle aparece.

Las funciones nos permiten coger un conjunto de instrucciones que vayamos a repetir de forma habitual y, en base a unos argumentos de entrada, realizar esas instrucciones y devolvernos un resultado. Definamos nuestra primera función:

DEFINE calcular_sumatorio(valor_final) {
  sumatorio = 0
  incremento = 1
  WHILE (incremento <= valor_final) {
    sumatorio += incremento
    incremento += 1
  }
  DEVOLVER sumatorio
}

Aquí tenemos nuestra primera función. En pseudocódigo hemos optado por colocar la palabra DEFINE y seguidamente el nombre de la función. Luego, entre paréntesis hemos colocado los argumentos de la función. Este DEFINE ha sido por conveniencia nuestra, pues en cada lenguaje de programación veremos que para definir funciones se utilizan varias formas (def, function…).

Argumentos de una función

Una función puede tener todos los argumentos que queramos, incluso cero. Podemos empaquetar un trozo de código que vayamos a utilizar mucho para luego reutilizarlo las veces que sea necesario simplemente “llamando” a la función. No es necesario que tenga argumentos.

Tampoco es necesario que la función tenga un valor de retorno que, en el ejemplo que hemos puesto, hemos indicado como DEVOLVER. La función puede, perfectamente, imprimir algo por pantalla o hacer una serie de instrucciones sin necesidad de devolvernos nada.

Ejemplo de llamadas a las funciones

El pseudocódigo de arriba no hace nada, pues nunca llamamos o utilizamos la función. ¿Y cómo la utilizamos? De la siguiente manera.

DEFINE calcular_sumatorio(valor_final) {
  sumatorio = 0
  incremento = 1
  WHILE (incremento <= valor_final) {
    sumatorio += incremento
    incremento += 1
  }
  DEVOLVER sumatorio
}

// De esta forma, estamos imprimiendo el valor que devuelve la función
IMPRIMIR calcular_sumatorio(1000)

// De esta forma, estamos guardando el valor devuelto en una variable
sumatorio_resuelto = calcular_sumatorio(1000)

// Llamar a esta función concreta de esta forma no nos serviría
calcular_sumatorio(1000)

Hemos colocado tres ejemplos de llamadas a funciones para ver qué ocurre. En la línea 12 llamamos a la función con el argumento 1000. De esta forma, se ejecutaría el código de la función y la variable valor_final cogería el valor 1000. La función nos devolvería el resultado de sumar los 1000 primeros números, y como hemos colocado IMPRIMIR delante de la función, pues ese resultado se imprimiría.

En la línea 15 hemos hecho exactamente lo mismo, pero ahora hemos guardado el resultado devuelto por la función en una variable llamada sumatorio_resuelto. Así, tenemos esta variable con el valor y podremos utilizarla tantas veces como queramos.

Utilizar correctamente el valor devuelto

Lo que ocurre en la línea 18 no daría error, pero no nos sirve. Para esta función en concreto, todo se haría igual pero, el resultado que devuelve la función acaba perdiéndose, pues ni se guarda en una variable ni se imprime. Para este caso, hubiera sido mejor imprimir el resultado directamente dentro de la función en lugar de devolverlo.

Por tanto, llamar a una función es tan fácil como escribir el nombre que le hemos dado, indicarle los argumentos que necesita y obtener un resultado con el que hacer alguna cosa. Pasemos, pues, a obtener los sumatorios de 10, 100, 1000 y 10000 que buscábamos anteriormente.

DEFINE calcular_sumatorio(valor_final) {
  sumatorio = 0
  incremento = 1
  WHILE (incremento <= valor_final) {
    sumatorio += incremento
    incremento += 1
  }
  DEVOLVER sumatorio
}

IMPRIMIR calcular_sumatorio(10);
IMPRIMIR calcular_sumatorio(100);
IMPRIMIR calcular_sumatorio(1000);
IMPRIMIR calcular_sumatorio(10000);

Donde antes teníamos 31 líneas de código, ahora tenemos 14 nada más. Y si quisiéramos seguir calculando sumatorios, antes copiábamos de nuevo todo el código pero ahora nos sirve con llamar a la función con otro argumento distinto.

Añadiendo más argumentos

Vamos a mejorar un poco más nuestro ejemplo para ver la potencia de las funciones. Nuestra función asume que el incremento siempre empieza en 1 y, además, siempre va de uno en uno. Si quisiéramos calcular el sumatorio de los 1000 primeros números pares, esta función no nos serviría. Si quisiéramos calcular el sumatorio de los números entre el 501 y el 1000, tampoco nos serviría.

Vamos a utilizar más argumentos para dotar de flexibilidad y potencia a nuestra función.

DEFINE calcular_sumatorio(valor_final, valor_inicial, valor_incremento) {
  sumatorio = 0
  incremento = valor_inicial
  WHILE (incremento <= valor_final) {
    sumatorio += incremento
    incremento += valor_incremento
  }
  DEVOLVER sumatorio
}

IMPRIMIR calcular_sumatorio(10, 1, 1);
IMPRIMIR calcular_sumatorio(100, 1, 1);
IMPRIMIR calcular_sumatorio(1000, 1, 1);
IMPRIMIR calcular_sumatorio(1000, 2, 2);
IMPRIMIR calcular_sumatorio(1000, 501, 1);
IMPRIMIR calcular_sumatorio(500, 1000, 1);

Analicemos lo que hemos hecho. Ahora nuestra función tiene tres argumentos: valor_final que nos indica el último valor que debemos sumar, valor_inicial que nos indica el valor desde el que empezamos a sumar y valor_incremento que nos indica el valor en el que se irá incrementando nuestro incremento, valga la redundancia.

Repasemos bien qué hace cada llamada a la función:

  • calcular_sumatorio(10, 1, 1) nos va a calcular el sumatorio desde el 1 (valor inicial) hasta el 10 (valor final) contando de uno en uno (valor de incremento)
  • calcular_sumatorio(100, 1, 1) nos va a calcular el sumatorio desde el 1 hasta el 100 de uno en uno
  • calcular_sumatorio(1000, 1, 1) nos va a calcular el sumatorio desde el 1 hasta el 1000 de uno en uno
  • calcular_sumatorio(1000, 2, 2) nos va a calcular el sumatorio desde el 2 hasta el 1000 de dos en dos
  • calcular_sumatorio(1000, 501, 1) nos va a calcular el sumatorio desde el 501 hasta el 1000 de uno en uno
  • calcular_sumatorio(500, 1000, 1) nos devolverá un 0, pues nunca entrará en el WHILE ya que 500 no es mayor que 1000, por tanto el valor de sumatorio es el inicial, un 0

Ya hemos visto que, con un sencillo cambio añadiendo argumentos, tenemos una función más potente, capaz de calcular diversos tipos de sumatorios. Y todo ello, con pocas líneas de código a comparación de si hubiéramos ido uno por uno cambiando todas las veces en las que aparecía el código.

Argumentos con valores por defecto

Aún podemos mejorar más esta pequeña función. Podemos ver que es bastante habitual que contemos de uno en uno, y también podemos pensar que es normal empezar desde el 1. Para ello, nuestras funciones pueden tener argumentos con valores predefinidos, pero con la única condición de que siempre sean los últimos de entre los argumentos.

DEFINE calcular_sumatorio(valor_final, valor_inicial = 1, valor_incremento = 1) {
  sumatorio = 0
  incremento = valor_inicial
  WHILE (incremento <= valor_final) {
    sumatorio += incremento
    incremento += valor_incremento
  }
  DEVOLVER sumatorio
}

IMPRIMIR calcular_sumatorio(10);
IMPRIMIR calcular_sumatorio(100);
IMPRIMIR calcular_sumatorio(1000);
IMPRIMIR calcular_sumatorio(1000, 2, 2);
IMPRIMIR calcular_sumatorio(1000, 501);
IMPRIMIR calcular_sumatorio(500, 1000);

Las tres primeras llamadas a la función no necesitan ahora que les digamos el valor inicial y el valor con el que se incrementan. Cogerán, por defecto, los valores que les hemos dado en los argumentos cuando se ha definido la función. La cuarta llamada a la función, que cuenta el sumatorio sólo de los pares, sí necesita sobreescribir esos dos argumentos. Las dos últimas sólo sobreescriben el primero, porque el del incremento va a ser uno.

De esta forma, si tenemos valores por defecto, podemos definirlos en los argumentos de nuestras funciones. Así, le dejamos al programador la opción de indicarlos o no.

Lo que no serviría sería intentar calcular el sumatorio de 1 hasta 1000 yendo de dos en dos de esta forma: calcular_sumatorio(1000, 2). La razón es sencilla, haciéndolo así, la función cree que el 2 es el valor inicial y, por tanto, contará desde el 2 hasta el 1000 pero de uno en uno, ya que obviamente ve sólo dos argumentos y no sabe que nos estamos refiriendo al tercero en vez de al segundo.

Algunas funciones que ya hemos visto

Cada lenguaje de programación tiene definidas, por defecto, ciertas funciones que realizan ciertas instrucciones que se suelen repetir bastante o son de extrema utilidad.

En el artículo sobre los arrays en PHP vimos, por ejemplo, las funciones unset() para eliminar un elemento de un array y count() para contar todos los elementos de un array. En próximos artículos iremos viendo cada vez más y más funciones predefinidas para realizar ciertos cálculos sobre enteros o flotantes (calcular raíces cuadradas, por ejemplo), arrays (comparar strings) u otras funciones para uso de base de datos entre otras.

Mucho más por delante con las funciones

Hay muchas, muchísimas cosas aún que decir de las funciones, de los argumentos, de cómo utilizarlas y de decenas de cosas que se pueden hacer o no con ellas. Pero para una presentación básica, nos sirve lo visto, que será la forma más común de utilizarlas.

Presentando, pues, las funciones, tenemos una herramienta más para empaquetar código y reutilizarlo cuantas veces queramos. Realmente no hemos añadido ninguna funcionalidad nueva, pues lo que hacemos ahora lo podíamos hacer antes también. Pero la posibilidad de tener estos bloques de código para reutilizarlos a nuestro antojo abre un mundo de enormes posibilidades.

Deja una respuesta