Scala toString: в скобках или нет?
Мне хотелось бы, чтобы этот поток был своего рода резюме плюсов/минусов для переопределения и вызова toString
с пустыми скобками или без них, потому что эта вещь иногда меня смущает, хотя я был в Scala довольно долгое время.
Итак, какой из них предпочтительнее другого? Комментарии от Scala выродков, чиновников и параноиков OCD высоко ценятся.
Плюсы до toString
:
Плюсы до toString()
:
- определенно не "accessor-like" name (то, как инспектор IntelliJ IDEA каждый раз жалуется);
- может означать работу процессора или ввода-вывода (в тех случаях, когда подсчет каждого вызова
System.arrayCopy
имеет решающее значение для производительности);
- даже может означать изменение какого-либо изменяемого состояния (рассмотрим пример, когда первый вызов
toString
стоит дорого, поэтому он кэшируется изнутри для более быстрого вызова в будущем).
Так какая лучшая практика? Я все еще что-то пропустил?
Обновление: этот вопрос связан конкретно с toString
, который определен на каждом объекте JVM, поэтому я надеялся найти наилучшую практику, если она когда-либо существует.
Ответы
Ответ 1
Здесь какое программирование в Scala (раздел 10.3) должно сказать:
Рекомендуемое соглашение - использовать безпараметрический метод, когда нет параметров, и метод получает доступ к изменяемому состоянию только посредством чтение полей содержащего объекта (в частности, это не изменить изменяемое состояние). Это соглашение поддерживает единообразный доступ принцип 1, в котором говорится, что клиентский код не должен решение реализовать атрибут как поле или метод.
Вот что должно сказать (неофициальный) Scala Style Guide (стр. 18):
Scala позволяет пропускать круглые скобки по методам arity-0 (нет аргументы):
reply()
// is the same as
reply
Однако этот синтаксис следует использовать только тогда, когда рассматриваемый метод не имеет побочных эффектов (Чисто-функциональный). Другими словами, было бы приемлемым опустить круглые скобки при вызове queue.size, но не при вызове println(). Это соглашение отражает соглашение об объявлении метода, приведенное выше.
В последнем не упоминается принцип единообразного доступа.
Если ваш метод toString
может быть реализован как val
, это означает, что поле является неизменным. Если, однако, ваш класс изменен, toString
может не всегда давать тот же результат (например, для StringBuffer
). Поэтому программирование в Scala означает, что мы должны использовать toString()
в двух разных ситуациях:
1) Когда его значение изменено
2) При наличии побочных эффектов
Лично я считаю это более распространенным и более последовательным, чтобы игнорировать первый из них. На практике toString
почти не будет иметь побочных эффектов. Поэтому (если это не так), всегда используйте toString
и игнорируйте принцип унифицированного доступа (следуя Руководству по стилю): держите круглые скобки для обозначения побочных эффектов, а не изменчивости.
Ответ 2
Да, вам что-то не хватает: семантика.
Если у вас есть метод, который просто возвращает значение, вы не должны использовать parens. Причина в том, что это размывает линию между val
и def
s, удовлетворяя принципу равномерного доступа . Например. рассмотрим метод size
для коллекций. Для векторов или массивов фиксированного размера это может быть всего лишь val
, другие коллекции могут потребоваться для его расчета.
Использование пустых паренов должно быть ограничено методами, которые выполняют какой-то побочный эффект, например. println()
или метод, который увеличивает внутренний счетчик, или метод, который сбрасывает соединение и т.д.
Ответ 3
Я бы рекомендовал всегда использовать toString
. Что касается вашего третьего "про" до toString()
:
Возможно, изменится какое-то изменяемое состояние (рассмотрим пример, когда первый вызов toString стоит дорого, поэтому он кэшируется внутри, чтобы в будущем получать более быстрые вызовы).
Прежде всего, toString
обычно не должно быть дорогостоящей операцией. Но предположим, что это дорого, и предположим, что вы решили кэшировать результат внутри. Даже в этом случае я бы сказал, используйте toString
, если результат toString
всегда одинаковый для заданного состояния объекта (без учета состояния кеша toString
).
Единственная причина, по которой я бы не рекомендовал использовать toString
без parens, - это если у вас есть профилировщик/анализатор кода, который делает предположения на основе наличия или отсутствия паренс. В этом случае следуйте соглашениям, указанным указанным профилировщиком. Кроме того, если ваш toString
настолько сложный, подумайте о переименовании его в нечто другое, например expensiveToString
. Неофициально ожидается, что toString
будет простой, простой функцией в большинстве случаев.
Ответ 4
Не много аргументов в этом ответе, но только GenTraversableOnce
объявляет следующие defs без круглых скобок:
toArray
toBuffer
toIndexedSeq
toIterable
toIterator
toList
toMap
toSeq
toSet
toStream
toTraversable