1
votes

Apparence de la classe singleton

Il semble y avoir un contraste entre les classes singleton de nil , false , true et celle d'une instance d'une classe personnalisée.

i) Les classes singleton de nil , false et true sont désignées par leurs noms de constants assignés:

XXX

ii) La classe singleton de nil , false et true apparaît sur les listes d'ancêtres: p>

a.class.ancestors #=> [A, Object, Kernel, BasicObject]

Pour la classe singleton nommée AClass d'une instance a d'une classe personnalisée A ,

a.singleton_class #=> #<Class:#<A:0x00007fda832a7eb0>>

i) AClass n'est pas référencé par son nom de constante attribué:

class A; end
a = A.new
AClass = a.singleton_class

ii) AClass n'apparaît pas dans la liste des ancêtres:

nil.class.ancestors #=> [NilClass, Object, Kernel, BasicObject]
false.class.ancestors #=> [FalseClass, Object, Kernel, BasicObject]
true.class.ancestors #=> [TrueClass, Object, Kernel, BasicObject]

Est-ce le comportement attendu? Qu'est-ce qui divise nil , false , true d'une part et a d'autre part? De quoi cette spécification découle-t-elle?


2 commentaires

Ces classes contournent l'habituel code> RBASIC () recherche de classe.


Aussi: BasicObject.new.singleton_class # ⇒ NoMethodError: méthode non définie `singleton_class 'pour #


4 Réponses :


2
votes

Je ne sais pas si cela aide, mais à partir de la documentation pour singleton_class :

Si obj est nil , true ou false , il renvoie NilClass , TrueClass < / code> ou FalseClass , respectivement.

Donc singleton_class a un comportement spécial pour nil , true et false au lieu du comportement standard de retour la classe singleton des objets.


4 commentaires

L'objet retourné ( NilClass , TrueClass , FalseClass ) n'est pas spécial car il s'agit bien des classes singleton. Ce qui est spécial, c'est la façon dont ils sont affichés.


Cela peut être réalisé en remplaçant la méthode #inspect de la classe singleton. classe AClass; Def self.inspect; 'Une classe'; fin; fin; a.singleton_class # => AClass


@ 3limin4t0r Avec les classes non singleton, vous n'avez pas besoin de remplacer inspect pour faire cela. La question que je me pose est la suivante: pourquoi je dois le remplacer par des classes singleton à l'exception de NilClass , FalseClass et TrueClass .


@sawa merci pour votre commentaire. Je me demande pourquoi ces 3 sont explicitement mentionnés dans la documentation s'il n'y a pas de comportement particulier. C'est une question intéressante et je vais certainement suivre les réponses des autres.



0
votes

Dans ruby, NilClass , FalseClass et TrueClass ne peuvent avoir qu'une seule instance. C'est pourquoi ils n'ont pas de singleton_class .

Par exemple:

a = nil 
def a.foo
  'foo'
end 

b = nil 
b.foo => # foo

Comme nous pourrions le voir, b répond à la méthode foo et renvoie foo string même si nous avons défini la méthode foo pour la variable a . Cela signifie que ces 3 classes ne peuvent avoir qu'une seule instance. Et il y a autre chose à souligner que nil , false et true sont des variables mais des pseudo-variables. Ils ne peuvent pas être affectés à des structures de données différentes. Dans un sens, ce sont des variables figées.


2 commentaires

Je ne sais pas ce que vous entendez par "ils n'ont pas de singleton_class". Si "ils" pointe vers NilClass , FalseClass et TrueClass , assurez-vous qu'ils n'en ont pas (bien que vous puissiez en créer un: NilClass.singleton_class # => # ), mais pas sûr de ce que vous essayez de dire avec ça. Si «ils» indiquent plutôt nil , false et true , alors vous vous trompez. Ils ont des classes singleton, c'est-à-dire NilClass , FalseClass et TrueClass , comme je l'ai écrit. Et il n'est pas non plus clair comment cela découle du fait que « NilClass , FalseClass et TrueClass ne peuvent avoir qu'une seule instance.


Et il est encore plus difficile de trouver une pertinence entre la dernière partie de votre réponse et ma question.



2
votes

1. nil , false , true objets

i) Les classes singleton de nil, false et true sont désignées par leurs noms de constante assignés:

Ce n'est pas correct. La méthode singleton_class de nil , true et false ne renvoie pas leurs classes singleton car elles n'existent pas. Au lieu de cela, il renvoie leurs classes réelles. La raison pour laquelle ces objets n'ont pas de classes singleton est évidente et est bien décrite dans la réponse de @ zeitnot.

Ce comportement est attendu et est documenté ici https : //ruby-doc.com/core/Object.html#method-i-singleton_class

ii) La classe singleton de nil, false et true apparaît sur l'ancêtre listes

Ce n'est pas non plus correct. Étant donné que ces objets n'ont pas de classes singleton, ce que vous voyez dans la liste des ancêtres est leurs classes réelles. Mais même s'ils avaient des classes singleton, vous ne les obtiendriez pas de cette façon (continuez à lire pour savoir pourquoi)

2. une instance a d'une classe personnalisée A

i) AClass n'est pas référencé par son nom de constante attribué:

AClass = a.singleton_class

Ce code fait référence à AClass a.singleton_class . Mais c'est une relation unidirectionnelle (de AClass à a.singleton_class ). Cela ne fait pas que a.singleton_class fait référence et renvoie AClass comme vous vous y attendez.

ii) AClass n'apparaît pas dans la liste des ancêtres:

Pour obtenir une liste d'ancêtres comprenant la classe singleton, exécutez a.singleton_class.ancestors au lieu de a.class.ancestors .

class A; end
class B < A; end
class C < B; end

A.ancestors # => [A, ...]
B.ancestors # => [B, A, ...]
C.ancestors # => [C, B, A, ...]

La méthode ancestors recherche uniquement la hiérarchie:

a.singleton_class.ancestors #=> [#<Class:#<A:0x000000000191dba0>>, A, Object, Kernel, BasicObject]


7 commentaires

Si true n'a pas de classe singleton comme vous le prétendez, alors sur quelle classe la méthode singleton suivante foo est-elle définie? def true.foo; fin; true.method (: foo) .owner # => TrueClass Si vous dites que ce n'est pas une classe singleton, alors qu'est-ce qu'une classe singleton?


Notez ceci: [true, false, nil] .all? {| x | x.singleton_class == x.class} . Les classes de ces constantes sont renvoyées comme des cas exceptionnels lorsqu'une classe singleton est demandée (voir ici ). Par conséquent, votre foo se trouve directement sur la classe de true (c'est-à-dire TrueClass ). Il n'y a aucun autre objet pour lequel x.class == x.singleton_class est vrai.


@sawa Vous avez répondu à votre propre question. C'est TrueClass - la classe actuelle. La définition d'une méthode singleton pour ces objets revient à définir une méthode d'instance qui appartient à leur classe réelle


@chumakoff Si vous dites que ce n'est pas une classe singleton, alors qu'est-ce qu'une classe singleton?


@chumakoff Je ne comprends pas non plus votre argument "Mais c'est une relation unidirectionnelle (de AClass à a.singleton_class ). Cela ne fait pas de un .singleton_class fait référence à et renvoie AClass comme prévu. " Lorsque vous avez une classe sans nom, son inspection commence à faire référence à son nom lorsque vous la nommez. b = Class.new => # ; B = b # => B Je ne vois pas comment votre argument correspond à cela.


La classe singleton est plutôt bien définie ailleurs , et Je suis sûr que vous savez ce que c'est. Mais ces trois sont spécifiquement chargés de mentir à propos de leur classe singleton , conformément au lien ci-dessus, et de rapporter leur classe réelle lorsqu'ils sont envoyés avec singleton_class .


@sawa Dans le cas d'une classe singleton, vous n'avez pas de classe sans nom



1
votes

Un bon exemple dit souvent plus que beaucoup de mots:

foo = FooClass.instance # unfortunately the syntax is not exactly the same
foo #=> foo
foo.class #=> FooClass
foo.singleton_class #=> FooClass

Voyons maintenant les similitudes:

true #=> true
true.class #=> TrueClass
true.singleton_class #=> TrueClass

require 'singleton'

class FooClass
  include Singleton
  alias singleton_class class

  def inspect
    'foo'
  end
end

Cela signifie que true.singleton_class fait référence à sa propre classe au lieu de sa classe singleton. Cela a du sens, puisque true est un singleton qui fait de sa propre classe la classe singleton par définition. (Puisqu'il s'agit de la classe d'un singleton.)


2 commentaires

C’est pareil, mais ce n’est absolument pas ainsi que cela est implémenté dans Ruby. FooClass.send (: new) fonctionne parfaitement, produisant une autre instance de FooClass : [FooClass.send (: new), FooClass.send (: new)] .map (&: __ id __). réduire (: ==) # ⇒ false .


@AlekseiMatiushkin C'est un détail d'exécution. TrueClass est écrit en C tandis que ma classe ci-dessus est écrite en Ruby lui-même. Atteindre exactement le même comportement est assez difficile. L'état d'esprit reste le même. Dans le scénario ci-dessus, vous appelez une méthode privée exprès, qui n'est pas l'interface fournie (les méthodes publiques).