Scala неявный выбор использования - PullRequest
23 голосов
/ 10 сентября 2009

Мне было интересно, действительно ли прозрачные implicit преобразования являются такой хорошей идеей, и может ли лучше использовать имплицит больше, например, явно . Например, предположим, у меня есть метод, который принимает Date в качестве параметра, и у меня есть неявное преобразование, которое превращает String в Date:

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

private def foo(d: Date)

Тогда, очевидно, я могу назвать это прозрачным implicit преобразованием:

foo("20090910")

Было бы лучше сделать факт, что я преобразовываю строку в дату, более явным?

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

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

Итак, использование выглядит больше как:

foo("20090910".toDate)

Преимущество этого состоит в том, что позже становится яснее, что происходит - меня несколько раз ловили прозрачные implicit преобразования, о которых я должен знать (от Option до Iterable кого-нибудь?) это использование все еще позволяет нам воспользоваться преимуществом implicit с.

Ответы [ 2 ]

43 голосов
/ 10 сентября 2009

Я считаю, что более «явный» способ выполнения неявных преобразований намного лучше с точки зрения читабельности, чем полностью прозрачный, по крайней мере, в этом примере.

По моему мнению, использование implicit s полностью прозрачно от типа A до типа B нормально, когда вы можете всегда просматривать объект типа A как пригодный для использования. всякий раз, когда требуется объект типа B. Например, неявное преобразование String в RandomAccessSeq[Char] всегда имеет смысл - String всегда может концептуально рассматриваться как последовательность символов (в C строка просто последовательность символов, например). Вызов x.foreach(println) имеет смысл для всех String с.

С другой стороны, более явные преобразования должны использоваться, когда объект типа A может иногда использоваться в качестве объекта типа B. В вашем примере вызов foo("bar") не имеет смысла и выдает ошибку. Поскольку в Scala нет проверенных исключений, вызов foo(s.toDate) четко сигнализирует о том, что может быть выдано исключение (s может быть недопустимой датой). Кроме того, foo("bar".toDate) явно выглядит неправильно, в то время как вам нужно ознакомиться с документацией, чтобы понять, почему foo("bar") может быть неправильным. Примером этого в стандартной библиотеке Scala являются преобразования из String с в Int с с помощью метода toInt из оболочки RichString (String с можно рассматривать как Int с, но не все время ).

13 голосов
/ 13 сентября 2009

Когда вы делаете неявное преобразование из X в Y (как преобразование из String в Date выше), вы, по сути, говорите, что, если бы у вас был полный контроль над написанием X, вы бы заставили X реализовать или быть подклассом Y.

Если для X имеет смысл реализовать Y, добавьте преобразование. Если это не так, то, возможно, это не подходит. Например, для String имеет смысл реализовывать RandomAccessSeq [Char], но, возможно, для String не имеет смысла реализовывать Date (хотя String, реализующий StringDate, выглядит неплохо).

(Я немного опоздал, и у Флавиу отличный ответ, но я хотел добавить комментарий о том, как я думаю о последствиях.)

...