22

¿Cuáles son las ventajas de OOP subtipificación sobre clases de tipos, si las hay? En otras palabras, ahora que tenemos clases de tipos, ¿hay alguna razón para seguir utilizando OOP subtipificación?Ventajas del subtipado sobre clases de tipos

PD: Soy un programador de Scala.

+0

@JoshD: No puedo encontrar ninguna relación entre esas dos preguntas, y mucho menos considerarlos duplicados. –

+4

@Jim: qué diplomático de usted. – JoshD

+0

Al menos acortar eso a "WTF" - ¿no haría que mucha gente se sintiera contaminada y preguntara si debía participar en esa clase de conversación? En segundo lugar, parece que ya sabes la respuesta. Si es así, responda su propia pregunta para que la gente como yo pueda recibir una educación adecuada. –

Respuesta

14

En la actualidad, la tara sintáctica de las clases de tipos de Scala es un poco mayor que para la subtipificación a través de la herencia de rasgos, como lo es la sobrecarga del tiempo de ejecución potencial. Imagine un caso en el que necesita tener cincuenta tipos diferentes de eventos conforme a una interfaz para admitir un motor de procesamiento de eventos.Mucho más fácil 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, la libertad de nombrar, y malo-assery general, pero escribiendo a cabo los cincuenta los métodos de conversión y luego hacer las importaciones apropiadas cuando se necesita la clase de tipo va a llegar a ser un dolor correcto. Si no necesita la flexibilidad, es difícil ver la recompensa. Además, está esa molesta palabra clave "nueva" en el segundo, que generará un sinfín de "es esto sobreestresar los argumentos del recolector de basura".

La situación es peor para la herencia mixin que introduce el estado mutable. Considere el rasgo siguiente, 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 
} 

uso increíblemente útil de la herencia mixin, y no es realmente factible con clases de tipo Scala, debido a la presencia del val "bloqueo". ¿A dónde debería ir? Si lo coloca en la clase adaptada, perderá 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ías bloqueando diferentes objetos de bloqueo cada vez que te adapten.

+0

Irrelevante a un lado Re: "¿esto es sobreestresar al colector de basura" argumentos: en este caso particular, uno podría usar 'perezoso val' en lugar de 'def', ¿verdad? – mokus

+0

No lo creo. Todos mis "def" tienen argumentos, lo que significa que no pueden ser vagos vals. ¿Me estoy perdiendo de algo? –

+0

oh, duh ... perdón por publicar antes del café;) – mokus

3
+1

Ya he visto ese enlace. No estoy pidiendo una comparación lado a lado. Mi pregunta básicamente es: ahora que tenemos clases de tipos, ¿hay alguna razón para seguir usando OOP? – Jim

+0

Disculpas. Tu pregunta original no estaba clara para mí; ese es mucho mejor –

+0

Creo que las clases de tipos han existido por un tiempo. Probablemente eres tú quien acaba de descubrirlos. Entonces, la respuesta a su propia pregunta depende completamente de usted: Jim, ahora que ha descubierto las clases de tipos, ¿todavía necesita ** OOP? – OscarRyz

9

Personalmente, encuentro programación orientada a objetos más fáciles de tratar dentro de las limitaciones de lo que se maneja bien. En otras palabras: en los casos en que realmente no necesita necesita clases, encuentro que los objetos son más fáciles de entender.

Sin embargo, esto podría ser solo un artefacto de la carga sintáctica que tiene la incrustación típica de objetos de clase. Si Haskell tuviese azúcar sintáctica para algunos tipos comunes de patrones de tipo de letra, esa diferencia probablemente desaparecería.

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

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


Ver Type Classes as Objects and Implicits por Bruno C.D.S. Oliveira, Adriaan Moros y Martin Odersky, así como the discussion of that paper on Lambda the Ultimate, especialmente este buen resumen de Paul Snively (énfasis añadido):

Martin Odersky y el equipo de las decisiones de diseño en torno a cómo hacer clases de tipos en un OO unificado y lenguaje de FP continuar teniendo una fruta fascinante. Los implicitos se parecen cada vez menos a las "clases de tipos de personas pobres", y cada vez más como una mejora sobre las clases de tipo, en mi opinión, una rápida lectura de este documento.

+3

Las clases de tipos no pueden hacer herencia de implementación, sin embargo. –

6

En un lenguaje que no es puramente funcional, la subtipificación le permite tener diferentes efectos secundarios con el mismo uso; esto no siempre es fácil de lograr con clases de tipos. (Puede lograrlo, por supuesto, me parece más incómodo).

Además, la subtipificación puede ser más eficiente: es una manera de almacenar en caché la información de que "X es una Y" sin requerir conversiones repetidas (o heroísmo del compilador para almacenar en caché esa información) de X a Y. Para jerarquías muy profundas, esto podría ser un problema.

3

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

2

Un motivo pragmático para continuar el soporte para OOP es la interoperabilidad. Una de las preguntas actualmente en curso en la discusión de BitC es si agregar herencia individual al lenguaje. Hay pros y contras pragmáticos, y también emite pro y contra en sus implicaciones para el sistema de tipo formal y la inferencia de tipo.

Por un tiempo, el mecanismo de resolución de instancia para las clases de tipo nos convenció de que las clases de tipo 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 tipo no escala en términos humanos: un cambio por 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 individual y alguna forma de F < + Tipo de esquema SelfType. Existen preocupaciones 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 instancia que busca resolver este problema a nuestra satisfacción. La pregunta con la que estamos luchando ahora es (a) si los programas BitC necesitan subtipado, y si es así para qué, y (b) incluso si no lo hacemos, si la interoperabilidad con programas en lenguajes OO puede requerir que nosotros apoyemos una tipo de sistema 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 preocupaciones de interoperabilidad para ser considerados.

Jonathan Shapiro