VISITAS:

Mostrando entradas con la etiqueta funciones. Mostrar todas las entradas
Mostrando entradas con la etiqueta funciones. Mostrar todas las entradas

martes, 11 de agosto de 2015

SWIFT (VI) FUNCIONES Y CLOSURES

Las funciones son algo típico en todos los lenguajes de programación clásicos. Los closures ya no lo son tanto, al menos, no son tan conocidos, aunque llevan existiendo muchos años en lenguajes tan conocidos como Javascript.

FUNCIONES EN SWIFT

Una función es un bloque de código que puede ser invocado por su nombre para ejecutar una determinada tarea. Puede recibir datos de entrada y puede retornar uno o más resultados. Cuando se define una función se especifican los parámetros de entrada y el tipo del valor retornado (si los hay). Cuando se invoca a una función se pasan datos como argumentos a la función y se puede recoger el resultado en una variable, por ejemplo. Nótese la sutil diferencia entre parámetros y argumentos.

Ejemplo de declaración de una función en swift:

    func suma(operando1 : Int, operando2 : Int) -> Int {
        return operando1 + operando2
    }

Llamada a una función:

    var a : Int = suma(3, 6)

Parámetros externos

En el ejemplo anterior, los nombres de los parámetros son internos a la función y no pueden utilizarse en la llamada, es decir, la llamada se basa únicamente en el orden de los parámetros. Pero a veces es mejor (o más claro) que en la llamada a la función se especifique también el nombre de los parámetros. Para ello se antepone el carácter # al nombre del parámetro:

    func resta(#minuendo : Int, #sustraendo : Int) -> Int {
        return minuendo - sustraendo
    }

Y la llamada:

    var resultado : Int = resta( minuendo : 5, sustraendo : 3)

Parámetros por defecto

Swift permite especificar un valor por defecto para un parámetro (o parámetros) que pudieran no especificarse en la llamada a función. Estos parámetros con valores por defecto deben situarse al final de la lista de parámetros en la declaración de la función. Cuando en un parámetro se especifica un valor por defecto, swift asume que ese parámetro es externo y permite su nombrado en la llamada (ver subapartado anterior "parámetros externos").

    func info(account : Int, owner : String  = "Unknown") -> String {
        return "Account: \(account), owner: \(owner)."
    }

Ejemplos de posibles llamadas a esta función:

    var s1 = info(26351)  --> Account 26351, owner: Unknown.
    var s2 = info(10005, owner : "John")  --> Account 10005, owner: John.

Retornando múltiples valores desde una función

Una función puede retornar múltiples valores de varias formas: retornando un objeto, retornando un array o diccionario, y por último, retornando una tupla. Veamos este último caso.

    func getUserInfo(id : String) -> (nombre : String, apellido : String, dni : Int) {
        // buscar información del usuario en BD por ejemplo
        return ("Juan", "López", "4747563-P")
    }

Llamada a esta función:

    var info = getUserInfo("A3625")
    println("\(info,nombre) \(info,apellido) - \(info.dni)")

Número variable de parámetros

En swift una función puede recibir un número variable de parámetros (puede ser cero). Esto se indica con ...
Dentro de la función los parámetros son un array.

    func printInfo(datos : String...) {
        for s in datos {
            println(s)
        }
    }

Llamada:

    printInfo("a", "b", "c", "d")

Parámetros variables

Los parámetros recibidos por una función son constantes (es como si tuvieran un let delante) y no se pueden modificar dentro de la función.
Si queremos modificar alguno de los parámetros de una función, debemos declararlo variable poniéndole var delante.

    func suma(var operando1 : Int, operando2 : Int) -> Int {
        operando1 += operando2
        return operando1
    }

Esto no significa que el argumento pasado a la función se vaya a modificar, simplemente que podemos cambiar el valor internamente en la función. Para que se modifique el argumento externo, tendremos que utilizar parámetros de entrada/salida, como se describe en el siguiente subapartado.

Parámetros de entrada/salida

Para que una función pueda modificar el valor de un argumento es necesario definir el parámetro correspondiente como inout:

    func duplica(inout valor : Int) {
        valor = 2 * valor
    }

En la llamada tenemos que anteponer el carácter & al argumento (el cual tiene que ser una variable obligatoriamente):

    var v : Int = 4;
    duplica(&v)
    println(v)   --> 8

CLOSURES EN SWIFT

Antes de entrar en las closures, introduzcamos el tema 

Las funciones como tipos de datos

Una característica muy interesante de swift (y de otros lenguajes de programación) es que las funciones pueden ser tratadas como tipos de datos. De esta forma, se puede por ejemplo definir una función y asignarla a una constante o variable:

    func kilometers2Miles(kilometers : Float) -> Float {
        return meters * 0.62137
    }
    let f = kilometers2Miles

Habiendo hecho esa asignación podemos invocar a la función a través de la constante:

    var result = f(100.0)

Lo interesante de esto es que cuando asignamos una función a una constante tenemos todas las capacidades de los tipos de datos. Concretamente, una función puede pasarse como argumento a otra función, o incluso ser retornada de una función.

El tipo de datos de la función lo definen los parámetros y el valor retornado. En el ejemplo anterior, la función recibe un parámetro Float y devuelve un valor Float, por tanto el tipo de esta función sería:

    (Float) -> Float

Por ejemplo, podemos definir una función que reciba otra función como parámetro:

    func invoke( theFunction : (Float) -> Float, value : Float) -> Float {
        return theFunction(value)
    }

Y podemos invocarla así:

    invoke(kilometers2Miles, 34.8)

Igualmente, podemos retornar una función:

    func getFunction() -> (Float) -> Float {
        return kilometers2Miles
    }

Expresiones closure

Una expresión closure es sencillamente un bloque de código. Las expresiones closure se pueden asignar a constantes o variables:

    let f = { println("Hola") }
    f()   --> Hola

Las expresiones closure también pueden recibir parámetros y devolver resultados. Por ejemplo:

    let m = { ( operando1 : Float, operando2 : Float) -> Float in return operando1 * operando2 }
    let v = m(20, 34.2)

La sintaxis es parecida a la de una función, pero no tiene nombre, todo va entre llaves y se utiliza la palabra reservada in para indicar el comienzo del código. De hecho, las funciones swift son expresiones closure con nombre.

Closures

Un closure es un bloque de código (una función o una expresión closure) junto con una o más variables que existen en el contexto de ese bloque de código. Por ejemplo:

    func externa() -> () -> Int {
        var contador = 0
        func interna() -> Int {
            contador += 1
            return contador
        }
        return interna
    }

    let miClosure = externa()
    let resultado = miClosure()

En este ejemplo, la función externa retorna una función interna. Realmente retorna un closure, ya que retorna la función interna más la variable contador, que está declarada en el scope de la función interna. De hecho, cada vez que se llama a miClosure() se va incrementando el contador.












viernes, 9 de enero de 2015

Javascript avanzado: Funciones

Este es el primer artículo de una serie que tengo la intención de escribir sobre javascript avanzado. Empezaré por intentar explicar algunos conceptos avanzados de las funciones en javascript.

Muchos desarrolladores, cuando les preguntan ¿sabes javascript? Responden un sí inmediata y contundentemente. Yo era uno de ellos, hasta hace poco.
Muchos pensábamos que javascript se reduce a una serie de tipos básicos, condiciones if, bucles for/while y declaración de funciones. Algunos incluso hemos utilizado callbacks para eventos en páginas html.
También, muchos pensábamos que javascript se utiliza única y exclusivamente en el desarrollo web, dentro las páginas html. Efectivamente, así empezó javascript. Pero hoy en día, esto no es cierto. Javascript es un lenguaje muy avanzado y que se utiliza en muchos otros entornos además del desarrollo web, por ejemplo, en el desarrollo de aplicaciones para móvil.

Javascript es uno de los lenguajes más avanzados y expresivos que existen actualmente (esto puede sorprender a más de uno). Estas son algunas de sus características destacadas:

  • Rendimiento: Javascript utiliza compilación just-in-time, o sea, se compila y se traduce a código máquina justo antes de ejecutarse. Su rendimiento es similar al de aplicaciones escritas en C o C++. Sin embargo, javascript tiene la penalización de la recolección de basura y enlazado dinámico de tipos (las variables pueden cambiar de tipo dinámicamente).
  • Objectos: Javascript tiene características avanzadas de orientación a objetos. Utiliza el modelo de herencia con prototipos (en lugar de clases, tenemos prototipos de objetos). Este modelo es más potente y flexible que el modelo de herencia con clases utilizado en lenguajes como Java. Javascript también soporta, a pesar de ser poco conocidas, las siguientes características: encapsulación, polimorfismo, herencia múltiple y composición.
  • Sintaxis: La sintaxis de javascript es similar a la de lenguajes como C++, Java, C# o PHP. Esta es una de las causas del éxito de javascript.
  • Funciones: En javascript, casi todo son objetos, incluidas las funciones. Por este motivo, podemos usar una función en cualquier sitio en que podemos utilizar una variable (por ejemplo en un parámetro de una llamada a función). Las funciones que reciben como parámetro una función o retornan una función como resultado, se llaman funciones de alto orden.
  • Reutilización: Javascript es portable, es decir, puede ejecutarse en cualquier plataforma.
Comencemos por tanto explicando algunos conceptos, no demasiado avanzados sobre las funciones en javascript, pero que introducen los conceptos más avanzados que se explicarán posteriormente. En posteriores artículos hablaré del ámbito (scope), closures, this, prototype.

Las funciones son datos

En javascript existen los siguientes tipos:

  • PRIMITIVOS
    • Number: desde 5e-308 hasta 1e+308, Infinity, NaN
    • Boolean: true, false
    • String: "....", '....'
    • undefined: cuando una variable se declara, su valor es undefined
    • null: se puede asignar null a una variable
  • OBJECT
    • Object
    • function

Las funciones son también un dato, concretamente, Object.

var f = function(v) {
    return v+1;
}
typeof f;   // "function"


Funciones de callback

function add(f1, f2) {
    return f1() + f2();
}
var one = function() { return 1; }
var two = function() { return 2; }
add(one, two);   // 3

Funciones inmediatas

Las funciones inmediatas se ejecutan inmediatamente:

(function() {
    alert('hello');
})();

Las funciones inmediatas pueden recibir parámetros:

(function(name) {
    alert('hello '+name);
})('world');
Las funciones inmediatas se pueden utilizar para tareas de inicialización, ya que se ejecutan inmediatamente y todas sus variables locales quedan dentro, en privado.

Funciones privadas

function outer(p1) {
    function inner(p2) {
        return 2 * p2;
    }
    return 10 + inner(p1);
}

La función inner() no es accesible desde fuera.

Función que retorna una función

function a() {
    return function() { return 'A'; };
}

var f = a();   // asigna la función interna a la variable f
f();       // invoca la función interna

También se puede invocar la función interna del siguiente modo:

a()();
Se puede reasignar una función. De esta forma, la primera vez que se ejecuta la función puede realizar labores de inicialización y después su función habitual:

function f() {
    // labores iniciales
    .......
    return function() { ...... labores habituales .... };
}
f = f(); 
   
Otra forma más elegante de reasignar una función:

function a() {
    ... código que se ejecuta la primera vez
    a = function() { ... código habitual .... };
}
Y otra forma más, utilizando funciones inmediatas:

var a = (function() {
    function init() {
        .... inicialización
    }
    function work() {
        .... trabajo real
    }
    init();
    return work;
})();