Wut ‽‽‽
Mais par quelle magie ? 🤔

C’est bien la première fois que je ne comprend pas le comportement de Ruby là… On dirait du JS… 🤔

Ah mais la vache !!! Ça a modifié la valeur par défaut en fait !!!!

aeris ☣ 🇫🇷 @aeris
Follow

[30] pry(main)> f = Hash.new []
=> {}
[31] pry(main)> f[:foo] << :bar
=> [:bar]
[32] pry(main)> f[:bar]
=> [:bar]

@aeris

Juste une piste, désolé si c'est a coté de plaque.Je ne connais pas ruby mais dans les exemples donnés les clefs/valeurs sont crées via l’opérateur =
Or tu utilises <<
Est-ce que cet opérateur a un comportement particulier avec les hash?

@alfajet Non, << est juste l’opérateur de concaténation sur un tableau.
[] << :bar = [:bar]

@aeris @alfajet
Concaténer un tableau ça marche sur un Array, pas sur un Hash, si?

@nemesis @alfajet Sauf que là, je concat sur la valeur par défaut (f[:foo] n’existant pas, c’est supposé retourner []), qui est un tableau

@aeris @alfajet
D'après ta capture, ça retourne {} contrairement à la liste des clés qui retourne []. Donc je ne suis pas complètement certain que tu ais récupéré un tableau en cas de valeur inexistante.

@nemesis @alfajet Sisi, ça ça fonctionne bien :

[37] pry(main)> f = Hash.new []
=> {}
[38] pry(main)> f[:foo]
=> []

@aeris @alfajet
Mais ce tableau par défaut, il est stocké où? Dans un pointeur mémoire spécifique? Ou dans le Hash?

@aeris @nemesis
As tu regarde le lien que j'ai poste precedement?
stackoverflow.com/a/9343737

A priori le pb vient de f = Hash.new [] qui a le tableau pour valeur par defaut.

f[:foo] retournera ce tableau vide car la cle :foo n'existe pas.

f[:foo] << :bar de meme retournera [:bar] car cette valeur est rajouté au tableau par defaut mais et cle foo n'existant pas, cela retourne ce tableau par defaut.

@alfajet @aeris
Ok donc c'est vraiment une valeur par défaut stockée à part, pas une valeur mise dans chaque association invoquée. Du coup en effet, la modifier modifie la réponse de toute association inexistante invoquée.

@aeris oui, c'est le même tableau qui est utilisé partout

```
[1] pry(main)> plop = []
=> []
[2] pry(main)> f = Hash.new plop
=> {}
[3] pry(main)> f[:foo] << :bar
=> [:bar]
[4] pry(main)> plop
=> [:bar]
```

Si tu en veux un nouveau pour chaque valeur par défaut, il faut utiliser un bloc :

```
[1] pry(main)> f = Hash.new { [] }
=> {}
[2] pry(main)> f[:foo] << :baz
=> [:baz]
[3] pry(main)> f[:baz]
=> []
```

@bmichel En fait c’est surtout le .keys vides qui a aussi donné des migraines sur sur freenode 😂

@bmichel Et en vrai le { [] } pose aussi souci sur le .keys, qui reste vide et divers effets de bord à la con…

[1] pry(main)> f = Hash.new { [] }
=> {}
[2] pry(main)> f[:foo] << :baz
=> [:baz]
[3] pry(main)> f
=> {} 🤔
[4] pry(main)> f.keys
=> [] 🤔
[5] pry(main)> f[:foo]
=> [] 🤔
[6] pry(main)> f[:bar]
=> []

@bmichel La solution indiquée sur IRC est d’utiliser <<= en plus de { [] }

[8] pry(main)> f = Hash.new { [] }
=> {}
[9] pry(main)> f[:foo] <<= :baz
=> [:baz]
[10] pry(main)> f
=> {:foo=>[:baz]}
[11] pry(main)> f.keys
=> [:foo]
[12] pry(main)> f[:foo]
=> [:baz]
[13] pry(main)> f[:bar]
=> []

@bmichel Tout est justifiable proprement, mais ça doit quand même être la source incompréhensible de quelques bugs 😂

@aeris oui, je n'ai jamais trop compris pourquoi la valeur par défaut était renvoyée avec un getter, mais l'élément n'est pas ajouté au hash

@bmichel En fait c’est finalement assez logique
« f[:foo] << bar » est finalement du sucre pour foo = f[:foo]; foo << bar », qui effectivement ne réaffecte jamais foo à la fin à « f[:foo] ». Et laisse donc le hash vide !