Opciones de uso implícito de Scala


Me he estado preguntando si transparente implicit las conversiones son realmente una buena idea y si en realidad podría ser mejor usar implicits más, um, explícitamente. Por ejemplo, supongamos que tengo un método que acepta a Date como parámetro y tengo una conversión implícita que convierte a String en a Date:

implicit def str2date(s: String) : Date = new SimpleDateFormat("yyyyMMdd").parse(s)

private def foo(d: Date)

Entonces obviamente puedo llamar a esto con una conversión transparente implicit:

foo("20090910")

Sería mejor hacer el hecho de que estoy convertir la cadena en una fecha más explícito?

class DateString(val s: String) { 
  def toDate : Date = new SimpleDateFormat("yyyyMMdd").parse(s) 
}

implicit def str2datestr(s: String) : DateString = new DateString(s)

Entonces el uso se parece más a: {[18]]}

foo("20090910".toDate)

La ventaja de esto es que es más claro más adelante lo que está sucediendo - He sido sorprendido un par de veces ahora por las conversiones transparentes implicit que debería saber (Option a Iterable alguien?) y este uso nos permite aprovechar el poder de implicits.

Author: oxbow_lakes, 2009-09-10

2 answers

Creo que la forma más "explícita" de hacer conversiones implícitas es mucho mejor en términos de legibilidad que la totalmente transparente, al menos en este ejemplo.

En mi opinión, usar implicitde forma totalmente transparente de type A a type B está bien cuando se puede siempre ver un objeto de type A como si se pudiera usar siempre que se necesite un objeto de type B. Por ejemplo, la conversión implícita de un String a un RandomAccessSeq[Char] siempre tiene sentido - un String puede siempre, conceptualmente, ser visto como una secuencia de caracteres (en C, una cadena es solo una secuencia de caracteres, por ejemplo). Una llamada a x.foreach(println) tiene sentido para todos Strings.

Por otro lado, las conversiones más explícitas deben usarse cuando un objeto de tipo A puede a veces usarse como un objeto de tipo B. En su ejemplo, una llamada a foo("bar") no tiene sentido y lanza un error. Como Scala no ha comprobado excepciones, una llamada a foo(s.toDate) claramente indica que podría haber una excepción lanzada (s podría no ser una fecha válida). Además, foo("bar".toDate) claramente se ve mal, mientras que necesita consultar la documentación para ver por qué foo("bar") podría estar mal. Un ejemplo de esto en la biblioteca estándar de Scala son las conversiones de String s a Int s, a través del método toInt del wrapper RichString (String s se puede ver como Int s, pero no todo el tiempo).

 43
Author: Flaviu Cipcigan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-11 15:49:47

Cuando haces una conversión implícita de X a Y (como la conversión de String a la Fecha anterior), esencialmente estás diciendo que, si hubieras tenido control total sobre escribir X en primer lugar, habrías hecho que X implementara o fuera una subclase de Y.

Si tiene sentido que X implemente Y, entonces agregue la conversión. Si no lo hace, entonces tal vez no es apropiado. Por ejemplo, tiene sentido que String implemente RandomAccessSeq[Char] , pero tal vez no tenga sentido que String fecha de implementación(aunque String implementar StringDate parece estar bien).

(Llego un poco tarde, y Flaviu tiene una excelente respuesta, pero quería agregar un comentario sobre cómo pienso sobre implicits.)

 13
Author: Jorge Ortiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-10 19:43:38