tl; dr: Будет ли определение символов, не зависящее от языка, и причина их использования на других языках?
Итак, почему создатель Ruby использовал концепцию symbols
в языке?
Я спрашиваю об этом с точки зрения неруби программиста. Я выучил много других языков и ни на одном из них не нашел необходимости указывать, имел ли я дело с тем, что называет Руби symbols
.
Главный вопрос заключается в том, существует ли symbols
в Ruby концепция производительности или что-то, что нужно из-за того, как написан язык?
Будет ли программа на Ruby легче и / или быстрее, чем ее, скажем, аналог Python или Javascript? Если так, будет ли это из-за symbols
?
Поскольку одним из намерений Ruby является простота чтения и записи для людей, разве его создатели не могли облегчить процесс кодирования, внедрив эти улучшения в самом интерпретаторе (как это может быть в других языках)?
Похоже, что все хотят знать только то, что symbols
есть и как их использовать, а не почему они там вообще.
источник
Ответы:
Создатель Ruby, Юкихиро "Matz" Мацумото, опубликовал объяснение того, как на Ruby повлияли Lisp, Smalltalk, Perl (а в Википедии также говорится об Ada и Eiffel):
В любом компиляторе вы будете управлять идентификаторами для функций, переменных, именованных блоков, типов и так далее. Обычно вы храните их в компиляторе и забываете о них в производимом исполняемом файле, за исключением случаев, когда вы добавляете отладочную информацию.
В Лиспе такие символы являются первоклассными ресурсами, размещенными в разных пакетах, что означает, что вы можете добавлять свежие символы во время выполнения, связывать их с различными типами объектов. Это полезно при метапрограммировании, потому что вы можете быть уверены, что у вас не будет конфликтов имен с другими частями кода.
Кроме того, символы интернируются во время чтения и могут сравниваться по тождеству, что является эффективным способом получения значений нового типа (например, чисел, но абстрактных). Это поможет в написании кода, в котором вы напрямую используете символические значения, вместо определения ваших собственных типов перечислений, подкрепленных целыми числами. Также каждый символ может содержать дополнительные данные. Вот как, например, Emacs / Slime может прикреплять метаданные из Emacs прямо в список свойств символа.
Понятие символа является центральным в Лиспе. Посмотрите, например, PAIP («Парадигмы программирования искусственного интеллекта: тематические исследования в Common Lisp, Norvig») для подробных примеров.
источник
Ну, они строго не «должны», они решили. Также обратите внимание, что, строго говоря,
Symbol
s не являются частью языка, они являются частью базовой библиотеки. Они действительно имеют буквальный синтаксис языка на уровне, но они будут работать так же хорошо , если вы должны были построить их по телефонуSymbol::new
.Вы не сказали, что это за «множество других языков», но вот лишь небольшая выдержка из языков с
Symbol
типом данных, подобным Ruby:Есть и другие языки, которые предоставляют функции
Symbol
s в другой форме. Например, в Java функции RubyString
делятся на два (фактически три) типа:String
иStringBuilder
/StringBuffer
. С другой стороны, функции типа RubySymbol
объединены вString
тип Java : JavaString
могут быть интернированы , литеральные строки иString
s, которые являются результатом вычисляемых во время компиляции константных выражений, автоматически интернируются, динамически генерируемыеString
s могут интернироваться с помощью вызоваString.intern
метод. ИнтернированныйString
в Java в точности такой же, какSymbol
в Ruby, но он не реализован как отдельный тип, это просто другое состояние, что JavaString
может быть в. (Примечание: в более ранних версиях RubyString#to_sym
раньше вызывался,String#intern
и этот метод до сих пор существует как устаревший псевдоним.)Symbol
Это прежде всего тип данных со специфической семантикой . Эта семантика также позволяет реализовать некоторые производительные операции (например, быстрое тестирование на равенство O (1)), но это не главная цель.Symbol
В языке Ruby они вообще не нужны, без них Ruby прекрасно бы работал. Они являются чисто библиотечной функцией. В языке есть только одно место, которое связано сSymbol
s:def
выражение определения метода соответствуетSymbol
обозначению имени определяемого метода. Однако это довольно недавнее изменение, до этого возвращаемое значение просто оставалось неуказанным. МРТ просто оценивалиnil
, Рубиния оценивали доRubinius::CompiledMethod
объекта и так далее. Также было бы возможно оценить кUnboundMethod
... или простоString
.Я не уверен, что вы спрашиваете здесь. Производительность в основном зависит от качества реализации, а не от языка. Кроме того, Node - это даже не язык, а интегрированная среда ввода / вывода для ECMAScript. Запуск эквивалентного скрипта на IronPython и MRI, скорее всего, IronPython будет быстрее. Запуск эквивалентного скрипта на CPython и JRuby + Truffle, JRuby + Truffle, вероятно, будет быстрее. Это не имеет ничего общего с
Symbol
s, но с качеством реализации: JRuby + Truffle имеет агрессивно оптимизирующий компилятор, а также весь механизм оптимизации высокопроизводительной JVM, CPython - простой интерпретатор.Нет,
Symbol
это не оптимизация компилятора. Это отдельный тип данных со специфической семантикой. Они не похожи на флаоны YARV , которые являются частной внутренней оптимизацией дляFloat
s. Ситуация не такая, как дляInteger
,Bignum
иFixnum
, которая должна быть невидимой частной внутренней оптимизацией, но, к сожалению, не так. (Это , наконец , будет исправлена в Рубине 2.4, который удаляетFixnum
иBignum
и листья простоInteger
.)Делать это так, как это делает Java, в качестве особого состояния нормальных
String
s означает, что вам всегда нужно проявлять осторожность относительно того,String
находятся ли ваши s в этом специальном состоянии и при каких обстоятельствах они автоматически находятся в этом специальном состоянии, а когда нет. Это гораздо большая нагрузка, чем просто наличие отдельного типа данных.Symbol
это тип данных, который обозначает концепцию имени или метки .Symbol
Это ценностные объекты , неизменяемые, обычно немедленные (если язык различает такие вещи), не имеющие состояния и не имеющие идентичности. ДваSymbol
s, которые равны, также гарантированно будут идентичны, другими словами, дваSymbol
s, которые равны, фактически являются одним и тем жеSymbol
. Это означает, что равенство значений и ссылочное равенство - это одно и то же, и, следовательно, равенство эффективно и O (1).Причины, по которым они есть на языке, на самом деле одинаковы, независимо от языка. Некоторые языки полагаются на них больше, чем другие.
Например, в семействе Лисп нет понятия «переменная». Вместо этого вы
Symbol
связались со значениями.В языках с отражающими или самосозерцательными возможностями,
Symbol
s часто используется для обозначения названия отраженных сущностей в API , отражения, например , в Ruby,Object#methods
,Object#singleton_methods
,Object#public_methods
,Object#protected_methods
, иObject#public_methods
возвращатьArray
изSymbol
й (хотя они могли бы точно так же возвращатьArray
изMethod
с).Object#public_send
принимаетSymbol
обозначение имени сообщения для отправки в качестве аргумента (хотя оно также принимаетString
и,Symbol
более семантически правильно).В ECMAScript
Symbol
s являются фундаментальным строительным блоком обеспечения безопасности ECMAScript в будущем. Они также играют большую роль в отражении.источник
Символы полезны в Ruby, и вы увидите их по всему коду Ruby, потому что каждый символ используется повторно при каждой ссылке на него. Это улучшение производительности по сравнению со строками, потому что каждое использование строки, которая не сохранена в переменной, создает новый объект в памяти. Например, если я использую одну и ту же строку несколько раз в качестве хеш-ключа:
Строка «а» создается в памяти 101 000 раз. Если бы я использовал символ вместо:
Символ
:a
- это еще один объект в памяти. Это делает символы значительно более эффективными, чем строки.ОБНОВЛЕНИЕ Вот тест (взятый из Codecademy ), который демонстрирует разницу в производительности:
Вот мои результаты для моего MBP:
Существует четкое различие в использовании строк и символов для простой идентификации ключей в хэше.
источник
"a"
действительно является свежей строкой, я думаю, в вашем примере их будет ровно две"a"
(и реализация может даже совместно использовать память, пока один из них не будет мутирован). Чтобы создать миллионы строк, вам, вероятно, потребуется использовать String.new ("a"). Но я не очень разбираюсь в Ruby, так что, возможно, я ошибаюсь.string_AZ[String.new("r")]
для того, чтобы увидеть, если это имеет значение. Я получаю 21 мс для строк (оригинальная версия), 7 мс с символами и 50 мс для свежих строк каждый раз. Так что я бы сказал, что строки с буквальной"r"
версией выделяются не так сильно .