Un artículo del Lic. Carlos Peralta, Developer en GlobalLogic Mobile.

En la pasada edición 2015 de la conferencia anual para desarrolladores (WWDC) que Apple organiza anualmente, en la sesión nro. 408, el líder técnico de la librería estándar de Swift, Dave Abrahams, formuló una frase que estimo encerraría mucho marketing, o por lo menos una sobrevaloración de la nueva funcionalidad en el lenguaje. Dave habló no de una nueva característica, sino de una orientación. Una nueva visión y nuevos mecanismos de abstracción en el diseño de sistemas, y para demostrarlo no hace otra cosa que demostrar antes los problemas de la programación orientada a objetos.

De manera un poco confusa, Dave no sólo habla de los protocolos en Swift, sino también de tipos que se representan por valor y no por referencia; lo cual ataca directamente a las clases, base de OOP.

Veamos primero un resumen de lo expuesto por Dave para luego expresar mi opinión al respecto:

Los tres problemas con las clases (tipo base y principal de la OOP):

  1. Implicit sharing of mutable state: cuando dos instancias apuntan o referencian a una misma propiedad, una de esas instancias puede hacer un cambio al cual la otra, en otro momento, puede querer acceder esperando un valor original; pero se encuentra con el valor cambiado por la primera. Esto se puede solucionar realizando copias, lo cual lleva a la siguiente secuencia de problemas:

Es ineficiente: se abusa de las copias, lo cual hace al sistema más lento. Para solucionarlo se crean colas y multi hilos los cuales nos llevan a race conditions. Para solucionar este último problema utilizamos locks; lo cual crea ineficiencia terminando en Deadlocks, lo cual genera más ineficiencia, que se resume en… más bugs.

Queda claro que la solución de realizar copias entre instancias tiene un costo. (De esta forma queda abierta la solución que se propone luego con el uso de structs y enums; tipos que se pasan por valor y Swift maneja inteligentemente, limpiando cuando pierden contexto).

  1. Herencia pesada, limitada e intrusiva:
  • Las clases sólo se pueden heredar de una clase padre.
  • Al heredar tenemos todas las propiedades y métodos del padre, y siendo que sólo podemos necesitar parte de las mismas, hay un peso extra.
  • Al momento de crear la clase debemos decidir cuál será la clase base. Esto nos fuerza a tomar decisiones de diseño en tiempo de codificación que determinarán y/o acotarán las futuras modificaciones sobre el diseño inicial. No es un modelo retroactivo.
  • Las propiedades de la clase base se debe aceptar lo cual no sólo genera una carga extra para la subclase sino que complica los inicializadores.
  • Hay que tener cuidado de no cambiar las invariantes (propiedades de clase).
  1. Se pierden las relaciones entre los tipos:
  • Cuando se realizan downcasts, casi siempre es una señal que se perdió una relación entre las clases.              
  • No es posible realizar una referencia entre la clase y su padre: this – other

 

Estos 3 problemas nos llevan a la necesidad de crear un nuevo mecanismo de abstracción, según Dave:

  • Que soporte value types (y clases),
  • Que no fuerce a heredar sólo de una clase,
  • Que soporte el modelado retroactivo: extender luego las clases; no en momento de la creación,
  • Que no imponga un modelo de datos,
  • Que no sume carga a los inicializadores,
  • Que deje bien claro qué hay que implementar.

 

Finalmente se presenta la solución: protocolos, structs y enums.

Mediante protocolos (que no son más que interfaces en otros lenguajes, con la posibilidad de poseer una implementación predeterminada a través de extensiones), se presenta un nueva “orientación”. El diseño se inicia planteando los protocolos y luego los tipos se pasan por valor (structs y enums) que lo implementan. Swift los maneja inteligentemente, limpiando cuando pierden contexto.

Dave también muestra cómo a través de cláusulas de filtro (where) se pueden aplicar protocolos en relación a otros. También menciona el uso de generics con protocolos.

De esta forma queda demostrado cómo es posible saltar los 3 problemas mencionados en relación a las clases y OOP. (Nota del Autor: para ver código, por favor ver los ejemplos en el vídeo de la sesión)

Argumentos previos a la conclusión

La programación orientada a objetos tiene muchos años de experiencia y teoría que fundamentan su existencia. Algo me hacía ruido: ¿sólo una funcionalidad de interfaz con posibilidad de implementaciones predeterminadas, más dos tipos de valor, podrían ponerse al nivel de OOP? No lo creo.

Sin duda es una característica potente; pero no reemplaza ni es necesario hablar de “programación orientada a protocolos”. Creo que es un característica complementaria, no reemplazante, y tal denominación se presta a la confusión.

OOP tiene mecanismos de abstracción prácticos como la encapsulación, el polimorfismo y la herencia, que claramente tienen su lugar.

Formular esa frase para describir una nueva funcionalidad confunde y busca, a mi parecer, publicidad.

Java, en su versión 8, trae una nueva funcionalidad llamada “métodos predeterminados” (default methods). Si vemos, claramente son interfaces con implementación predeterminada, lo cual permite tener casi lo mismo que con los protocolos. Sin embargo, no por ello Oracle salió en una conferencia oficial a decir: “Tenemos un nueva programación orientada a métodos predeterminados”.

Veamos código:

interface InterfaceA {

public void saySomething(); 

default public void sayHi() {
      System.out.println(“Hi”);
    }
}

public class MyClass implements InterfaceA {
   public static void main(String[] args) {
       // TODO code application logic here
   }

  @Override
   public void saySomething() {
       System.out.println(“Hello World”);
   }
}

Más detalles sobre lo métodos predeterminados de Java 8 en este artículo

Queda claro que Java 8 ya tiene interfaces con implementaciones predeterminadas. De todas formas, tengamos en cuenta algunas diferencias entre las interfaces de Swift y Java:

  • Swift permite definir propiedades, además de definir métodos como en Java.
  • Swift puede combinar protocolos y exigir, por ejemplo, que un parámetro de una función implemente 2 protocolos:

func foo ( var1 : protocol<A, B> ){}

  • Ambos permiten implementaciones predeterminadas en los protocolos a través de las extensiones. Pero, a diferencia de Java, Swift permite realizarlo retroactivamente.
  • Swift permite filtrar, a través de patrones, dónde y cómo los requerimientos del protocolo son implementados.

 

Si bien estas últimas características hacen de los protocolos en Swift una herramienta algo más avanzada que las interfaces en Java; no creo que sea suficiente para hablar de una nueva orientación de programación; ni de una idea novedosa o única.   
Conclusión:

Es una sobrevaloración de la nueva funcionalidad del lenguaje. Los protocolos en Swift no son más que interfaces con posibles implementaciones predeterminadas, lo cual no es único ni novedoso en relación a otros lenguajes modernos y maduros.

De todas formas encuentro dos puntos muy interesantes en la charla de Dave: el modelado retroactivo y el lema que utilizan internamente en la librería de Swift; “comienza con el protocolo”. Estos puntos pueden llegar a definir una “orientación” en el momento de diseñar un sistema, pensando en la posibilidad de extender clases de la librería base o propia luego del diseño inicial, gradualmente (modelado retroactivo); además de pensar en definir las interfaces como primer paso. Pero de ninguna forma es un nuevo paradigma de programación al nivel de OOP.

Es una nueva funcionalidad del lenguaje muy potente, nada más. Estimo que Dave y Apple como es usual, intentan vender a Swift sumando palabras claves y  marketineras.