Hash keys: string or symbol?

Per molto tempo ho usato esclusivamente simboli per le chiavi degli
Hash,
senza approfondire mai la ragione per cui fosse preferibile rispetto
alla
stringa, a parte dover digitare un carattere in meno.

Ultimamente mi sto ponendo il quesito nuovamente, per via del fatto che
spesso quando si passano dati in giro, specie in formato json, quello
che
ritorna un hash con le chiavi in formato stringa.

C’ sempre li famoso symbolize_keys, ma mi chiedo se sia un passaggio
necessario o pi una conseguenza di una abitudine diffusa e non
corrispondente ad un bisogno reale.

Che dite?

-f

Il giorno 21 novembre 2014 13:08, Fabrizio R. [email protected]
ha
scritto:

Il giorno 21 novembre 2014 13:14, Davide R.
<[email protected]

ha scritto:

string - Why use symbols as hash keys in Ruby? - Stack Overflow

se il numero delle chiavi non noto a priori e usi ruby < 2.2 stile o
non
stile l’uso dei simboli una pessima idea.

IMVVVHO: da ruby 2.2+ non dovrebbe fare una grossa differenza.

my 2c.
michele.

Stavo per scrivere la stessa cosa di Michele F…

Aggiungerei che se crei symbols dall’input dell’utente, corri il rischio
di un attacco DoS perché i symbols non vengono eliminati dalla memoria.

Con dell’introduzione del GC per i symbols in Ruby 2.2 il problema
dovrebbe essere risolto.

Duilio

Proprio per questo motivo in Rails params di tipo
ActiveSupport::HashWithIndifferentAccess, che fa si che ad un hash si
possa
accedere indifferentemente con simboli o con stringhe. ActiveSupport
implementa anche Hash#with_indifferent_access, utile per convertire un
Hash
ed accedervi indifferentemente con simboli o stringhe:

hash = {‘asd’ => ‘ciao’}
hash[:asd] #=> nil
hash.with_indifferent_access[:asd] #=> ‘ciao’

Maurizio De Santis

Il giorno 21 novembre 2014 13:28, Duilio R.
<[email protected]

ha scritto:

Immagino che HashWithIndifferentAccess converta le stringhe in input in
simboli per poi eseguire il confronto e non il contrario.

2014-11-21 15:20 GMT+01:00 Maurizio De Santis
[email protected]:

Aggiungo che:

Per i simboli la velocita’ di accesso NON dipende dalla lunghezza della
key
(che ha un object_id immutabile)
Per le stringhe invece questo NON vale in quanto le stringhe sono
“mutabili” e non hanno un puntatore.

quindi posso fare:

:precipitevolissimevolmente => true

Ma se faccio

“precipitevolissimevolmente” => true

e’ male

Il giorno 21 novembre 2014 16:05, Davide R.
<[email protected]

ha scritto:

ah ah ah e quindi?

Stringhe o Simboli?

E poi se HashWithIndifferentAccess me li converte in symbols che faccio?

Ma sopratutto: se, come da thread precedente, non c’e’ problema ad avere
troppi oggetti in ruby, come mai che ora mi fate economia di simboli?

E cmq io uso vim

Ciao

Il giorno 21 novembre 2014 15:58, Fabrizio R. [email protected]
ha
scritto:

Puoi provare anche tu:

“test”.object_id
“test”.object_id
:test.object_id
:test.object_id

Il giorno 21 novembre 2014 16:17, Davide R.
<[email protected]

ha scritto:

Prendiamo una libreria che parsa JSON, un oggetto JSON molto grande, e
lo
trasforma in un hash. O molti piccoli json. E’ indifferente, magari
rimangono in memoria per un tempo prolungato.

JSON.parse({a: 10}.to_json).keys
=> [“a”]

Questo un problema memory-wise da quello che stiamo dicendo, o sarebbe
peggio se venisse creato un Hash con simboli come chiavi?

2014-11-21 16:39 GMT+01:00 Andrea P. [email protected]:

Il giorno 21/nov/2014, alle ore 16:05, Davide R.
[email protected] ha scritto:

Ma sopratutto: se, come da thread precedente, non c’e’ problema ad avere
troppi oggetti in ruby, come mai che ora mi fate economia di simboli?

come facevano gi notare: gli oggetti sono garbage collected, i simboli
no :slight_smile:

cito il buon Michele F.:

se il numero delle chiavi non noto a priori e usi ruby < 2.2
stile o non stile l’uso dei simboli una pessima idea.

ciao,
A.

Vediamo se questa sintesi mette d’accordo tutti:

  1. Gli Hash con simboli vanno bene per la velocit di accesso, sono un
    problema nel caso il numero di chiavi non sia noto a priori (sopratutto
    se
    le chiavi posso essere create dagli utenti: DOS attack)
  2. Gli Hash con stringhe sono lenti in accesso ai dati: la velocita’
    dipende dalla grandezza della chiave (quindi evito di usare stringhe
    troppo
    lunghe), ma le chiavi sono GC
  3. Se uso JSON.parse le mia chiavi saranno simboli by default
  4. ActiveSupport ha un metodo che ritira i valori usando come chiave
    indifferentemente stringa o simbolo.
  5. Vim e’ decisamente superiore a Emacs in tutto

Siamo daccordo?

Possiamo andare a casa che e’ venerdi?

:slight_smile:

Davide

Il giorno 21 novembre 2014 17:00, Fabrizio R. [email protected]
ha
scritto:

Ad ogni modo, ho trovato una opzione:

JSON.parse({a: 10}.to_json, symbolize_names: true).keys
=> [:a]

La domanda rimane, anche se con questa opzione almeno lo sviluppatore
pu
decidere come operare.

2014-11-21 16:57 GMT+01:00 Fabrizio R. [email protected]:

ok per 1) < 2.2.

Per sublime beh … c’e’ atom ormai

tsk tsk

Il giorno 21 novembre 2014 17:20, Michele F. [email protected]
ha
scritto:

Il giorno 21 novembre 2014 17:16, Davide R.
<[email protected]

ha scritto:

Vediamo se questa sintesi mette d’accordo tutti:

  1. Gli Hash con simboli vanno bene per la velocit di accesso, sono un
    problema nel caso il numero di chiavi non sia noto a priori (sopratutto se
    le chiavi posso essere create dagli utenti: DOS attack)

Possiamo andare a casa che e’ venerdi?

solo se ammetti che 1) accade per ruby < 2.2 e ti converti a sublime.

m.

Il giorno 21 novembre 2014 17:24, Davide R.
<[email protected]

ha scritto:

ok per 1) < 2.2.

Per sublime beh … c’e’ atom ormai

…sei gentile a dedicare del tempo ad aspettare il tuo editor :slight_smile:
[con questa auguro buon w.e. a tutta la lista]

m.

ma se ti faccio upload di un json con chiavi stringhe di 2000
caratteri ed HashWithIndifferentAccess
converte in stringe (mutable),

non e’ un 'altro DOS attack? Ogni volta che carichi l’Hash per cercare
qualcosa: BOOM!

Sbaglio?

Il giorno 21 novembre 2014 17:37, Maurizio De Santis <
[email protected]> ha scritto:

Immagino che HashWithIndifferentAccess converta le stringhe in input in
simboli per poi eseguire il confronto e non il contrario.

Sbagliato: se HashWithIndifferentAccess convertisse stringhe in simboli
potresti dossare un’applicazione Rails (Ruby < 2.2) semplicemente
inviando
richieste con tante query string keys che, venendo convertite in simboli
da
Rails e non GCed, intaserebbero la memoria.

Maurizio De Santis

Il giorno 21 novembre 2014 15:58, Fabrizio R. [email protected]
ha
scritto:

Il tuo esempio non mi chiaro… sar che venerd! :smiley:
Il 21/nov/2014 18:46 “Davide R.” [email protected] ha
scritto:

  1. Gli Hash con simboli vanno bene per la velocità di accesso, sono un
    problema nel caso il numero di chiavi non sia noto a priori (sopratutto
    se
    le chiavi posso essere create dagli utenti: DOS attack)

E’ così. Ma: Ruby 2.2 a Natale e Rails 4.2 (quando?) risolveranno il
problema; nella maggior parte dei casi si sa quali sono le chiavi;
JSON.parse genera stringhe come chiavi.

  1. Gli Hash con stringhe sono lenti in accesso ai dati: la velocita’
    dipende dalla grandezza della chiave (quindi evito di usare stringhe
    troppo lunghe), ma le chiavi sono GC

Sì.

  1. Se uso JSON.parse le mia chiavi saranno simboli by default

Non è quel che fa il JSON.parse che sto usando io.

2.1.5 :001 > require ‘json’
=> true
2.1.5 :002> json = JSON.parse(‘{“hello”: “goodbye”}’)
=> {“hello”=>“goodbye”}
2.1.5 :003> json[:hello]
=> nil
2.1.5 :004> json[“hello”]
=> “goodbye”

Vediamo se così genera simboli…

2.1.5 :005> json = JSON.parse(‘{hello: “goodbye”}’)
JSON::ParserError: 757: unexpected token at ‘{hello: “goodbye”}’

No, questo non è JSON. Dalla definizione in home page a http://json.org/
le chiavi JSON sono stringe racchiuse tra doppi apici. Infatti:

2.1.5 :006 > json = JSON.parse(“{‘hello’: 1}”)
JSON::ParserError: 757: unexpected token at ‘{‘hello’: 1}’

  1. ActiveSupport ha un metodo che ritira i valori usando come chiave
    indifferentemente stringa o simbolo.

Sì.

  1. Vim e’ decisamente superiore a Emacs in tutto

Nel corso dei secoli ci sono state guerre combattute per questo.
Permettimi di considerare vim una nuova versione di vi e dopo 25 anni
che li uso ti posso solo dire che ognuno dei due ha i suoi punti di
forza. Da che vim ha uno scripting degno di tal nome lo si può usare
come fosse emacs. Per chi usa emacs da tempo è inutile fare switch e
immagino viceversa. Tipicamento uso vi per sudo vi /etc/qualcosa o sui
server in ssh. E’ più pratico.

Non aggrovigliamoci ulteriormente e restiamo su stringhe e hash :slight_smile:
Buona domenica.