Методы экземпляра F #… должны ли они возвращать новый экземпляр вместо изменения текущего объекта?

#f# #immutability

#f# #неизменяемость

Вопрос:

Проблема в том, должен ли метод экземпляра в любом случае изменять объект, содержащий метод, или он должен возвращать новый экземпляр? Я новичок в F # и концепции полной изменяемости, которая предлагается для F #.

Пока просто использую псевдокод, если мне не нужно быть более конкретным.

Первая мысль — просто добавить сообщение в список сообщений на объекте:

 class Something
  ctr(messages)
     _messages.Add(messages)

  AddMessage(message)
   _messages.Add(message)
  

Второе — создать новый список, который объединяет старый список и новое сообщение. Затем я бы создал новый экземпляр и отправил обратно.

 class Something
  ctr(messages)
     _messages.Add(messages)

  AddMessage(message)
    newMessageList = _messages.Join(message)
      return new Something(newMessageList)
  

Я слишком много думаю о неизменности?

Ответ №1:

На мой взгляд, ответ зависит от ваших требований. Неизменяемый стиль, вероятно, более идиоматичен и был бы разумным значением по умолчанию. Однако одна приятная особенность F # заключается в том, что вы можете выбирать, что делать, исходя из ваших потребностей; в коде, использующем мутацию, нет ничего изначально неправильного. Вот некоторые вещи, которые следует учитывать:

  • Иногда изменяемый подход приводит к повышению производительности, особенно при использовании в однопоточном контексте (но обязательно измеряйте реалистичные сценарии, чтобы быть уверенным!)
  • Иногда неизменяемый подход лучше использовать в многопоточных сценариях
  • Иногда требуется взаимодействовать с библиотеками, которые проще использовать с императивным кодом (например, API, использующий a System.Action<_> ).
  • Вы работаете в команде? Если да, то являются ли они опытными разработчиками C #? Опытные разработчики F #? Какой код им будет легче всего читать (возможно, изменяемый стиль)? Какой код вам будет проще всего поддерживать (возможно, неизменяемый стиль)?
  • Вы просто делаете это как упражнение? Тогда может быть полезно практиковать неизменяемый стиль.

Отступая еще дальше, есть несколько других моментов, которые следует учитывать:

  • Вам действительно нужен метод экземпляра? Часто использование функции с привязкой к разрешению в модуле более идиоматично.
  • Вам действительно нужен новый номинальный тип для того, что вы делаете? Если это просто тонкая оболочка вокруг списка, вы можете рассмотреть возможность использования list s напрямую.

Ответ №2:

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

Если вы действительно хотите перейти к неизменности, я бы посоветовал вам использовать больше концепций FP, таких как модули, функции (а не методы, которые у вас есть в программировании на основе классов), рекурсивные типы данных и т.д.

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