Introspection de type - Type introspection

En informatique , l' introspection de type est la capacité d'un programme à examiner le type ou les propriétés d'un objet au moment de l' exécution . Certains langages de programmation possèdent cette capacité.

L'introspection ne doit pas être confondue avec la réflexion , qui va plus loin et est la capacité d'un programme à manipuler les valeurs, les métadonnées, les propriétés et les fonctions d'un objet au moment de l'exécution. Certains langages de programmation possèdent également cette capacité (par exemple, Java , Python , Julia et Go ).

Exemples

Rubis

L'introspection de type est une fonctionnalité essentielle de Ruby . En Ruby, la classe Object (ancêtre de chaque classe) fournit Object#instance_of?et des Object#kind_of?méthodes pour vérifier la classe de l'instance. Ce dernier renvoie vrai lorsque l'instance particulière à laquelle le message a été envoyé est une instance d'un descendant de la classe en question. Par exemple, considérons l'exemple de code suivant (vous pouvez immédiatement essayer cela avec Interactive Ruby Shell ):

$ irb
irb(main):001:0> A=Class.new
=> A
irb(main):002:0> B=Class.new A
=> B
irb(main):003:0> a=A.new
=> #<A:0x2e44b78>
irb(main):004:0> b=B.new
=> #<B:0x2e431b0>
irb(main):005:0> a.instance_of? A
=> true
irb(main):006:0> b.instance_of? A
=> false
irb(main):007:0> b.kind_of? A
=> true

Dans l'exemple ci-dessus, la Classclasse est utilisée comme n'importe quelle autre classe dans Ruby. Deux classes sont créées, Aet B, la première est une superclasse de la seconde, puis une instance de chaque classe est vérifiée. La dernière expression donne true car Aest une superclasse de la classe de b.

De plus, vous pouvez directement demander la classe de n'importe quel objet, et les "comparer" (le code ci-dessous suppose avoir exécuté le code ci-dessus):

irb(main):008:0> A.instance_of? Class
=> true
irb(main):009:0> a.class
=> A
irb(main):010:0> a.class.class
=> Class
irb(main):011:0> A > B
=> true
irb(main):012:0> B <= A
=> true

Objectif c

En Objective-C , par exemple, l'Object générique et le NSObject (dans Cocoa / OpenStep ) fournissent la méthode isMemberOfClass: qui renvoie true si l'argument de la méthode est une instance de la classe spécifiée. La méthode isKindOfClass:renvoie de la même manière true si l'argument hérite de la classe spécifiée.

Par exemple, supposons que nous ayons une Appleet une Orangeclasse héritant de Fruit.

Maintenant, dans la eatméthode, nous pouvons écrire

- (void)eat:(id)sth {
    if ([sth isKindOfClass:[Fruit class]]) {
        // we're actually eating a Fruit, so continue
        if ([sth isMemberOfClass:[Apple class]]) {
            eatApple(sth);
        } else if ([sth isMemberOfClass:[Orange class]]) {
            eatOrange(sth);
        } else {
            error();
        }
    } else {
        error();
    }
}

Désormais, lorsque eatest appelé avec un objet générique (un id), la fonction se comportera correctement en fonction du type de l'objet générique.

C++

C++ prend en charge l'introspection de type via les mots-clés typeid et dynamic_cast des informations de type à l' exécution (RTTI) . L' expression peut être utilisée pour déterminer si un objet particulier appartient à une classe dérivée particulière. Par exemple: dynamic_cast

Person* p = dynamic_cast<Person *>(obj);
if (p != nullptr) {
  p->walk();
}

L' typeidopérateur récupère un std::type_infoobjet décrivant le type le plus dérivé d'un objet :

if (typeid(Person) == typeid(*obj)) {
  serialize_person( obj );
}

Objet Pascal

L'introspection de type fait partie du Pascal Objet depuis la version originale de Delphi, qui utilise fortement RTTI pour la conception de formulaires visuels. Dans Object Pascal, toutes les classes descendent de la classe de base TObject, qui implémente la fonctionnalité RTTI de base. Le nom de chaque classe peut être référencé dans le code à des fins RTTI ; l'identifiant de nom de classe est implémenté comme un pointeur vers les métadonnées de la classe, qui peuvent être déclarées et utilisées comme une variable de type TClass. Le langage inclut un opérateur is , pour déterminer si un objet est ou descend d'une classe donnée, un opérateur as , fournissant un transtypage de type vérifié, et plusieurs méthodes TObject. Une introspection plus approfondie (énumération des champs et des méthodes) n'est traditionnellement prise en charge que pour les objets déclarés dans l'état $M+ (un pragma), généralement TPersistent, et uniquement pour les symboles définis dans la section publiée. Delphi 2010 a augmenté cela à presque tous les symboles.

procedure Form1.MyButtonOnClick(Sender: TObject);
var
   aButton: TButton;
   SenderClass: TClass;
begin
   SenderClass := Sender.ClassType; //returns Sender's class pointer
   if sender is TButton then
   begin
      aButton := sender as TButton;
      EditBox.Text := aButton.Caption; //Property that the button has but generic objects don't
   end
   else begin
      EditBox.Text := Sender.ClassName; //returns the name of Sender's class as a string
   end;
end;

Java

L'exemple le plus simple d'introspection de type en Java est l' instanceofopérateur. L' instanceofopérateur détermine si un objet particulier appartient à une classe particulière (ou à une sous-classe de cette classe, ou à une classe qui implémente cette interface). Par exemple:

if (obj instanceof Person) {
    Person p = (Person)obj;
    p.walk();
}

La java.lang.Classclasse est la base d'une introspection plus poussée.

Par exemple, s'il est souhaitable de déterminer la classe réelle d'un objet (plutôt que s'il est membre d'une classe particulière ), Object.getClass()et Class.getName()peut être utilisé :

System.out.println(obj.getClass().getName());

PHP

En PHP, l' introspection peut être effectuée à l'aide de l' instanceofopérateur. Par exemple:

if ($obj instanceof Person) {
    // Do whatever you want
}

Perl

L'introspection peut être réalisée en utilisant les fonctions refet isade Perl .

Nous pouvons introspecter les classes suivantes et leurs instances correspondantes :

package Animal;
sub new {
    my $class = shift;
    return bless {}, $class;
}

package Dog;
use base 'Animal';

package main;
my $animal = Animal->new();
my $dog = Dog->new();

en utilisant:

print "This is an Animal.\n" if ref $animal eq 'Animal';
print "Dog is an Animal.\n" if $dog->isa('Animal');

Protocole méta-objet

Une introspection bien plus puissante en Perl peut être réalisée en utilisant le système d'objet Moose et le protocole Class::MOP méta-objet ; par exemple, vous pouvez vérifier si un objet donné remplit un rôle X :

if ($object->meta->does_role("X")) {
    # do something ...
}

Voici comment vous pouvez répertorier les noms complets de toutes les méthodes pouvant être invoquées sur l'objet, ainsi que les classes dans lesquelles elles ont été définies :

for my $method ($object->meta->get_all_methods) {
    print $method->fully_qualified_name, "\n";
}

Python

La méthode d'introspection la plus courante en Python consiste à utiliser la dirfonction pour détailler les attributs d'un objet. Par exemple:

class Foo:
    def __init__(self, val):
        self.x = val

    def bar(self):
        return self.x
>>> dir(Foo(5))
['__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
'__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__setattr__', '__str__', '__weakref__', 'bar', 'x']

En outre, les fonctions intégrées typeet isinstancepeuvent être utilisés pour déterminer ce qu'un objet est tout hasattrpeut déterminer ce qu'un objet fait . Par exemple:

>>> a = Foo(10)
>>> b = Bar(11)
>>> type(a)
<type 'Foo'>
>>> isinstance(a, Foo)
True
>>> isinstance(a, type(a))
True
>>> isinstance(a, type(b))
False
>>> hasattr(a, 'bar')
True

ActionScript (as3)

Dans ActionScript , la fonction flash.utils.getQualifiedClassNamepeut être utilisée pour récupérer le nom de classe/type d'un objet arbitraire.

// all classes used in as3 must be imported explicitly
import flash.utils.getQualifiedClassName;
import flash.display.Sprite;
// trace is like System.out.println in Java or echo in PHP
trace(flash.utils.getQualifiedClassName("I'm a String")); // "String"
trace(flash.utils.getQualifiedClassName(1)); // "int", see dynamic casting for why not Number
trace(flash.utils.getQualifiedClassName(new flash.display.Sprite())); // "flash.display.Sprite"

Alternativement, l'opérateur ispeut être utilisé pour déterminer si un objet est d'un type spécifique :

// trace is like System.out.println in Java or echo in PHP
trace("I'm a String" is String); // true
trace(1 is String); // false
trace("I'm a String" is Number); // false
trace(1 is Number); // true

Cette deuxième fonction peut également être utilisée pour tester les parents d' héritage de classe :

import flash.display.DisplayObject;
import flash.display.Sprite; // extends DisplayObject

trace(new flash.display.Sprite() is flash.display.Sprite); // true
trace(new flash.display.Sprite() is flash.display.DisplayObject); // true, because Sprite extends DisplayObject
trace(new flash.display.Sprite() is String); // false

Introspection Méta-Type

Comme Perl, ActionScript peut aller plus loin que l'obtention du nom de la classe, mais toutes les métadonnées, fonctions et autres éléments qui composent un objet utilisant la flash.utils.describeTypefonction ; ceci est utilisé lors de l'implémentation de la réflexion dans ActionScript.

import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;
import flash.display.Sprite;

var className:String = getQualifiedClassName(new flash.display.Sprite()); // "flash.display.Sprite"
var classRef:Class = getDefinitionByName(className); // Class reference to flash.display{{Not a typo|.}}Sprite
// eg. 'new classRef()' same as 'new  flash.display.Sprite()'
trace(describeType(classRef)); // return XML object describing type
// same as : trace(describeType(flash.display.Sprite));

Voir également

Les références

Liens externes