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

Почему символы не заморожены?

Я понимаю теоретическое различие между строками и символами. Я понимаю, что Символы предназначены для представления концепции или имени или идентификатора или метки или ключа, а строки - это мешок символов. Я понимаю, что Струны являются изменяемыми и преходящими, где Символы неизменны и постоянны. Мне даже нравится, как символы отличаются от строк в текстовом редакторе.

Меня беспокоит то, что на самом деле Символы настолько похожи на строки, что тот факт, что они не реализованы как строки, вызывает много головных болей. Они даже не поддерживают утиную печать или неявное принуждение, в отличие от другой известной "той же, но другой" пары Float и Fixnum.

Самая большая проблема, конечно, в том, что хеши, входящие в Ruby из других мест, такие как JSON и HTTP CGI, используют строковые ключи, а не символьные ключи, поэтому программы Ruby должны наклоняться назад, чтобы либо преобразовать их спереди, либо в время поиска. Простое существование HashWithIndifferentAccess и его необузданное использование в Rails и других средах демонстрируют, что здесь проблема, зуд, который нужно поцарапать.

Может ли кто-нибудь сказать мне практическую причину, почему символы не должны быть заморожены? Кроме "потому что это всегда было сделано" (историческое) или "потому что символы не являются строками" (попрошайничество).

Рассмотрим следующее удивительное поведение:

:apple == "apple"  #=> false, should be true

:apple.hash == "apple".hash #=> false, should be true

{apples: 10}["apples"]  #=> nil, should be 10

{"apples" => 10}[:apples]  #=> nil, should be 10

:apple.object_id == "apple".object_id #=> false, but that actually fine

Все, что потребуется, чтобы сделать следующее поколение рубистов менее запутанным:

class Symbol < String
  def initialize *args
    super
    self.freeze
  end

(и много другого взлома на уровне библиотеки, но все же, не слишком сложно)

См. также:

Обновление: я думаю, что Matz очень хорошо описывает случай class Symbol < String: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9192 (спасибо Azolo за то, что он выкопал это, а также возможную ретракцию Маца.

4b9b3361

Ответ 1

Этот ответ резко отличается от моего исходного ответа, но я столкнулся с парой интересный threads в списке рассылки Ruby. (Оба хороших чтения)

Итак, в какой-то момент 2006 года matz реализовал класс Symbol как Symbol < String. Затем класс Symbol был удален, чтобы удалить любую изменчивость. Таким образом, Symbol фактически был неизменным String.

Однако он был отменен. Дана

Несмотря на то, что это сильно против DuckTyping, люди склонны использовать случай по классам и символу < Строка часто вызывает серьезные проблемы.

Итак, ответ на ваш вопрос по-прежнему: a Symbol похож на String, но это не так. Проблема не в том, что Symbol не должен быть String, а вместо этого он исторически не был.

Ответ 2

Я не знаю о полном ответе, но здесь большая его часть:

Одна из причин, по которой символы используются для хэш-ключей, состоит в том, что каждый экземпляр данного символа является точным одним и тем же объектом. Это означает, что :apple.id всегда будет возвращать одно и то же значение, даже если вы его не проходите. С другой стороны, "apple".id будет возвращать разные id каждый раз, так как создается новый строковый объект.

Это отличие в том, почему символы рекомендуются для хеш-ключей. При использовании символов не требуется проверка эквивалентности объектов. Он может быть закорочен непосредственно к идентичности объекта.

Ответ 3

Другое соображение состоит в том, что "apple".each_char имеет смысл, но :apple.each_char нет. Строка представляет собой "упорядоченный список символов", но символ представляет собой атомный набор данных без явного значения.

Я бы сказал, что HashWithIndifferentAccess на самом деле демонстрирует, что символы Ruby выполняют две разные роли; символы (которые по существу похожи на перечисления на других языках) и интернированные строки (которые по существу являются превентивной оптимизацией, компенсируя тот факт, что рубин интерпретируется, поэтому не имеют преимуществ интеллектуального оптимизирующего компилятора.)

Ответ 4

Смотрите этот ответ: fooobar.com/questions/259525/...

Основные причины: производительность (символы хранятся в виде целых чисел и никогда не собираются мусором) и согласованность (:admin и :admin всегда указывают на тот же объект, где "admin" и "admin" не имеют это гарантия) и т.д.

Ответ 5

Основы этого, это не должно быть правдой:

:apple == "apple"  #=> false, should be true

:apple.hash == "apple".hash #=> false, should be true

Символы всегда одни и те же объекты, а текст - нет.

Ответ 6

Если вообще String может наследовать Symbol, потому что он добавляет много функциональности (мутирует). Но Символ никогда не может использоваться как "Строка", потому что при любых обстоятельствах, когда потребуется мутация, это не сработает.

В любом случае, как я сказал выше, символ string == никогда не должен возвращать true, как было предложено выше. Если вы немного об этом подумаете, вы заметите, что разумной реализации == в классе, который также рассматривает экземпляры sub-класса, не может быть.