miércoles, 9 de noviembre de 2011

Por qué creo que Objective-C es mejor que Java

Hace unos días @GMilano hacía una comparación en Twitter donde decía que
Android vs iOS
IDEs:Eclipse > XCode
Language: Java > Objective-C
Framework: Cocoa > Android
Emulator: iOS > Android
Analysis: iOS > Android
y mi respuesta fue que
Casi de acuerdo, solo que Objective-C > Java... Pero, no es algo evidente al principio.
Esa respuesta tiene tiene una justificación, pero como verán lleva un poco más de 140 caracteres.

Aclaraciones:
  1. Trabajo con Objective-C desde hace unos dos años, pero hace mucho que no programo en Java en serio. Si cometo algún error en la comparación agradezco que me lo hagan notar.
  2. Hasta hace no mucho, tenía la idea de que todos los lenguajes de programación "modernos" eran más o menos equivalentes. Si tienen esa misma idea, primero lean este artículo de Joel Spolsky: Can your programming language do this?
  3. Muchas veeces uno no puede elegir (iOS = Objective-C, Android = Java), pero no por eso la comparación deja de ser válida :)
Extensibilidad de clases estándar

En Objective-C, uno puede agregar métodos a las clases estándar. Digamos por ejemplo que uno quiere agregar el método year a la clase NSDate para invocarlo con
int year = [myDate year];
en vez de hacer
NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSYearCalendarUnit fromDate:myDate];
int year = [comp year];
Eso se puede hacer de forma muy simple, creando una "category" con la implementación
@interface NSDate (Helpers)
- (int)year;
@end
@implementation NSDate
- (int)year {
    NSDateComponents *comp = [[NSCalendar currentCalendar] components:NSYearCalendarUnit fromDate:self];
    return [comp year];
}
@end
Esto en Java no es posible. Se puede crear una subclase, o hacer un método estático en alguna otra clase, pero no modificar las clases ya existentes.

Blocks y selectors

En Objective-C, se pueden definir métodos que reciban un bloque de código o un "selector" (básicamente es el nombre de un método). En Java el pasaje de funciones por parámetro es bastante más complicado e involucra crear una clase específica que contenga el método.

Pasar funciones o bloques de código por parámetro permite por ejemplo implementar el método map: en la clase NSArray (combinando con lo que decía más arriba de las categories) de esta forma
- (NSArray *)map:(id (^)(id element))block {
  if (!self) {
    return nil;
  }
  NSMutableArray *tempArray = [[NSMutableArray alloc] initWithCapacity:[self count]];
  for (id element in self) {
    [tempArray addObject:block(element)];
  }
  return [tempArray autorelease];
}
¿Cuál es la gracia? Que si quiero construir un array a partir de otro, solo tengo que pasarle al método map: el bloque de código de la transformación, sin tener que escribir todo el código accesorio: crear el nuevo array, iterar, manejo de memoria, casos de borde (if !self), etc.

Además si en algún momento se hace alguna optimización o algún arreglo, queda para todos los que lo usan.

Manejo de memoria

En lo que tiene que ver con el manejo de memoria, tanto Objective-C como Java tienen Garbage Collector.

Claro, eso no es cierto para el caso de iOS... donde Objective-C usa una técnica llamada "reference counting". Si bien esto es más complejo para el programador, es mejor en tiempo de ejecución (si se hace bien) porque la memoria se libera en el momento que se deja de usar, no hay que esperar por un proceso que lo haga (GC)

Antes de iOS 5, era el programador que tenía que encargarse de retener/liberar los objetos, cosa que es bastante tediosa al principio y genera buena parte de los errores que cometen los novatos.

Con la liberación de iOS 5 y las herramientas asociadas, se incluye una nueva opción: dejar que el compilador se encargue. Esto se llama Automatic Reference Counting (ARC) y tiene lo mejor de los dos mundos: es mejor en tiempo de ejecución y no es una carga para el programador.

Sintaxis

Con respecto a la sintaxis, tengo que reconocer que ahí sí, Java le gana  a Objective-C. Tener que acceder a un elemento de un array con
[myArray objectAtIndex:0];
es bastante tedioso...

Por eso decía en Twitter que no es evidente que Objective-C es mejor que Java, porque la primer impresión que uno se lleva con el lenguaje es que es bastante complicado, sintácticamente hablando.

Conclusión

Estas son algunas de las diferencias que tienen ambos lenguajes. Seguramente hay muchas más, y alguno tendrá votos a favor para cualquiera de los dos lenguajes. Lo que quería con este post era justificar mi respuesta en Twitter, dando mi punto de vista al respecto.

En una próxima entrega agregaré también la comparación con C# y Ruby...

8 comentarios:

  1. Hola Marcos,

    Personalmente creo que realizar una comparación entre los dos lenguajes es difícil. Ambos se encuentran actualmente en proceso de evolución y tengo entendido que la próxima versión de Java incorporará muchas características "prestadas" de C# como LINQ, expresiones Lambda y hasta un runtime dinámico.

    Habiendo dicho esto, personalmente prefiero Objective-C. Si bien creo que la notación de corchetes permite pensar mejor en términos de "enviar mensajes a objetos" , desde mi punto de vista la "killer app" de Objective-C es ser un super conjunto de C, permitiendo "bajar" al hardware y exprimir hasta la última gota de performance para tareas intensivas de cómputo.

    Laboralmente, también trabajo con Objective-C desde hace unos dos años.

    ¡Espero con ansias las próximas comparaciones!

    Saludos!

    ResponderEliminar
  2. Varrojo: Es verdad que están en proceso de evolución, la comparación se refiere al estado actual de los lenguajes...

    ResponderEliminar
  3. es interesante lo que planteas pero también discutible. Para mi los keyword messages (myArray objectAtIndex:0) son superiores a cualquier otra notación.
    No se como es en Objective-C pero tengo 2 comentarios:
    1. Supongo que Objective-C tiene autocompletation, por lo que la escritura del mensaje al objeto NO debería ser un problema.
    2. Podes ir a la clase Array e implementar algo asi:
    Array
    at: index
    ^self objectAtIndex: index

    Y ahora tenes disponible el mensaje #at:

    myArray at: 4


    Coincido que tener Bloques es una ventaja abismal sobre cualquier otro lenguaje (orientado a objetos) que no los tenga.

    Saludos,
    Bruno

    ResponderEliminar
  4. Bruno:

    La sintaxis de Objective-C es poco intuitiva para cualquiera que haya programado en C, C++, C#, Java, Ruby, Perl, Python, PHP, etc. Capaz que no para alguien que viene de Smalltalk :)

    Con respecto a implementar el método "at:", sí, se puede, pero ese era solo un ejemplo. Es algo más general, impuesto capaz por las APIs. Por ejemplo, el método para filtrar elementos de un array es "filterArrayUsingPredicate:", que es descriptivo, pero en cualquier otro lenguaje se llamaría simplemente "filter:"

    Autocompletion tiene, por suerte!

    ResponderEliminar
  5. Fabuloso.

    De todo lo que han detallado, concluyo en que solo hay buenas noticias para este lenguaje de programación. Respecto a lo poco intuitivo que puede ser Objective-C, tu sabes que el hombre es un animal de costumbre, por lo que es cuestion de acostumbrarse a este pequeño detalle de forma.

    Muchas gracias por aclararme la mente!

    ResponderEliminar
  6. Es una cuestion de principios. ¿porque utilizar un nuevo concepto si se puede utilizar uno existente? ¿porque utilizar Bloques si se pueden utilizar interficies (tambien anonimas)?¿porque añadir funciones si se pude extender la clase? igual serciria para c# ¿porque utilizar propiedades si se pueden utilizar funciones?
    Para mi mas simple significa mas abstracto y por lo tanto mas escalable.

    ResponderEliminar
  7. Java le da mil patadas al Objective C, es mejor hacer las cosas de una manera más abstracta i no permitir hacer de todo a los programadores bajando a bajo nivel. El resultado codigos leibles i perfecta orientación a objetos.

    ResponderEliminar
    Respuestas
    1. Neee, apple y su software es robusto gracias a Obj-C y su perfecta estrutura, quierase o no iOs está mucho mejor construido que Android.

      Eliminar