Introspección de tipos

De Wikipedia, la enciclopedia libre
Saltar a: navegación, búsqueda

En informática, la introspección de tipos es la capacidad de algunos lenguaje de programación orientado a objetos de determinar el tipo de un objeto en tiempo de ejecución. Esta es una característica notable de Objective-C, y una característica común en todo lenguaje que permita que clases de objetos sean manipuladas como objetos de clase primera por el programador. La introspección de tipos puede ser utilizada para implementar polimorfismo.

Ejemplos[editar]

Ruby[editar]

La introspección de tipos es una característica básica de Ruby. En Ruby, la clase Object (padre de toda clase) incluye los métodos Object#instance_of? y Object#kind_of? para comprobar la clase de cualquier instancia. La última devuelve true cuando la instancia particular a la que se le envió el mensaje era una instancia de un descendiente de esta clase en cuestión. Para clarificar, considérese seguir el siguiente código de ejemplo (que puede probarse inmediatamente con irb):

$ 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.send '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

En el ejemplo anterior, la clase Class se usa como cualquier otra clase en Ruby. Se crean dos clases, A y B, siendo la primera padre de la segunda, y luego se comprueba una instancia de cada clase. La última expresión nos devuelve verdadero porque A es una superclase de la clase de b. En el ejemplo inferior se muestra un método alternativo en Ruby que puede utilizarse para definir clases (y que lleva a un resultado idéntico):

$ irb
 
irb(main):001:0> class A; end
 
=> nil
 
irb(main):002:0> class B < A; end
 
=> nil
 
irb(main):003:0> a=A.new
 
=> #<A:0x2e4c33c>
 
irb(main):004:0> b=B.new
 
=> #<B:0x2e4a974>
 
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

También se puede preguntar directamente por la clase de cualquier objeto, y "compararlos" (el siguiente código asume haber ejecutado el código superior):

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

Objective-C[editar]

En Objective-C, por ejemplo, ambos objetos genéricos Object y NSObject (en Cocoa/OpenStep) proporcionan el método isMemberOfClass: que devuelve true si el argumento al método es una instancia de la clase especificada. El método isKindOfClass: devuelve true si el argumento, de forma análoga, es descendiente de la clase especificada.

Por ejemplo, digamos que tenemos un par de clases Perrito y Gatito descendientes de una clase Animal, y una clase Veterinario.

Ahora, en el método desex puede escribirse

- desex: (id) to_desex
 
{
 
   if([to_desex isKindOfClass:[Animal class]])
 
   {
 
      //we're actually desexing an Animal, so continue
 
      if([to_desex isMemberOfClass:[Perrito class]])
 
         desex_dog(to_desex);
 
      else if([to_desex isMemberOfClass:[Gatito class]])
 
         desex_cat(to_desex);
 
      else
 
         error();
 
   }
 
   else
 
   {
 
      error();
 
   }
 
}

Ahora, cuando se llama a desex con un objeto genérico (un id), la función se comportará de forma correcta dependiendo del tipo de objeto genérico.

C++[editar]

C++ soporta introspección de tipos a través de las palabras clave typeid y dynamic cast.

La expresión dynamic_cast puede utilizarse para determinar si un objeto en concreto es de una clase determinada. Por ejemplo:

if(Persona *p = dynamic_cast<Persona *>(obj)){
 
  p->andar();
 
}

El operador typeid devuelve un objeto std::type_info que describe el tipo más derivado de un objeto:

std::cout << typeid(obj).name() << std::endl;

Object Pascal[editar]

La introspección de tipos ha sido parte de Object Pascal desde la primera versión de Delphi, que usa mucho RTTI para diseño visual de formularios. En Object Pascal, toda clase desciende de la clase base TObject, que implementa funcionalidad RTTI básica. El nombre de cada clase puede refrenciarse en código para propósitos de RTTI; el identificador del nombre de clase está implementado como un puntero a los metadatos de la clase, que pueden ser declarados y usados como una variable de tipo TClass.

El lenguaje include un operador is, para determinar si un objeto es o desciende de una clase determinada, así como un operador as, que proporciona typecast con comprobación de tipos, y varios métodos en TObject.

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;

Introspección de Objetos Java[editar]

El ejemplo más sencillo de introspección de tipos en Java es el operador instanceof . El operador instanceof determina si un objeto concreto pertenece a una clase en particular (o a una subclase de esta, o a una clase que implemente tal interfaz). Por ejemplo:

if(obj instanceof Persona){
 
   Persona p = (Persona)obj;
 
   p.andar();
 
}

La clase java.lang.Class[1] es la base de una introspeción más avanzada.

Como ejemplo, si se desea determinar la clase actual de un objeto (más que si un objeto pertenece a una clase en concreto), pueden utilizarse los métodos Object.getClass() y Class.getName():

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

Perl[editar]

Se puede lograr introspección con las funciones ref e isa Perl.

Podemos realizar introspección sobre las clases siguientes y sus instancias correspondientes:

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();

utilizando:

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

Meta-Object Protocol (MOP)[editar]

Se puede lograr una introspección mucho mayor en Perl utilizando el sistema de objetos Moose[2] y la Class::MOP protocolo meta-object,[3] por ejemplo de esta forma se puede comprobar si un objeto determinado realiza un rol X:

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

Se puede listar como sigue una lista de los nombres completamente cualificados de todos los métodos que pueden ser invocados en el objeto, junto con las clases en donde fueron definidos::

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

Véase también[editar]

Referencias[editar]

  1. Java API: java.lang.Class
  2. Moose meta API documentation (en inglés)
  3. Class::MOP - a meta-object protocol for Perl (en inglés)

Enlaces externos[editar]