Question

Je me demandais si les conversions transparentes implicites sont vraiment une si bonne idée et s'il serait peut-être préférable d'utiliser implicitement plus, euh, explicitement . Par exemple, supposons que j’ai une méthode qui accepte un Date en tant que paramètre et une conversion implicite qui transforme une String en Date :

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

private def foo(d: Date)

Alors, évidemment, je peux appeler cela avec une conversion implicite transparente:

foo("20090910")

Serait-il préférable de rendre plus explicite le fait que je convertis la chaîne en une date?

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

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

L'usage ressemble donc davantage à:

foo("20090910".toDate)

L’avantage de cela est qu’il est clair plus tard ce qui se passe - des conversions implicites transparentes dont je devrais avoir connaissance ( Option à Iterable ?) et cet usage nous permet toujours de tirer parti de la puissance de implicite s.

Était-ce utile?

La solution

Je pense que plus "explicite" La meilleure façon de réaliser des conversions implicites est bien meilleure en termes de lisibilité que la solution totalement transparente, du moins dans cet exemple.

À mon avis, l'utilisation de implicite est complètement transparente à partir du type A pour taper B , si vous pouvez toujours affiche un objet de type A comme pouvant être utilisé chaque fois qu'un objet de type B est requis. Par exemple, la conversion implicite d'une String en RandomAccessSeq [Char] a toujours un sens - une String peut toujours, conceptuellement, être vue comme une séquence de caractères (en C, une chaîne est juste une séquence de caractères, par exemple). Un appel à x.foreach (println) est logique pour tous Chaîne s.

D'autre part, les conversions plus explicites doivent être utilisées lorsqu'un objet de type Un peut parfois être utilisé comme objet de type B . Dans votre exemple, un appel à foo ("barre") n'a pas de sens et génère une erreur. Scala ne disposant pas d'exceptions vérifiées, un appel à foo (s.toDate) indique clairement qu'une exception peut être levée ( s peut ne pas être une date valide). De même, foo ("bar" .toDate) a clairement tort, alors que vous devez consulter la documentation pour savoir pourquoi foo ("bar") peut être erroné. Un exemple de cela dans la bibliothèque standard Scala est la conversion de String s en Int s, via la méthode toInt de RichString wrapper ( String peut être vu comme Int , mais pas tout le temps ).

Autres conseils

Lorsque vous effectuez une conversion implicite de X en Y (comme la conversion de String en Date ci-dessus), vous dites essentiellement que, si vous aviez eu le plein contrôle de l'écriture de X au départ, vous auriez fait implémenter X ou être une sous-classe de Y.

S'il est logique que X implémente Y, ajoutez la conversion. Si ce n'est pas le cas, alors peut-être que ce n'est pas approprié. Par exemple, il est logique que String implémente RandomAccessSeq [Char], mais peut-être que ce n’est pas logique pour String d’implémenter Date (bien que String implémentant StringDate semble correct).

(Je suis un peu en retard, et Flaviu a une excellente réponse, mais je voulais ajouter un commentaire sur ma façon de penser les implications.)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top