oop scala programming-languages haskell functional-programming

oop - Ventajas de los subtipos sobre las clases de tipos.



scala programming-languages (6)

En la actualidad, la sobrecarga sintáctica de las clases de tipo Scala es un poco más grande que para el subtipo a través de la herencia de rasgos, como lo es la sobrecarga potencial en tiempo de ejecución. Imagine un caso en el que necesite que cincuenta tipos diferentes de eventos se ajusten a una interfaz para admitir un motor de procesamiento de eventos. Mucho mas facil de escribir

class MyEvent extends Event{ val name = "foo" }

que

class MyEvent{ val name = "foo" } object MyEvent2Event{ implicit def convert(myEvent:MyEvent) = new Event{ val name = myEvent.name} }

La segunda forma permite mucha más flexibilidad en términos de polimorfismo post-hoc, libertad de nomenclatura y mala evaluación en general, pero al escribir esos cincuenta métodos de conversión y luego realizar las importaciones apropiadas cuando se necesita la clase de tipos será necesario. Un dolor correcto. Si no necesita la flexibilidad, es difícil ver la recompensa. Además, hay una palabra clave "nueva" molesta en la segunda, que generará un sinfín "es esta sobreestensión de los argumentos del recolector de basura".

La situación es peor para la herencia mixta que introduce un estado mutable. Considere el siguiente rasgo, tomado del código de producción:

trait Locking{ private val lock = new ReentrantReadWriteLock() def withReadLock[T](body: => T):T={ try{ lock.readLock.lock() body }finally{ lock.readLock.unlock() } } // same for withWriteLock }

El uso increíblemente práctico de la herencia mixin, y no es realmente factible con las clases de tipo Scala, debido a la presencia del valor "lock". ¿Dónde debería ir? Si lo coloca en la clase adaptada, pierde la mayor parte del valor de encapsulación del rasgo. Si lo pones en el código del adaptador, los bloqueos ya no protegen nada, ya que estarás bloqueando diferentes objetos de bloqueo cada vez que te adaptes.

¿Cuáles son las ventajas de los subtipos OOP sobre las clases de tipos, en su caso? En otras palabras, ahora que tenemos clases de tipos, ¿hay alguna razón para seguir usando el subtipo OOP ?

PD: soy programador de scala.


En un lenguaje que no es puramente funcional, los subtipos le permiten tener diferentes efectos secundarios con el mismo uso; Esto no siempre es fácil de lograr con las clases de tipo. (Puedes lograrlo, por supuesto; a mi me parece más incómodo).

Además, los subtipos pueden ser más eficientes: es una forma de almacenar en caché la información de que "X es una Y" sin necesidad de una conversión repetida (o heroicas de compilación para almacenar en caché esa información) de X a Y. Para jerarquías muy profundas, esto podría ser un problema.



Personalmente, me parece más fácil lidiar con la POO dentro de las limitaciones de lo que maneja bien. En otras palabras: en los casos en que no necesitas clases de tipos, encuentro objetos más fáciles de entender.

Sin embargo, esto podría ser simplemente un artefacto de la sobrecarga sintáctica que tiene la típica incrustación de objetos tipográfica. Si Haskell tuviera azúcar sintáctica para algunos tipos comunes de patrones de clase de tipos, esa diferencia probablemente desaparecería.

Lo que me parece más interesante es el hecho de que la comunidad de Haskell muestra que las clases de tipos son más poderosas que los objetos, ya que existe una incrustación trivial de objetos en las clases de tipos, pero las clases de tipos pueden hacer cosas que los objetos no pueden. La comunidad Scala, sin embargo, muestra que los objetos son al menos tan poderosos como las clases de tipos 1 , ya que existe una incrustación trivial de clases de tipos en los objetos.

Esto parece indicar que la relación entre los dos es mucho más íntima de lo que comúnmente se piensa.

1 Ver Clases tipográficas como objetos e implícitos de Bruno CdS Oliveira, Adriaan Moors y Martin Odersky, así como la discusión de ese artículo sobre Lambda the Ultimate , especialmente este bonito resumen de Paul Snively (énfasis agregado):

Las decisiones de diseño de Martin Odersky y del equipo sobre cómo realizar clases de tipos en un lenguaje OO y FP unificado siguen dando frutos fascinantes. Los implícitos se parecen cada vez menos a las "clases de tipos de hombres pobres", y más y más a una mejora de las clases de tipos , en mi opinión, dada una lectura rápida de este documento.


Una diferencia más para Scala al menos es que las cadenas de subtipos solo funcionan, mientras que las cadenas de tipos de texto son mucho más difíciles. Si tenemos los tipos A, B y C, entonces si A <B y B <C entonces necesariamente A <C. Sin embargo, si A <% B y B <% C no es necesariamente el caso de que A <% C. Esto se debe a que el compilador de Scala no aplicará múltiples conversiones implícitas, ya que de lo contrario tipearía la inferencia porque difícil y (IIRC) potencialmente indecidible.


Una razón pragmática para continuar el soporte para la POO es la interoperabilidad. Una de las preguntas actualmente en curso en la discusión de BitC es si se debe agregar una herencia única al idioma. Hay ventajas y desventajas pragmáticas, y también problemas a favor y en contra en sus implicaciones para el sistema de tipo formal y la inferencia de tipos.

Durante un tiempo, el mecanismo de resolución de instancias para las clases de tipos nos convenció de que las clases de tipos eran fundamentalmente defectuosas por falta de seguridad de enlace. En ausencia de un mecanismo de resolución de ámbito léxico, la resolución de instancia de clase de tipo no se puede escalar en términos humanos: un cambio por parte de un grupo de desarrollo puede causar errores de vinculación en una aplicación escrita en otro lugar por un grupo completamente diferente. Eso nos hizo mirar a regañadientes la herencia única y algún tipo de esquema F < + SelfType. Existen inquietudes relacionadas cuando las instancias tienen múltiples resoluciones con diferentes grados de especialización.

Desde entonces, hemos llegado a un enfoque de resolución de instancias que busca resolver este problema a nuestra satisfacción. La pregunta con la que estamos luchando ahora es (a) si los programas BitC necesitan subtipos, y si es así, y (b) incluso si no es así, si la interoperabilidad con programas en idiomas OO puede requerir que admitamos un sistema de tipos. en el que la herencia es expresable, y en consecuencia un lenguaje en el que se puede utilizar.

Ninguna de las cuales es una respuesta concluyente a la pregunta del OP. El punto, supongo, es que los problemas aquí van más allá del diseño de cualquier lenguaje en particular. También hay factores humanos y problemas de interoperabilidad que deben considerarse.

Jonathan shapiro