Подтвердить что ты не робот

Scala toString: в скобках или нет?

Мне хотелось бы, чтобы этот поток был своего рода резюме плюсов/минусов для переопределения и вызова toString с пустыми скобками или без них, потому что эта вещь иногда меня смущает, хотя я был в Scala довольно долгое время.

Итак, какой из них предпочтительнее другого? Комментарии от Scala выродков, чиновников и параноиков OCD высоко ценятся.

Плюсы до toString:

  • кажется очевидным и естественным выбором на первый взгляд;
  • большинство случаев тривиальны и просто строят строки "на лету" без изменения внутреннего состояния;
  • другим распространенным случаем является делегирование вызова метода завернутой абстракции:

    override def toString = underlying.toString
    

Плюсы до toString():

  • определенно не "accessor-like" name (то, как инспектор IntelliJ IDEA каждый раз жалуется);
  • может означать работу процессора или ввода-вывода (в тех случаях, когда подсчет каждого вызова System.arrayCopy имеет решающее значение для производительности);
  • даже может означать изменение какого-либо изменяемого состояния (рассмотрим пример, когда первый вызов toString стоит дорого, поэтому он кэшируется изнутри для более быстрого вызова в будущем).

Так какая лучшая практика? Я все еще что-то пропустил?

Обновление: этот вопрос связан конкретно с toString, который определен на каждом объекте JVM, поэтому я надеялся найти наилучшую практику, если она когда-либо существует.

4b9b3361

Ответ 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