Clases en Ruby vs Clases en Java
Publicado por Aníbal Rojas 1 Diciembre 2005 en Java, Ruby. Etiquetas: No Tags. english • españolEn Java era así: Uno se vestía con una túnica de color azafrán, se rapaba la cabeza, prendía un poco de velas y varillas de incienso, para después empezar con el mantra "La Clase es el Tipo del Objetoooooo, La Clase es el Tipo del Objetoooooo, La Clase es el Tipo del Objetoooooo, ..."
En Ruby las clases no son tipos, los objetos son tan, pero taaaan plásticos que en realidad la mejor aproximación a saber de que tipo es un objeto es explorar su comportamiento, lo que ha llevado a definir el "Duck Typing". Si el objeto camina como un pato, vuela como un pato, y suena como un pato, entonces no es un objeto Java porque no se parece a Duke ;-)
Esto se refleja en cosas como el método method_missing de la clase Object (raíz de la muy "chata" jerarquía de clases de Ruby) que es invocado cuando un objeto recibe un mensaje que no sabe como manejar, y que permite hace cosas como:
def method_missing( id_metodo )
metodo_invocado = id_metodo.id2name
metodo_invocado.length if metodo_invocado =~ /cua*c/
end
end
de_goma = Pato.new
puts de_goma.cuac # -> 4
puts de_goma.cuaac # -> 5
puts de_goma.cuaaac # -> 6
Que es una clase que responde dinámicamente (devolviendo la longitud de los mensajes "cuac" que le pasan) a un mensaje para el que no encuentra un método definido en forma explícita en ella. El potencial a nivel de Domain Specific Languages está muy bien explicado por Jim Weirich en su presentación del para el RubyConf Speaking the Lingo: Creating Domain Specific Languages in Ruby, el podcast está en Odeo y es burda de ameno.
Una de esas cosas extrañas en Ruby cuando uno viene de Java es que las clases no tienen mucho de particular, empezando con que una clase en Ruby es sencillamente una constante que referencia a un objeto de la clase Class, que por cierto no tiene ni media docena de métodos.
Cuando por algún motivo intentas usar una clase y esta no se encuentra definida, lo que se obtiene es un: uninitialized constant que por supuesto uno no entiende de que va.
La clase Class extiende de Module que es básicamente una colección de métodos y constantes, y que cuando se viene del mundo Java uno intenta reconciliar erróneamente con un Package.
De forma análoga un Módulo en Ruby también es una constante que referencia a un objeto de la clase Module (que si es un hierro), y tiene una vago parecido "funcional" a las interfaces en Java, ya que los módulos en Ruby permiten añadir funcionalidad a un clase sin tener que recurrir a la herencia, ya que en Ruby tampoco existe la herencia múltiple.
En Ruby se utiliza un mecanismo llamado mixin que permite obtener acceso a las constantes, variables de clase y métodos de instancia del módulo que se incluye.
La ventaja de los Módulos Ruby sobre las Interfaces Java para obtener comportamientos predefinidos, es que cuando haces un include de un Module no piensas ¡Cooooooño tengo que implementar tooooooodo ese poco de métodos! Que fastidioooooo....
Cuando uno entiende que el código dentro de una Clase o Módulo Ruby es sencillamente código ejecutable entonces es cuando se da cuenta de porque Java parecia una cómoda y segura camisa de fuerza en lo que a orientación a objetos se refiere, ya que manipular las clases se hace extremadamente natural y por ejemplo cambia un método de privado a público es tan sencillo como:
def metodo_publico
"hola"
end
private
def metodo_privado
"adios"
end
end
o = MiClase.new
begin
puts "Va a generar un error"
puts o.metodo_publico
puts o.metodo_privado
rescue
puts $!
end
class MiClase
public(:metodo_privado)
end
begin
puts "Ya el método es público"
puts o.metodo_publico
puts o.metodo_privado
rescue
puts $!
end
Lo que genera la salida:
hola
private method 'metodo_privado' called for #<miclase :0x2bd0da0>
Ya el método es público
hola
adios
La variable $! es un perlismo (en vías de extinción por lo que entiendo) en Ruby, y sencillamente referencia la última excepción que se generó. Y ojo, los métodos public y private son privados, el bochinche tampoco es taaaan así ;-)
Un concepto que existe en Java (pero se usa poco en mi experiencia) es el de la Clase Anónima (Anonymous Class) (Singleton Class) que en Ruby surge por todos lados, y se evidencia cuando se manipula el comportamiento de un objeto específico y no la clase a la que está asociado:
original = lenguaje.dup
class <<lenguaje
def to_s
"#{self} :-("
end
end
puts lenguaje.class # -> String
puts lenguaje.to_s # -> Java :-(
puts original.class # -> String
puts original.to_s # -> Java
El método to_s de Ruby es equivalente al toString de Java, fíjense como ambas variables reportan que su clase es String, pero sólo en una hemos alterado el comportamiento de método to_s.
Ahora, el método to_s pertenece a la clase Object de Ruby, y como en Ruby las clases nunca están cerradas, yo puedo darle una navaja al mono redefiniendo ese método ahí mismo con algo como:
puts o.to_s # -> #object :0x2bd1520
class Object
alias to_s_ANTERIOR to_s
def to_s
"*** #{to_s_ANTERIOR} ***"
end
end
puts o.to_s # -> *** #object :0x2bd1520 ***
Cosa, que en Java sería blasfemia por motivos de seguridad, que es reforzada por la propia jerarquía de los Classloaders, etc ¿Cómo les quedó el ojo? Parafraseando el nombre de un popular libro de Zen, en Ruby "Nada Sagrado" ;-)
Muy buena la explicacion.
Esta barbaro poder entender un poco mas la flexibilidad de ruby con ejemplos claros como los diste
Gracias y esperemos ver mas!!!
Jojojojo si ciertamente java tiene sus detalles y como por ahi decia un conocido es un lenguaje que sacaron y fueron parchando con el tiempo, parchando por aqui y por aca lo que termino en un masacote todo medio planeado. A mi en lo personal me gusta Java y era el lenguaje que usaba, ahorita por el trabajo aprendi y estoy usando Ruby y ROR, la verdad que es muy bueno =D me a gustado bastante aunque todavia no lo domino a la perfeccion =P, pero aun asi me sigue gustando Java.
JAVA FOR EVER ahhh I