Comment fonctionne l’affectation object_id?

Je joue avec .object_id de Ruby et .object_id remarqué que, dans plusieurs sessions séquentielles d’irb, j’ai les mêmes résultats:

 false.object_id // 0 true.object_id // 2 nil.object_id // 4 100.object_id // 201 

En fait, object_id de chaque entier semble être ((valeur * 2) + 1).

D’autre part, object_id d’une chaîne donnée n’est jamais le même après avoir quitté et relancé irb.

Cela soulève plusieurs questions pour moi:

  1. Existe-t-il un schéma connu par lequel certains object_id s sont déterminés? Les autres sont-ils fondamentalement aléatoires?
  2. Les identifiants true, false et nil ne sont pas séquentiels. Est-il possible de demander quel object est représenté par un identifiant donné? (Je suis curieux de savoir à quoi les autres chiffres et identifiants sont liés.)
  3. Pourriez-vous (pas que vous devriez) écrire Ruby obscurci où vous utilisez des identifiants d’objects connus pour faire référence à des objects sans les nommer, comme “object de l’id 201 + object de l’id 19” pour signifier “100 + 9”?

Mettre à jour

En utilisant la suggestion d’Andrew Grimm, j’ai essayé de découvrir d’autres objects “low id”, mais j’ai constaté que:

  • Il ne semble pas y avoir d’objects pairs dans cette séquence – les identifiants 6, 8, 10, etc.
  • Comme impliqué dans mon expérience précédente, tous les identifiants de numéros impairs appartiennent à des nombres. Plus précisément, id 1 pointe vers le nombre 0, 3 points à 1, 5 points à 2, et ainsi de suite.

Dans l’IRM, object_id d’un object est identique à la VALUE qui représente l’object au niveau C. Pour la plupart des types d’objects, cette VALUE est un pointeur vers un emplacement en mémoire où les données réelles de l’object sont stockées. Évidemment, cela sera différent lors de plusieurs exécutions, car cela ne dépend que de l’endroit où le système a décidé d’allouer la mémoire, et non de n’importe quelle propriété de l’object lui-même.

Cependant, pour des raisons de performances, true , false , nil et Fixnum s sont gérés spécialement. Pour ces objects, il n’y a pas vraiment de structure avec les données de l’object en mémoire. Toutes les données de l’object sont codées dans la VALUE elle-même. Comme vous l’avez déjà compris, les valeurs pour false , true , nil et tout Fixnum i sont respectivement 0 , 2 , 4 et i*2+1 .

La raison pour laquelle cela fonctionne est que sur tous les systèmes sur lesquels l’IRM s’exécute, 0 , 2 , 4 et i*2+1 ne sont jamais des adresses valides pour un object sur le tas.

Assigner Integer (value * 2) + 1 et non-entiers (x * 2) est analogue au paradoxe de Hilbert du Grand Hotel , qui décrit comment affecter infiniment plus d’invités à un hôtel infini.

En ce qui concerne la recherche d’objects par leur identifiant, il existe ObjectSpace._id2ref(object_id) . À moins que votre implémentation n’ait pas ObjectSpace.