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

Почему Matz решил сделать Strings mutable по умолчанию в Ruby?

Реверс этого вопроса: Почему строки нельзя изменять в Java и .NET?

Был ли этот выбор сделан в Ruby только потому, что операции (добавление и т.д.) эффективны в изменяемых строках, или была ли какая-то другая причина?

(Если бы это была только эффективность, что казалось бы странным, поскольку дизайн Ruby, по-видимому, не придавал высокой премии за эффективную реализацию.)

4b9b3361

Ответ 1

Это соответствует дизайну Ruby, как вы заметили. Неизменяемые строки более эффективны, чем изменяемые строки - меньшее копирование, поскольку строки повторно используются, - но сделать работу сложнее для программиста. Интуитивно видеть строки как изменчивые - вы можете объединить их вместе. Чтобы справиться с этим, Java молча переводит конкатенацию (через +) двух строк в использование объекта StringBuffer, и я уверен, что есть и другие подобные хаки. Вместо этого Ruby выбирает, чтобы строки изменялись по умолчанию за счет производительности.

Ruby также имеет ряд деструктивных методов, таких как String#upcase!, которые полагаются на изменяемые строки.

Другая возможная причина заключается в том, что Ruby вдохновлен Perl, а Perl использует изменчивые строки.

У Ruby есть символы и замороженные строки, оба они неизменяемы. В качестве дополнительного бонуса символы гарантированно уникальны для каждого возможного значения строки.

Ответ 2

Это мои мнения, а не Мац. Для целей этого ответа, когда я говорю, что язык имеет "неизменяемые строки", это означает, что все его строки неизменяемы, т.е. Нет возможности создать строку, которая изменена.

  • Конструкция "неизменной строки" рассматривает строки как оба идентификатора (например, как хеш-ключи и другие внутренние вложения VM), так и структуры хранения данных. Идея состоит в том, что это опасно для изменяемых идентификаторов. Для меня это звучит как нарушение единой ответственности. В Ruby у нас есть символ для идентификаторов, поэтому строки могут действовать как хранилища данных. Это правда, что Ruby позволяет использовать строки как хеш-ключи, но я считаю, что программисту некорректно хранить строку в переменной, использовать ее как хэш-ключ, а затем изменять строку. В разуме программиста существует (или должно быть) разделение двух применений строк. Часто строка, используемая в качестве хэш-ключа, является литеральной строкой, поэтому вероятность ее мутирования мало. Использование строки в качестве хэш-ключа мало чем отличается от использования массива из двух строк в качестве хэш-ключа. Пока ваш ум хорошо разбирается в том, что вы используете в качестве ключа, тогда нет проблем.

  • Наличие строки в качестве хранилища данных полезно с точки зрения когнитивной простоты. Просто рассмотрите Java и его StringBuffer. Это дополнительная структура данных (в уже большой и часто неинтуитивной стандартной библиотеке), которую вам нужно управлять, если вы пытаетесь выполнить строковые операции, такие как вставка одной строки в определенный индекс другой строки. Поэтому, с одной стороны, Java признает необходимость выполнять такие операции, но поскольку неизменяемые строки подвергаются программисту, им пришлось ввести еще одну структуру, чтобы операции все еще были возможны, не заставляя нас изобретать колесо. Это накладывает дополнительную когнитивную нагрузку на программиста.

  • В Python кажется, что самый простой способ вставить - захватить подстроки до и после точки вставки, а затем объединить их вокруг вставленной строки. Я полагаю, они могли бы легко добавить метод к стандартной библиотеке, которая вставляет и возвращает новую строку. Однако, если метод называется insert, новички могут думать, что он мутирует строку; чтобы быть описательным, его нужно было бы называть new_with_inserted или что-то странное. В повседневном использовании "вставка" означает, что вы меняете содержимое вещей, вставленных в (например, вставка конверта в почтовый ящик меняет содержимое почтового ящика). Опять же, возникает вопрос: "Почему я не могу изменить хранилище данных?"

  • Ruby обеспечивает замораживание объектов, поэтому их можно безопасно обойти без ввода тонких ошибок. Приятно, что Ruby обрабатывает строки так же, как и любую другую структуру данных (массивы, хэши, экземпляры классов); все они могут быть заморожены. Согласованность является программируемым. Неизменяемые строки заставляют строки выделяться как "специальные" структуры данных, если это не так, если вы используете их как хранилище данных.