El misterioso «some»: ¿por qué miles de desarrolladores preguntan sobre él?
\n\nSi alguna vez has escrito en SwiftUI, seguro que has visto la construcción some View. Se ve simple, pero los principiantes a menudo se confunden: «¿Qué es ese «some»? ¿Por qué no puedo escribir simplemente View? ¿Y si quito some — se rompe?». La pregunta «What is the "some" keyword in Swift(UI)?» ha acumulado miles de visitas en Stack Overflow — y no es casualidad. Detrás de una palabra corta se esconde toda una filosofía del Swift moderno.
En este artículo, entenderemos qué es la palabra clave some, por qué apareció en el lenguaje y por qué SwiftUI es impensable sin ella. Aprenderás cómo se relaciona con los genéricos, los protocolos y los «tipos opacos» (opaque types). Y lo más importante — comprenderás cómo escribir código más limpio y eficiente.
\n\nEl problema que resuelve «some»
\n\nImagina que escribes una función que devuelve algún objeto que cumple con el protocolo View. En SwiftUI esto ocurre constantemente:
func makeGreeting() -> View {\n return Text("Hello!")\n}\n\nEl compilador de Swift dirá: «El protocolo 'View' solo puede usarse como una restricción genérica (generic constraint), porque tiene requisitos de Self o associated type». Suena aterrador, pero la idea es simple: el protocolo View en SwiftUI requiere que el tipo se conozca en tiempo de compilación. Si devolvemos View — es una abstracción, y el compilador necesita algo concreto.
Antes, los desarrolladores se las ingeniaban con genéricos:
\n\nfunc makeGreeting<T: View>() -> T {\n return Text("Hello!") as! T\n}\n\nEsto funcionaba, pero parecía un parche: le prometes al compilador que devolverás T, pero en realidad «finges». Además, el código que llamaba a la función debía especificar explícitamente el tipo. Feo e inseguro.
«Some» — el salvador del código repetitivo
\n\nLa palabra clave some en Swift apareció en la versión 5.1 precisamente para estos casos. Le dice al compilador: «Voy a devolver un tipo concreto que cumple con el protocolo, pero no quiero decir su nombre. Tú mismo lo determinas en tiempo de compilación». Esto se llama tipo opaco (opaque type).
Volvamos a nuestro ejemplo:
\n\nfunc makeGreeting() -> some View {\n return Text("Hello!")\n}\n\n¡Ahora el código compila! El compilador sabe que se devuelve exactamente Text, pero desde fuera solo vemos some View. Esto proporciona dos cosas:
- \n
- Seguridad de tipos — el compilador verifica que el tipo devuelto es siempre el mismo. \n
- Encapsulación — ocultamos los detalles de implementación del código que llama. \n
Comparación: «some» vs genéricos vs protocolos
\n\nPara entender mejor la magia de some, comparemos tres enfoques con un ejemplo concreto. Supongamos que queremos escribir una función que devuelva una figura (círculo o cuadrado).
1. Devolver un protocolo (no compilará)
\n\nprotocol Shape {\n func draw()\n}\n\nstruct Circle: Shape {\n func draw() { print("Dibujando círculo") }\n}\nstruct Square: Shape {\n func draw() { print("Dibujando cuadrado") }\n}\n\n// Error: el protocolo 'Shape' no puede usarse como tipo de retorno\nfunc makeShape() -> Shape {\n return Circle()\n}\n\nComo ya sabemos, no funciona si el protocolo tiene associated types o Self requirements.
\n\n2. Uso de genéricos
\n\nfunc makeShape<T: Shape>() -> T {\n // Necesitamos crear T de alguna manera, pero no sabemos el tipo concreto\n fatalError("No se puede crear un genérico")\n}\n\nProblema: el código que llama debe saber qué tipo esperar. La función no puede decidir por sí misma qué devolver.
\n\n3. Uso de «some» (funciona perfectamente)
\n\nfunc makeShape() -> some Shape {\n