Una de las características que más llamó la atención cuando Apple presentó SwiftUI fue esa sentencia some que aparecía en la propiedad body necesaria para implementar el protocolo View en el que se basa todo el framework. Esto es necesario para SwiftUI pero es una de las nuevas características del lenguaje Swift 5.1 y se denominan tipos opacos.
Un tipo opaco se aplica cuando una función (o variable calculada) retorna un protocolo y obliga a que el tipo devuelto sea conocido en tiempo de compilación y siempre sea el mismo. Es decir, si mi función devuelve -> some Protocolo y Tipo1 y Tipo2 se conforman a ese protocolo, no puedo devolver unas veces Tipo1 y otras Tipo2, tengo que devolver uno u otro siempre. Otra forma de verlo es que el llamante de la función o variable calculada necesita que el tipo no varíe en tiempo de ejecución.
Ahora vamos a crear un tipo de cada y una enumeración que represente las dos opciones. Además seleccionamos una de las opciones (en seguida veremos para qué).
Luego creamos la siguiente propiedad calculada (si no va a recibir parámetros, ¿para qué vamos a hacer una función con los bonito que queda así?). Devolverá un tipo conformado a Persona, pero debido a la condición que hemos escrito, puede ser de tipo Pintor o Escritor.
Esto es perfectamente válido, no hay errores al compilar y se ejecuta sin problemas. Y estaréis pensado: ¿para qué me cuentas entonces este rollo? Porque la cosa cambia si añadimos some y hacemos que devuelva un tipo opaco.
Y vaya si cambia porque ni compila… El error es Function declares an opaque return type, but the return statements in its body do not have matching underlying types. Básicamente que estamos definiendo como retorno un tipo opaco pero estamos devolviendo dos tipos diferentes. En cambio, si devolvemos sólo un tipo, el error desaparece:
Recordemos que en Swift 5.1 también es posible omitir return cuando devolvemos una expresión simple.
Esto funciona a las mil maravillas pero quiero añadir una condición para que se muestre (o no) el saludo en más idiomas. Para ello tengo que agrupar los Text en un HStack.
Y aquí vemos que muestra el mismo error que antes porque una vez devuelvo un Text y otra un HStack y aunque ambos se conforman al protocolo View al tener que ser opaco el tipo devuelve, siempre tiene que coincidir.
Está claro que podemos hacer de forma sencilla un par de cambios y conseguir lo que queremos. Por ejemplo, esta solución si compilaría:
En este caso, HStack recibe uno o varios View y devuelve un tipo que se conforma también a View permitiendo cumplir la condición de los tipos opacos.
O así lo veo yo pero seguro que alguien puede aportar algo más, si es así, tenéis la caja de comentarios.

Definición informal
Seguro que no va a ser la definición más formal pero al menos es la que yo entiendo. Porque siendo sincero, se me ha atragantado un poco comprender el funcionamiento y sobretodo el fin que persiguen los tipos opacos en Swift.Un tipo opaco se aplica cuando una función (o variable calculada) retorna un protocolo y obliga a que el tipo devuelto sea conocido en tiempo de compilación y siempre sea el mismo. Es decir, si mi función devuelve -> some Protocolo y Tipo1 y Tipo2 se conforman a ese protocolo, no puedo devolver unas veces Tipo1 y otras Tipo2, tengo que devolver uno u otro siempre. Otra forma de verlo es que el llamante de la función o variable calculada necesita que el tipo no varíe en tiempo de ejecución.
Ejemplo
Si os acaba de explotar la cabeza, como a mí cuando leía las distintas definiciones por la red, creo que con un pequeño ejemplo es más fácil de asimiliar. Tenemos el protocolo Persona y los tipos Pintor y Escritor definidos así:
Ahora vamos a crear un tipo de cada y una enumeración que represente las dos opciones. Además seleccionamos una de las opciones (en seguida veremos para qué).

Luego creamos la siguiente propiedad calculada (si no va a recibir parámetros, ¿para qué vamos a hacer una función con los bonito que queda así?). Devolverá un tipo conformado a Persona, pero debido a la condición que hemos escrito, puede ser de tipo Pintor o Escritor.
Esto es perfectamente válido, no hay errores al compilar y se ejecuta sin problemas. Y estaréis pensado: ¿para qué me cuentas entonces este rollo? Porque la cosa cambia si añadimos some y hacemos que devuelva un tipo opaco.

Y vaya si cambia porque ni compila… El error es Function declares an opaque return type, but the return statements in its body do not have matching underlying types. Básicamente que estamos definiendo como retorno un tipo opaco pero estamos devolviendo dos tipos diferentes. En cambio, si devolvemos sólo un tipo, el error desaparece:

Recordemos que en Swift 5.1 también es posible omitir return cuando devolvemos una expresión simple.
SwiftUI
Empezamos hablando de SwiftUI así que vamos a ver los tipos opacos en acción con una ejemplo de lo que no se podría hacer debido a esta característica. Partimos del siguiente código:
Esto funciona a las mil maravillas pero quiero añadir una condición para que se muestre (o no) el saludo en más idiomas. Para ello tengo que agrupar los Text en un HStack.
Y aquí vemos que muestra el mismo error que antes porque una vez devuelvo un Text y otra un HStack y aunque ambos se conforman al protocolo View al tener que ser opaco el tipo devuelve, siempre tiene que coincidir.
Está claro que podemos hacer de forma sencilla un par de cambios y conseguir lo que queremos. Por ejemplo, esta solución si compilaría:

En este caso, HStack recibe uno o varios View y devuelve un tipo que se conforma también a View permitiendo cumplir la condición de los tipos opacos.
Para qué
No sé si es común o sólo me pasa a mi, pero una vez entendido un concepto, la siguiente pregunta es buscar la razón por la cuál existe. En este caso, los tipos opacos complementa la programación orientada a protocolos, y proporcionan más flexibilidad en casos en los que antes necesitábamos devolver tipos y no podríamos utilizar protocolos. Por otra parte, desconozco cómo está implementado SwiftUI por dentro, pero seguro que necesita esta característica para poder componer la interfaz, razón por la cuál aunque Swift es software libre, Apple forzó a que se implementase esta propuesta.O así lo veo yo pero seguro que alguien puede aportar algo más, si es así, tenéis la caja de comentarios.
Comentarios
Publicar un comentario