2009-09-10 13 views
23

Zastanawiałem się czy przezroczysteimplicit konwersje są naprawdę taki dobry pomysł i czy może to być rzeczywiście lepiej użyć implicits bardziej, hm, wyraźnie. Na przykład, przypuśćmy, że ma sposobu, który akceptuje Date jako parametr i mają niejawny konwersji, który zamienia String do Date:Scala wybory niejawne użytkowania

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

private def foo(d: Date) 

to oczywiście można nazwać przezroczystą implicit wzorem:

foo("20090910") 

Czy byłoby lepiej, aby przekonwertować ciąg na bardziej konkretną datę?

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

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

Tak więc użycie wygląda bardziej jak:

foo("20090910".toDate) 

Zaletą tego rozwiązania jest to, że jaśniejsze później, co się dzieje - Zostałem złapany się kilka razy przez przezroczysty implicit Konwersje, o których powinienem wiedzieć (Option do Iterable ktoś?), a to wykorzystanie pozwala nam nadal korzystać z mocy implicit s.

Odpowiedz

43

Uważam, że bardziej "wyraźny" sposób dokonywania niejawnych konwersji jest znacznie lepszy pod względem czytelności niż w pełni przejrzysty, przynajmniej w tym przykładzie.

Moim zdaniem, używając implicit s pełni przejrzysty od rodzaju A wpisać B jest OK, kiedy można zawsze zobaczyć obiekt typu A jako że mogą być stosowane w każdym miejscu io obiekt typu B jest potrzebne. Na przykład domyślna konwersja String nazawsze ma sens - zawsze można, zgodnie z koncepcją, traktować sekwencję znaków (w języku C ciąg znaków to na przykład sekwencja znaków). Połączenie z numerem x.foreach(println) ma sens w przypadku allString s.

Z drugiej strony, bardziej wyraźne konwersji należy stosować, gdy obiekt typu A może czasami być używany jako obiekt typu B. W twoim przykładzie połączenie z foo("bar") nie ma sensu i powoduje błąd. Ponieważ Scala nie ma sprawdzonych wyjątków, wywołanie foo(s.toDate) wyraźnie sygnalizuje, że może wystąpić wyjątek (s może być nieprawidłową datą). Również, foo("bar".toDate) wyraźnie wygląda źle, podczas gdy musisz zapoznać się z dokumentacją, aby zobaczyć, dlaczego foo("bar") może być nie tak. Przykładem tego w standardzie biblioteki Scala konwersje z String s do Int s, metodą z RichString opakowaniu toInt (String S może być postrzegane jako Int S, lecz nie cały czas).

13

Kiedy dokonujesz niejawnej konwersji z X na Y (np. Konwersja z ciągu do daty powyżej), zasadniczo mówisz, że gdybyś miał pełną kontrolę nad pisaniem Xa na pierwszym miejscu, zrobiłbyś X zaimplementować lub być podklasą Y.

Jeśli ma sens, aby X wprowadził Y, dodaj konwersję. Jeśli nie, to może nie jest właściwe. Na przykład sensowne jest, aby String implementował RandomAccessSeq [Char], ale może nie ma sensu, aby String implementował Date (chociaż String implementujący StringDate wydaje się być w porządku).

(Jestem trochę spóźniony, a Flaviu ma doskonałą odpowiedź, ale chciałem dodać komentarz o tym, jak myślę o implikatach.)