03: Funciones

Introducción

El trozo de código más largo que hemos visto hasta ahora tenía sólo cinco líneas. Los programas de varias miles de líneas parecen quedarnos aún muy lejos, pero debido a la naturaleza de Objective-C, debemos discutir la forma de organizar los programas en esta etapa temprana.

Si un programa consistiese en una sucesión larga y continua de instrucciones sería difícil encontrar y reparar errores. Además, una serie concreta de instrucciones podría aparecer en varias partes de tu programa. Si hubiese en ellas algún error, deberías arreglar el mismo error en varios lugares. Eso sería una pesadilla porque sería fácil olvidarse de uno (o varios). Por tanto, la gente ha pensado una solución para organizar el código, facilitando la corrección de errores.

La solución a este problema es agrupar las instrucciones dependiendo de la tarea que realicen. Por ejemplo, tienes una serie de instrucciones que calculan el área de un círculo. Una vez que has comprobado que esas instrucciones funcionan correctamente, nunca tendrás que volver a ese código para examinar si hay algún error en él. El conjunto de instrucciones, llamado función (function en inglés), tiene un nombre y puedes llamarlo por ese nombre cada vez que necesites que se ejecute ese código. Este concepto de usar funciones es fundamental, de hecho siempre hay al menos una función en un programa: la función main(). Esta función main() es la que busca el compilador para saber por donde debe empezar la ejecución del programa.

La función main()

Pasemos a estudiar la función main() con más detalle. [1]

//[1]
main()
{
    // Cuerpo de la función main(). Escribe aquí tu código.
}

La sentencia [1.1] muestra el nombre de la función, en este caso "main", seguido de la apertura y cierre de paréntesis. Es obligatorio que exista esta función main(), que por otro lado es una palabra reservada (lo que significa entre otras cosas que no podemos usarla como nombre para nuestras variables). Cuando creemos nuestras funciones podremos darles el nombre que queramos. Los paréntesis están ahí por una buena razón, pero la conoceremos más adelante en este capítulo. En las siguiente líneas [1.3, 1.5], hay llaves. Debemos poner nuestro código entre esas llaves { }. Cualquier cosa entre las llaves es lo que llamamos el cuerpo de la función. He copiado código del primer capítulo y lo he puesto aquí en donde corresponde [2].

//[2]
main()
{
    // A continuación se declaran las variables
    float anchoDelDibujo, altoDelDibujo, superficieDelDibujo;
    // Asignamos un valor inicial a las variables
    anchoDelDibujo = 8.0;
    altoDelDibujo = 4.5;
    // Aquí se realiza el cálculo
    superficieDelDibujo = anchoDelDibujo * altoDelDibujo;
}

Nuestra primera función

Si escribimos todo nuestro código en el cuerpo de la función main(), eso nos llevaría al problema del código desestructurado y difícil de depurar que queremos evitar. Así que escribamos otro programa, ahora con un poco de estructura. Además de la función main() obligatoria crearemos una función calculaAreaDelCirculo() [3].

//[3]
main()
{
    float anchoDelDibujo, altoDelDibujo, superficieDelDibujo;
    anchoDelDibujo = 8.0;
    altoDelDibujo = 4.5;
    superficieDelDibujo = anchoDelDibujo * altoDelDibujo;
}
calculaAreaDelCirculo()   // [3.9]
{
}

Ha sido fácil, pero nuestra función definida desde la línea [3.9] aún no hace nada. Observa que la especificación de la función está fuera del cuerpo de la función main(). En otras palabras, las funciones no están anidadas.

Queremos que nuestra nueva función calculaAreaDelCirculo() sea llamada desde la función main(). Veamos cómo podemos hacerlo [4].

//[4]
main()
{
    float anchoDelDibujo, altoDelDibujo, superficieDelDibujo,
        radioDelCirculo, superficieDelCirculo;  // [4.4]
    anchoDelDibujo = 8.0;
    altoDelDibujo = 4.5;
    radioDelCirculo = 5.0; // [4.7]
    superficieDelDibujo = anchoDelDibujo * altoDelDibujo;
    // ¡Aquí es donde llamamos a nuestra función!
    superficieDelCirculo = calculaAreaDelCirculo(radioDelCirculo); // [4.10]
}

Nota: no mostramos el resto del programa (ver [3]).

Pasar argumentos a la función

Hemos añadido un par de nombres de variable de tipo float [4.4], y hemos inicializado la variable radioDelCirculo dándole un valor [4.7].
Tiene más interés la línea [4.10], en la que llamamos a la función calculaAreaDelCirculo(). Como puedes ver, el nombre de la variable radioDelCirculo se ha puesto entre paréntesis. Es un argumento de la función calculaAreaDelCirculo(). El valor de la variable radioDelCirculo se pasa a la función calculaAreaDelCirculo(). Cuando la función calculaAreaDelCirculo() ha hecho su tarea debe devolver un valor, en este caso el resultado del cálculo de la superficie. Modifiquemos el código de la función calculaAreaDelCirculo() [5].

Nota: sólo se muestra el código de la función calculaAreaDelCirculo().

//[5]
calculaAreaDelCirculo(float radio) // [5.1]
{
    float area;
    area = 3.1416 * radio * radio;  // pi veces el cuadrado del radio [5.4]
    return area;
}

En [5.1] definimos que se requiere un valor de tipo float como entrada para la función calculaAreaDelCirculo(). Cuando se recibe, ese valor es almacenado en una variable llamada radio. Usamos una segunda variable, area, para almacenar el resultado del cálculo en [5.4], así que la declaramos en [5.3] de la misma forma que hemos declarado variables en la función main() [4.4]. Verás que la declaración de la variable radio se ha hecho dentro de los paréntesis [5.1]. La línea [5.5] devuelve el resultado a la parte del programa desde la que fue llamada esta función. Como consecuencia, en la línea [4.10], se asigna ese valor a la variable superficieDelCirculo.

La función en el ejemplo [5] está completa, excepto por una cosa. No hemos especificado el tipo de datos que devolverá la función. El compilador nos va a requerir ese dato, así que no nos queda otra opción que obedecerle e indicar que es de tipo float [6.1].

//[6]
float calculaAreaDelCirculo(float radio)  //[6.1]
{
    float area;
    area = 3.1416 * radio * radio;
    return area;
}

Como indica la primera palabra de la línea [6.1], el dato devuelto por esta función (en este caso el dato devuelto por la variable area), es de tipo float. Como programador, debes asegurarte de que la variable superficieDelCirculo en la función main() es también de ese tipo, para que el compilador no nos moleste sobre ese asunto.

No todas las funciones requieren argumentos. Si no hay ninguno, los paréntesis siguen siendo obligatorios, aunque no tengan contenido.

//[7]
int tiraElDado()
{
    int numeroDePuntos;
    // Aquí se escribiría código para generar un número aleatorio entre 1 y 6
    return numeroDePuntos;
}

Devolución de valores

No todas las funciones devuelven un valor. Si una función no devuelve un valor, entonces es de tipo void (que significa "vacío"). En este caso, la sentencia return es opcional. Si la usas, entonces la palabra return debe ir sola, sin indicarle a continuación un valor o nombre de variable.

//[8]
void alarmaXVeces(int x);
{
    // Código para hacer que suene la alarma x veces
    return;
}

Si la función tiene más de un argumento, como en la función calculaAreaDelDibujo() que está a continuación, los argumentos van separados por comas (,).

//[9]
float calculaAreaDelDibujo(float ancho, float alto)
{
    // Código para calcular la superficie...
}

Por convenio, la función main() debería devolver un entero y, por tanto, debería tener también una sentencia return. Debería devolver 0 (cero, [10.9]) para indicar que todo se ha ejecutado sin problemas. Ya que devuelve un entero, debemos escribir int antes de main() [10.1]. Pongamos junto todo el código que tenemos.

//[10]
int main()  // [10.1]
{
    float anchoDelDibujo, altoDelDibujo, areaDelDibujo,
       radioDelCirculo, superficieDelCirculo;
    anchoDelDibujo = 8;
    altoDelDibujo = 4.5;
    radioDelCirculo = 5.0;
    areaDelDibujo =  anchoDelDibujo * altoDelDibujo;
    superficieDelCirculo = calculaAreaDelCirculo(radioDelCirculo);      // [10.8]
    return 0;      // [10.9]
}
float calculaAreaDelCirculo(float radio)           // [10.12]
{
    float area;  // [10.14]
    area = 3.1416 * radio * radio;
    return area;
}

Hacer que todo funcione

Como puedes ver en [10], tenemos una función main() y otra función que hemos definido nosotros mismos [10.12]. Si intentásemos compilar este código, el compilador lo rechazaría. En la línea [10.8] indicaría que no conoce ninguna función llamada calculaAreaDelCirculo(). ¿Por qué? Aparentemente el compilador comienza leyendo la función main() y de repente encuentra algo que desconoce. No va más allá y nos muestra este aviso. Para satisfacer al compilador, simplemente debemos añadir una declaración de función antes de la línea con el main() [11.1]. No tiene complicación, ya que es la misma línea que en [10.12] excepto que termina con punto y coma (;). Ahora el compilador no se llevará una sorpresa cuando se encuentre la llamada a esa función.

//[11]
float calculaAreaDelCirculo(float radio);  // [11.1] declaración de la función 
int main()
{
    // Aquí va el código de la función main...
}

Nota: no se muestra aquí el resto del programa (ver [10]).

En seguida compilaremos el programa en la realidad. Pero antes un par de comentarios.

Cuando escribas programas es importante que intentes tener en mente la posibilidad de reutilizar tu código en un futuro. Nuestro programa podría tener una función calculaAreaDelRectangulo() tal como la que se muestra a continuación [12], que podría llamarse desde la función main(). Esto sería útil incluso aunque sólo se llamase a esa función una vez. La función main() sería más fácil de leer. Si tuviéramos que depurar el código sería más fácil encontrar el error analizando cada función que siguiendo una larga secuencia de instrucciones.

//[12]
float calculaAreaDelRectangulo(float largo, float ancho)  // [12.1]
{
    return (largo * ancho); //[12.3]
}

Como puedes ver, en un caso simple como este, es posible agrupar en una sola instrucción el cálculo y la devolución del resultado [12.3]. En [10.14] usé la variable area simplemente para mostrar cómo declarar una variable dentro de una función.

Aunque las funciones que definimos en este capítulo son bastante sencillas, es importante darse cuenta de que se puede modificar el contenido de una función sin que ello afecte al código que la llama. Lo que no debe cambiarse es la declaración de la función (es decir, su primera línea).

Por ejemplo, podemos cambiar el nombre de las variables internas de la función y seguirá trabajando (y esto no influirá en el resto del programa). Alguien podría escribir la función y tú podrías utilizarla sin conocer su interior. Todo lo que necesitas es saber cómo usarla. Ello implica conocer:

  • el nombre de la función
  • el número, orden y tipo de cada argumento
  • Lo que devuelve la función y el tipo del resultado

En el ejemplo [12], esas respuestas son, respectivamente:

  • calculaAreaDelRectangulo
  • Dos argumentos, ambos de tipo float, siendo el primero el alto y el segundo el ancho.
  • La función devuelve la superficie, y el resultado es de tipo float (como podemos deducir de la primera palabra de la línea [12.1]).

Variables protegidas

El código de cada función está protegido del programa principal y de cualquier otra función.

Esto significa que el valor de una variable interna de una función por defecto no puede ser modificado por ninguna otra variable de ninguna otra función, incluso aunque tuvieran el mismo nombre. Esta es una característica esencial de Objective-C. En el capítulo 5 volveremos a discutir este comportamiento. Pero antes vamos a arrancar Xcode y ejecutar el programa anterior [10].

Post new comment

The content of this field is kept private and will not be shown publicly.
Enter the code shown in the image:

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
6 + 2 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.

Donate!





If you like what you find here and wish to support further development of this site, please donate via PayPal. No account required.

Syndicate

Syndicate content

User login

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
1 + 10 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
Enter the code shown in the image: