jueves, 11 de abril de 2013

Cosas que me gustaría tener en Objective-C

En los últimos tiempos, el lenguaje Objective-C ha mejorado bastante, como ya hemos comentado en el blog (por ejemplo acá).

Pero (siempre hay un "pero"), igual hay algunas cosas que todavía se podrían mejorar o agregar al lenguaje.


Implementación default para métodos de protocolos

Supongamos que tenemos un @protocol MyProtocol, que define una @property NSArray *someArray.

Cuando uso una variable que está basada en este protocolo (id<MyProtocol> myVar), puedo ver cuantos elementos tiene el array escribiendo
[[myVar someArray] count]
Pero supongamos que esto lo hago muy seguido, entonces quiero cambiar esto, para que el protocolo ya defina la propiedad elementCount para poder usarla como
[myVar elementCount]
¿Cuál es el problema con esto? Que si agrego la propiedad elementCount al protocolo, tengo que implementarla en todas las clases que implementan el protocolo.

Una alternativa sería tener algo así como "method templates", donde se pudiera definir la implementación del método en el protocolo mismo. Estos templates solo podrían usar otros métodos y propiedades definidos en el protocolo.

Templates o módulos

Yendo en la misma línea, hay casos en que una implementación de un método es genérica, sin importar la clase en la que esté.

El ejemplo más claro de esto es con los "singleton". Una posible implementación es la siguiente:
+ (instancetype)sharedInstance {
  static id _sharedInstance = nil;
  static dispatch_once_t onceToken;
  dispatch_once(&onceToken, ^{
      _sharedInstance = [[self alloc] init];
  });
  return _sharedInstance;
}
(tomada de NSHipster, un excelente blog sobre Objective-C, ya que estamos)

Nótese que en esta implementación no se hace nunca referencia a la clase donde está definido el método. Lo único que se requiere es que tenga un método init.

Si tuviera algo equivalente a los módulos de Ruby (cuando se usan como "mixins"), podría simplemente "declarar" que una clase es un singleton, y que eso incluya la implementación del método sharedInstance.

Generics

En las APIs de Objective-C, cuando un método espera recibir un objeto genérico, declara que recibe un id, que indica que puede recibir cualquier tipo de objeto.

Esto es muy útil, y por ejemplo los arrays no controlan el tipo de objeto, por lo que podemos tener por ejemplo un número y un texto en el mismo array.

Sin embargo, hay veces que es útil saber de que tipo son los elementos de una colección, y forzar a que no se agreguen elementos de otro tipo.

Supongamos el caso que tenemos un protocolo que define una propiedad
@property (nonatomic, strong) NSArray *actions;
¿De qué tipo pueden ser las actions? No lo sabemos, a no ser que quien escribió el protocolo haya puesto un comentario... El lenguaje me debería ayudar a que esto quede más claro.

Boxing (y unboxing) de tipos básicos

En Objective-C, los arrays y los diccionarios solo pueden contener objetos, por lo que si queremos guardar por ejemplo un int en un array, tenemos que hacer el "boxing"y pasarlo al array como un NSNumber *.

Si bien no es algo complicado de hacer, por ejemplo;
int someInteger = 1;
NSArray *myArray = [NSArray arrayWithObject: @(someInteger) ];
podría ser el compilador el que se encargue de hacerlo...

Map & Reduce

Las funciones que tiene la API para manipular colecciones, en ciertos aspectos son bastante limitados.

Por ejemplo, no tengo funciones para Map y Reduce, que son muy útiles. Son fáciles de implementar, pero ya podrían venir incluidas.

Otras, por ejemplo para filtrar un array, son demasiado complicadas:
[[someArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^(id evaluatedObject, NSDictionary *bindings) {
  /* filtering code goes here */
}];
Debería poder escribir simplemente
[someArray filterWithBlock:^(id evaluatedObject) {
  /* filtering code goes here */
}];

Conclusión

Por suerte Objective-C es un lenguaje en evolución, así que tal vez podamos contar con alguna de estas cosas en el futuro...

No hay comentarios.:

Publicar un comentario