ruby - signo - simbolos de hospitales y su significado
¿Por qué los símbolos no son cuerdas congeladas? (6)
Entiendo la diferencia teórica entre cuerdas y símbolos. Entiendo que los Símbolos están destinados a representar un concepto o un nombre o un identificador o una etiqueta o una clave, y las Cadenas son una bolsa de caracteres. Entiendo que las cadenas son mutables y transitorias, donde los símbolos son inmutables y permanentes. Incluso me gusta cómo los símbolos se ven diferentes a las cadenas en mi editor de texto.
Lo que me molesta es que, en términos prácticos, los símbolos son tan similares a las cuerdas que el hecho de que no se implementen ya que las cuerdas causa muchos dolores de cabeza. Ni siquiera admiten la tipificación de pato o la coerción implícita, a diferencia de la otra famosa pareja "la misma pero diferente", Float y Fixnum.
El mayor problema, por supuesto, es que los hashes que llegan a Ruby desde otros lugares, como JSON y HTTP CGI, usan claves de cadena, no claves de símbolos, por lo que los programas de Ruby tienen que inclinarse hacia atrás para convertirlos por adelantado o en el momento de la búsqueda. La mera existencia de HashWithIndifferentAccess
, y su uso rampante en Rails y otros frameworks, demuestra que hay un problema aquí, una picazón que debe ser eliminada.
¿Alguien puede decirme una razón práctica por la que los Símbolos no se deben congelar Cuerdas? Aparte de "porque así es como siempre se ha hecho" (histórico) o "porque los símbolos no son cadenas" (planteando la pregunta).
Considera el siguiente comportamiento sorprendente:
: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''s actually fine
Todo lo que se necesitaría para confundir menos a la próxima generación de rubistas es esto:
class Symbol < String
def initialize *args
super
self.freeze
end
(y muchos otros piratas informáticos a nivel de biblioteca, pero aún así, no es demasiado complicado)
Ver también:
- http://onestepback.org/index.cgi/Tech/Ruby/SymbolsAreNotImmutableStrings.red
- http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
- ¿Por qué se rompe mi código al usar un símbolo de hash, en lugar de una cadena de hash?
- ¿Por qué usar símbolos como claves hash en Ruby?
- ¿Qué son los símbolos y cómo los usamos?
- Ruby Symbols vs Strings in Hashes
- No puedo dominar los símbolos en Ruby
- http://blog.arkency.com/could-we-drop-symbols-from-ruby/
- ¿Existen los símbolos de Ruby porque las cadenas son mutables y no internadas?
Actualización: creo que Matz presenta el caso para la class Symbol < String
muy bien aquí: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/9192 (gracias a Azolo por cavar esto arriba, y también la eventual retracción de Matz).
Esta respuesta es drásticamente diferente de mi respuesta original , pero encontré un par de threads interesting en la lista de correo de Ruby. (Ambas buenas lecturas)
Entonces, en un momento dado en 2006, matz implementó la clase Symbol < String
como Symbol < String
. Luego, se eliminó la clase de Symbol
para eliminar cualquier mutabilidad. Así que un Symbol
era, de hecho, una String
inmutable.
Sin embargo, fue revertido. La razón dada fue
Aunque es altamente en contra de DuckTyping, las personas tienden a usar el caso en las clases, y Symbol <String a menudo causa problemas graves.
Así que la respuesta a tu pregunta sigue siendo: un Symbol
es como una String
, pero no lo es.
El problema no es que un Symbol
no deba ser String
, sino que históricamente no lo fue.
Los fundamentos de esto son, estos no deberían ser verdaderos:
:apple == "apple" #=> false, should be true
:apple.hash == "apple".hash #=> false, should be true
Los símbolos son siempre los mismos objetos, y el texto no lo es.
No sé una respuesta completa, pero aquí hay una gran parte de ella:
Una de las razones por las que los símbolos se utilizan para las claves hash es que cada instancia de un símbolo dado es exactamente el mismo objeto. Esto significa que :apple.id
siempre devolverá el mismo valor, aunque no lo estés pasando. Por otro lado, "apple".id
devolverá un ID diferente cada vez, ya que se crea un nuevo objeto de cadena.
Esa diferencia es por qué se recomiendan los símbolos para las claves hash. No es necesario realizar una prueba de equivalencia de objetos cuando se usan símbolos. Puede ser cortocircuitado directamente a la identidad del objeto.
Otra consideración es que "apple".each_char
tiene sentido, pero :apple.each_char
no tiene. Una cadena es una "lista ordenada de caracteres", pero un símbolo es un punto de datos atómico sin valor explícito.
Diría que HashWithIndifferentAccess
realidad demuestra que los símbolos de Ruby cumplen dos roles diferentes; Símbolos (que son esencialmente como enums en otros idiomas) y cadenas internadas (que son esencialmente una optimización preventiva, que compensa el hecho de que ruby se interpreta, por lo que no tiene los beneficios de un compilador de optimización inteligente).
Si es que una Cadena podría heredar el Símbolo, porque agrega mucha funcionalidad (mutación). Pero un Símbolo nunca puede ser usado "como una" Cadena porque en todas las circunstancias donde se necesitaría la mutación fallaría.
En cualquier caso, como dije anteriormente, el símbolo string == nunca debe devolver verdadero como se sugirió anteriormente. Si piensa un poco en esto, notará que no puede haber una implementación razonable de == en una clase que también considere instancias de subclase .
Ver esta respuesta: https://.com/a/6745253/324978
Razones principales: el rendimiento (los símbolos se almacenan como enteros y nunca se recolectan basura) y la consistencia ( :admin
y :admin
siempre apuntarán al mismo objeto, donde "admin"
y "admin"
no tienen esa garantía), etc. .