2012-03-21 23 views
6

he leído este post relevante, pero no había muchas respuestas concretas (mal diseño de un lenguaje más o menos): Why can't static methods be abstract in Javamétodos estáticos abstractas en Scala

estoy un poco de un recién llegado a la Scala, ¿Es esto posible (tal vez con rasgos o algo así)?

Intenté hacer que mi clase base extendiera un rasgo, pero luego las clases secundarias deben implementar el método estático abstracto como método miembro, cuando realmente quiero que se requiera su implementación en el objeto complementario.

+1

¿Puedes contarnos un poco más sobre tu situación específica? ¿Por qué necesita que el método esté en el objeto complementario? Puede haber una manera diferente de hacerlo en scala. –

+0

Aquí hay un ejemplo: Mi clase abstracta base tiene un método de autocorrección abstracto, esto no necesita estar vinculado a una instancia específica. Estoy considerando implementar métodos en la clase abstracta base que usaría este método de autocorrección. Si no es necesario anular la funcionalidad en las clases secundarias, mis clases secundarias deberán implementar su propio método de autocorrección, por lo tanto, métodos estáticos abstractos. –

+0

Si todo lo que hace es llamar a un método que no está vinculado a una instancia específica, coloque el método en el objeto complementario y llámelo desde su clase y todas las subclases. Esa sería la forma normal de hacerlo en Scala. –

Respuesta

4

No hay métodos estáticos en Scala [*], por lo que su pregunta es discutible.

Sin embargo, se puede obtener lo que desea mediante la extensión de un objeto con un rasgo:

scala> trait A { def foo(): Int } 
defined trait A 

scala> object C extends A { def foo(): Int = 5 } 
defined module C 

scala> C.foo 
res0: Int = 5 

que probablemente hace lo que quiere. Realmente no hay ninguna manera de forzar que algo se implemente en el objeto complementario de una clase. El objeto complementario puede no existir.

[*] Técnicamente, existen, pero esto es más un detalle de implementación que una filosofía general. Ver Method in companion object compiled into static methods in scala?

+2

En realidad, los métodos de un objeto comanion se pueden considerar como métodos estáticos de la clase. – Nicolas

+2

@Nicolas Sí, hay un reenviador estático en la clase, pero como he dicho, se trata más de un detalle de implementación para ayudar a interoperar con Java.El lenguaje Scala en sí mismo no tiene una noción de métodos estáticos. Es más de un singleton. –

+0

¿Cómo es posible que el objeto complementario no exista? ¿No debería ser esto resuelto durante el tiempo de compilación? –

0

Hay dos explicaciones posibles de por qué los métodos estáticos abstractos no son posibles en Scala, Java, C++ o C#.

Primero es técnico: los métodos abstractos/virtuales requieren una referencia a un objeto (llamado este) para elegir una anulación que se ejecutará. No proporciona tal objeto cuando llama a un método estático.

En segundo lugar es lógico: los métodos estáticos abstractos/virtuales no tienen ningún sentido. Cuando llamas a un método estático, siempre sabes el tipo que contiene ese método. Usted escribe:

MyClass.DoSomething(args) 

Si tiene MyDerivative que se extiende MiClase, sólo se puede definir otro método estático:

MyDerivative.DoSomethingDifferent(args) 

Sólo hay ningún punto en los métodos virtuales estáticas, ya que funcionará igual de ordinario métodos estáticos

+5

Por "métodos estáticos abtract", las personas a menudo se refieren a métodos que deben ser implementados estáticamente por cualquier subclase concreta. Aunque estoy de acuerdo en que no está bien formado, hay argumentos válidos en su existencia. Vea, por ejemplo, cómo las colecciones scala intentan imponer la creación de un objeto complementario con "métodos estándar". – Nicolas

0

No estoy seguro de qué le gustaría hacer con un método estático abstracto en Java, pero el único caso de uso potencial que he visto descrito en el pasado (me gustaría recordar por quién ...) está llamando un método directamente en un parámetro de tipo genérico.

es decir, si Java permitió que algo como esto ...

// this is not valid java... 
// let's pretend we can define a static method in an interface 
interface Foo { 
    static String Foo(); 
} 

// a class that implements our interface 
class FooImpl implements Foo { 
    public static String Foo() {return "foo";} 
} 

...podríamos utilizarlo en un parámetro genérico, para llamar Foo() directamente en el tipo

static <T extends Foo> String Test() { 
     return T.Foo(); // even if our hypothetical static interface 
         // was a valid thing, this would probably still fail 
         // due to type erasure  
} 

Esto haría un poco más sentido en C# porque:

  1. genéricos reificadas significan el tipo no se borran
  2. en los operadores de C# son los métodos estáticos y se puede define your own operators

Básicamente esto significa que en un "pretender C#" con interfaces estáticas, se puede usar somethi ng correspondiente al código "pretender java" anterior para escribir un método genérico que funciona en cualquier tipo que defina un operador específico (p. todo lo que tiene un operador "+").

Ahora, volviendo a scala. ¿Cómo aborda scala este escenario? En parte no es así. Scala no tiene métodos estáticos: un objeto es un singleton (es decir, una clase con solo una instancia) pero sigue siendo una clase con métodos de instancia normales, es decir, en objetos todavía llama métodos en la única instancia, no directamente en el tipo (incluso los operadores son métodos en scala).

Así que en Scala escribiríamos:

trait Foo { def Foo:String } 
object FooImpl extends Foo { def Foo = "foo" } 

def Test(f: Foo) = f.Foo 

... y llamar a nuestro método con

scala> Test(FooImpl) 
res0: String = foo 
// note that FooImpl is still an instance (the only one) of FooImpl and not 
// the type itself 

Puede hacer algunos trucos con los implícitos para evitar pasar la única instancia como un parámetro:

implicit def aFoo = FooImpl 
def Test2(implicit f: Foo) = f.Foo 

ahora esto funciona:

scala> Test2 
res1: String = foo 

Con más trucos avanzados con implicitos, scala también define Numeric, que allows you to use operators on any numeric value, aunque no implemente una interfaz común de fábrica.

Cuestiones relacionadas