2009-08-13 20 views
11

Después de haber escrito algunas herramientas de scala, estoy tratando de comprender la mejor forma de organizar mi código, particularmente las implicaciones. Tengo 2 objetivos:¿Cómo debo organizar implicits en mi aplicación Scala?

  • A veces, quiero ser capaz de importar solo las implicidades que pido.
  • Othertimes, quiero importar todo.

Para evitar la duplicación de los implícitos, se me ha ocurrido con esta estructura (similar a la forma en que está dispuesto scalaz):

case class StringW(s : String) { 
    def contrived = s + "?" 
} 

trait StringWImplicits { 
    implicit def To(s : String) = StringW(s) 
    implicit def From(sw : StringW) = sw.s 
} 

object StringW extends StringWImplicits 

// Elsewhere on Monkey Island 

object World extends StringWImplicits with ListWImplicits with MoreImplicits 

Esto me permite simplemente

import StringW._ // Selective import 

o (en la mayoría de los casos)

import World._. // Import everything 

¿Cómo funciona? todos los demás lo hacen?

+0

¿Qué es 'implicit' sobre algo de esto? –

+0

Supongo que se suponía que todas las definiciones 'def' estaban implícitas. –

+0

Solucionado ahora, gracias! –

Respuesta

4

Creo que implicit conversiones son peligrosas si no sabes de dónde vienen. En mi caso, puse mis implicit s en una clase Conversions y import que lo más cerca posible el uso posible

def someMethod(d: Date) ; Unit { 
    import mydate.Conversions._ 
    val tz = TimeZone.getDefault 
    val timeOfDay = d.getTimeOfDay(tz) //implicit used here 
    ... 
} 

No estoy seguro de que me gusta "heredar" implícitos de varios trait s para el mismo razón por la cual se consideró mala práctica de Java para implementar un interface por lo que podría usar sus constantes directamente (en su lugar se prefieren las importaciones estáticas).

+1

No es que esté necesariamente en desacuerdo con este consejo, pero podría señalarse que las implicaciones son útiles porque son, bueno, implícitas. Si agrega una declaración de importación justo antes de usarla cada vez, quizás exista un argumento de que también podría haber aplicado explícitamente la conversión implícita. –

+0

Meditaba sobre este punto exacto cuando caminaba a casa ayer (¡y no siempre lo sigo yo mismo!). Sin embargo, prefiero las importaciones sobre la herencia. –

1

Normalmente tenía implicit conversiones en un objeto que indica claramente que lo que se importa es una conversión de implicit.

Por ejemplo, si tengo una clase com.foo.bar.FilthyRichString, las conversiones implícitas entrarían en com.foo.bar.implicit.FilthyRichStringImplicit. Sé que los nombres son un poco largos, pero es por eso que tenemos IDEs (y el soporte IDE de Scala está mejorando). La forma en que hago esto es que creo que es importante que todas las conversiones implícitas se puedan ver claramente en un 10 second code review. Podía mirar el código siguiente:


// other imports 
import com.foo.bar.FilthyRichString 

import com.foo.bar.util.Logger 
import com.foo.bar.util.FileIO 

import com.foo.bar.implicits.FilthyRichStringImplicit._ 
import com.foo.bar.implicits.MyListImplicit._ 
// other implicits 

y de un vistazo ver todas las conversiones implícitas que están activos en este archivo de origen. También estarían todos reunidos si usa la convención de que las importaciones están agrupadas por paquetes, con una nueva línea entre diferentes paquetes.

En la misma línea del mismo argumento, no me gustaría un objeto catch-all que contenga todas las conversiones implícitas. En un proyecto grande, ¿realmente usaría todas las de las conversiones implícitas en todos sus archivos fuente? Creo que hacerlo significa un acoplamiento muy ajustado entre las diferentes partes de tu código.

Además, un objeto general no es muy bueno para la documentación. En el caso de escribir explícitamente todas las conversiones implícitas usadas en un archivo, uno puede simplemente mirar sus declaraciones de importación y saltar directamente a la documentación de la clase implícita. En el caso de un objeto catch-all, uno tendría que mirar ese objeto (que en un gran proyecto podría ser enorme) y luego buscar la conversión implícita que están buscando.

Estoy de acuerdo con oxbow_lakes que tener una conversión implícita en trait s es malo debido a la tentación de heredar de él, que es, como dijo, una mala práctica. En esa línea, haría que los objetos contengan las conversiones implícitas final solo para evitar la tentación por completo. Su idea de importarlos lo más cerca posible del uso es muy bueno también, si las conversiones implícitas se usan con moderación en el código.

-- Flaviu Cipcigan

Cuestiones relacionadas