Me gustaría definir un rasgo con algunas propiedades que tienen una relación bien definida, por ejemplo, digamos que a * b = c
. La idea es que las implementaciones de este rasgo pueden proporcionar dos de estos y tener un descriptor para la tercera propiedad derivada automáticamente.Inferir implementaciones de métodos predeterminados mutuamente dependientes en Scala
( Esta es la misma característica que las clases de tipos de Haskell, si no recuerdo aquellos correctamente, en donde si ha definido (no recuerdo las clases de tipos de Haskell correctamente)<
de Ord
, >=
se ejecutaría de la ! . <
- aunque se puede definir cualquier subconjunto de funciones, siempre que el resto . podría inferirse)
El enfoque ingenuo realmente funciona bastante bien:.
trait Foo {
// a * b = c
def a: Double = c/b
def b: Double = c/a
def c: Double = a * b
}
class FooOne(override val a: Double, override val b: Double) extends Foo
class FooTwo(override val a: Double, override val c: Double) extends Foo
Aquí, las implementaciones FooOne
y FooTwo
son implementaciones completas de Foo
, y se comportan como se esperaba. Hasta aquí todo bien; este enfoque permite a las clases definir dos de las propiedades y obtener la tercera "gratis".
Sin embargo, las cosas empiezan a parecer menos optimista si se define una tercera clase:
class FooFail(override val a: Double) extends Foo
Esto compila bien - sin embargo, se provocará un desbordamiento de pila si alguna vez se evalúan sus b
c
o métodos.
Así que el enfoque ingenuo da la inferencia aspecto del enfoque de clase de tipos de Haskell, pero no tenemos la seguridad de tiempo de compilación. Lo que me gustaría es que el compilador se queje si se implementan menos de dos de los métodos implementando clases. Claramente, la sintaxis actual no es suficiente aquí; necesitamos que los métodos se consideren abstractos, aunque con una implementación predeterminada que se puede usar si y solo si los métodos dependientes no son abstractos.
¿Scala expone la semántica adecuada para definir esto? (No tengo ningún problema si hay una forma indirecta de definirlo, similar a union types, ya que no tengo conocimiento de ningún soporte de primera clase para esto en el lenguaje).
Si no, me las arreglaré con el enfoque ingenuo y simplemente definiré y probaré mis clases con cuidado. Pero realmente creo que esto es algo que el sistema de tipos debería poder atrapar (después de todo, no es Ruby. :)).
A menos que olvide mal por completo, Haskell utiliza precisamente el mismo enfoque ingenuo con el mismo problema. –
@Alexey - comentario interesante. Ha pasado un tiempo, pero me parece recordar que si no definía los métodos suficientes, obtendría un error de compilador/intérprete según el cual no era posible derivar todos los métodos para la clase de texto. Tal vez intente reproducir esto y leer sobre cómo lo hace Haskell, en busca de inspiración. –
OK, después de haber probado esto en Haskell, de hecho sufre el mismo problema (es equivalente a la situación de Scala ya que solo advierte sobre métodos totalmente abstractos). Dicho eso, la pregunta sigue en pie, aunque sin el precedente en otro idioma. –